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 <stddef.h>
21 
22 #include "common.h"
23 #include "log.h"
24 #include "threads.h"
25 #include "dbcache.h"
26 #include "ipc.h"
27 #include "mutexs.h"
28 #include "memalloc.h"
29 #include "zbxserver.h"
30 #include "zbxalgo.h"
31 #include "zbxregexp.h"
32 #include "cfg.h"
33 #include "zbxtasks.h"
34 #include "../zbxcrypto/tls_tcp_active.h"
35 #include "../zbxalgo/vectorimpl.h"
36 #include "base64.h"
37 #include "zbxeval.h"
38 
39 #define ZBX_DBCONFIG_IMPL
40 #include "dbconfig.h"
41 #include "dbsync.h"
42 #include "proxy.h"
43 #include "actions.h"
44 #include "zbxtrends.h"
45 #include "zbxvault.h"
46 #include "zbxserialize.h"
47 
48 int	sync_in_progress = 0;
49 
50 #define START_SYNC	WRLOCK_CACHE; sync_in_progress = 1
51 #define FINISH_SYNC	sync_in_progress = 0; UNLOCK_CACHE
52 
53 #define ZBX_LOC_NOWHERE	0
54 #define ZBX_LOC_QUEUE	1
55 #define ZBX_LOC_POLLER	2
56 
57 #define ZBX_SNMP_OID_TYPE_NORMAL	0
58 #define ZBX_SNMP_OID_TYPE_DYNAMIC	1
59 #define ZBX_SNMP_OID_TYPE_MACRO		2
60 
61 /* trigger is functional unless its expression contains disabled or not monitored items */
62 #define TRIGGER_FUNCTIONAL_TRUE		0
63 #define TRIGGER_FUNCTIONAL_FALSE	1
64 
65 /* trigger contains time functions and is also scheduled by timer queue */
66 #define ZBX_TRIGGER_TIMER_UNKNOWN	0
67 #define ZBX_TRIGGER_TIMER_QUEUE		1
68 
69 /* item priority in poller queue */
70 #define ZBX_QUEUE_PRIORITY_HIGH		0
71 #define ZBX_QUEUE_PRIORITY_NORMAL	1
72 #define ZBX_QUEUE_PRIORITY_LOW		2
73 
74 /* shorthand macro for calling in_maintenance_without_data_collection() */
75 #define DCin_maintenance_without_data_collection(dc_host, dc_item)			\
76 		in_maintenance_without_data_collection(dc_host->maintenance_status,	\
77 				dc_host->maintenance_type, dc_item->type)
78 
79 /******************************************************************************
80  *                                                                            *
81  * Function: zbx_value_validator_func_t                                       *
82  *                                                                            *
83  * Purpose: validate macro value when expanding user macros                   *
84  *                                                                            *
85  * Parameters: macro   - [IN] the user macro                                  *
86  *             value   - [IN] the macro value                                 *
87  *             error   - [OUT] the error message                              *
88  *                                                                            *
89  * Return value: SUCCEED - the value is valid                                 *
90  *               FAIL    - otherwise                                          *
91  *                                                                            *
92  ******************************************************************************/
93 typedef int (*zbx_value_validator_func_t)(const char *macro, const char *value, char **error);
94 
95 ZBX_DC_CONFIG	*config = NULL;
96 zbx_rwlock_t	config_lock = ZBX_RWLOCK_NULL;
97 static zbx_mem_info_t	*config_mem;
98 
99 extern unsigned char	program_type;
100 extern int		CONFIG_TIMER_FORKS;
101 
102 ZBX_MEM_FUNC_IMPL(__config, config_mem)
103 
104 static void	dc_maintenance_precache_nested_groups(void);
105 
106 /* by default the macro environment is non-secure and all secret macros are masked with ****** */
107 static unsigned char	macro_env = ZBX_MACRO_ENV_NONSECURE;
108 extern char		*CONFIG_VAULTDBPATH;
109 extern char		*CONFIG_VAULTTOKEN;
110 /******************************************************************************
111  *                                                                            *
112  * Function: dc_strdup                                                        *
113  *                                                                            *
114  * Purpose: copies string into configuration cache shared memory              *
115  *                                                                            *
116  ******************************************************************************/
dc_strdup(const char * source)117 static char	*dc_strdup(const char *source)
118 {
119 	char	*dst;
120 	size_t	len;
121 
122 	len = strlen(source) + 1;
123 	dst = (char *)__config_mem_malloc_func(NULL, len);
124 	memcpy(dst, source, len);
125 	return dst;
126 }
127 
128 /******************************************************************************
129  *                                                                            *
130  * Function: is_item_processed_by_server                                      *
131  *                                                                            *
132  * Parameters: type - [IN] item type [ITEM_TYPE_* flag]                       *
133  *             key  - [IN] item key                                           *
134  *                                                                            *
135  * Return value: SUCCEED when an item should be processed by server           *
136  *               FAIL otherwise                                               *
137  *                                                                            *
138  * Comments: list of the items, always processed by server                    *
139  *           ,------------------+--------------------------------------,      *
140  *           | type             | key                                  |      *
141  *           +------------------+--------------------------------------+      *
142  *           | Zabbix internal  | zabbix[host,,items]                  |      *
143  *           | Zabbix internal  | zabbix[host,,items_unsupported]      |      *
144  *           | Zabbix internal  | zabbix[host,discovery,interfaces]    |      *
145  *           | Zabbix internal  | zabbix[host,,maintenance]            |      *
146  *           | Zabbix internal  | zabbix[proxy,<proxyname>,lastaccess] |      *
147  *           | Zabbix internal  | zabbix[proxy,<proxyname>,delay]      |      *
148  *           | Zabbix aggregate | *                                    |      *
149  *           | Calculated       | *                                    |      *
150  *           '------------------+--------------------------------------'      *
151  *                                                                            *
152  ******************************************************************************/
is_item_processed_by_server(unsigned char type,const char * key)153 int	is_item_processed_by_server(unsigned char type, const char *key)
154 {
155 	int	ret = FAIL;
156 
157 	switch (type)
158 	{
159 		case ITEM_TYPE_CALCULATED:
160 			ret = SUCCEED;
161 			break;
162 
163 		case ITEM_TYPE_INTERNAL:
164 			if (0 == strncmp(key, "zabbix[", 7))
165 			{
166 				AGENT_REQUEST	request;
167 				char		*arg1, *arg2, *arg3;
168 
169 				init_request(&request);
170 
171 				if (SUCCEED != parse_item_key(key, &request) || 3 != request.nparam)
172 					goto clean;
173 
174 				arg1 = get_rparam(&request, 0);
175 				arg2 = get_rparam(&request, 1);
176 				arg3 = get_rparam(&request, 2);
177 
178 				if (0 == strcmp(arg1, "host"))
179 				{
180 					if ('\0' == *arg2)
181 					{
182 						if (0 == strcmp(arg3, "maintenance") || 0 == strcmp(arg3, "items") ||
183 								0 == strcmp(arg3, "items_unsupported"))
184 						{
185 							ret = SUCCEED;
186 						}
187 					}
188 					else if (0 == strcmp(arg2, "discovery") && 0 == strcmp(arg3, "interfaces"))
189 						ret = SUCCEED;
190 				}
191 				else if (0 == strcmp(arg1, "proxy") &&
192 						(0 == strcmp(arg3, "lastaccess") || 0 == strcmp(arg3, "delay")))
193 					ret = SUCCEED;
194 clean:
195 				free_request(&request);
196 			}
197 			break;
198 	}
199 
200 	return ret;
201 }
202 
poller_by_item(unsigned char type,const char * key)203 static unsigned char	poller_by_item(unsigned char type, const char *key)
204 {
205 	switch (type)
206 	{
207 		case ITEM_TYPE_SIMPLE:
208 			if (SUCCEED == cmp_key_id(key, SERVER_ICMPPING_KEY) ||
209 					SUCCEED == cmp_key_id(key, SERVER_ICMPPINGSEC_KEY) ||
210 					SUCCEED == cmp_key_id(key, SERVER_ICMPPINGLOSS_KEY))
211 			{
212 				if (0 == CONFIG_PINGER_FORKS)
213 					break;
214 
215 				return ZBX_POLLER_TYPE_PINGER;
216 			}
217 			ZBX_FALLTHROUGH;
218 		case ITEM_TYPE_ZABBIX:
219 		case ITEM_TYPE_SNMP:
220 		case ITEM_TYPE_EXTERNAL:
221 		case ITEM_TYPE_DB_MONITOR:
222 		case ITEM_TYPE_SSH:
223 		case ITEM_TYPE_TELNET:
224 		case ITEM_TYPE_HTTPAGENT:
225 		case ITEM_TYPE_SCRIPT:
226 			if (0 == CONFIG_POLLER_FORKS)
227 				break;
228 
229 			return ZBX_POLLER_TYPE_NORMAL;
230 		case ITEM_TYPE_CALCULATED:
231 		case ITEM_TYPE_INTERNAL:
232 			if (0 == CONFIG_HISTORYPOLLER_FORKS)
233 				break;
234 
235 			return ZBX_POLLER_TYPE_HISTORY;
236 		case ITEM_TYPE_IPMI:
237 			if (0 == CONFIG_IPMIPOLLER_FORKS)
238 				break;
239 
240 			return ZBX_POLLER_TYPE_IPMI;
241 		case ITEM_TYPE_JMX:
242 			if (0 == CONFIG_JAVAPOLLER_FORKS)
243 				break;
244 
245 			return ZBX_POLLER_TYPE_JAVA;
246 	}
247 
248 	return ZBX_NO_POLLER;
249 }
250 
251 /******************************************************************************
252  *                                                                            *
253  * Function: zbx_is_counted_in_item_queue                                     *
254  *                                                                            *
255  * Purpose: determine whether the given item type is counted in item queue    *
256  *                                                                            *
257  * Return value: SUCCEED if item is counted in the queue, FAIL otherwise      *
258  *                                                                            *
259  ******************************************************************************/
zbx_is_counted_in_item_queue(unsigned char type,const char * key)260 int	zbx_is_counted_in_item_queue(unsigned char type, const char *key)
261 {
262 	switch (type)
263 	{
264 		case ITEM_TYPE_ZABBIX_ACTIVE:
265 			if (0 == strncmp(key, "log[", 4) ||
266 					0 == strncmp(key, "logrt[", 6) ||
267 					0 == strncmp(key, "eventlog[", 9) ||
268 					0 == strncmp(key, "mqtt.get[", ZBX_CONST_STRLEN("mqtt.get[")))
269 			{
270 				return FAIL;
271 			}
272 			break;
273 		case ITEM_TYPE_TRAPPER:
274 		case ITEM_TYPE_DEPENDENT:
275 		case ITEM_TYPE_HTTPTEST:
276 		case ITEM_TYPE_SNMPTRAP:
277 			return FAIL;
278 	}
279 
280 	return SUCCEED;
281 }
282 
283 /******************************************************************************
284  *                                                                            *
285  * Function: get_item_nextcheck_seed                                          *
286  *                                                                            *
287  * Purpose: get the seed value to be used for item nextcheck calculations     *
288  *                                                                            *
289  * Return value: the seed for nextcheck calculations                          *
290  *                                                                            *
291  * Comments: The seed value is used to spread multiple item nextchecks over   *
292  *           the item delay period to even the system load.                   *
293  *           Items with the same delay period and seed value will have the    *
294  *           same nextcheck values.                                           *
295  *                                                                            *
296  ******************************************************************************/
get_item_nextcheck_seed(zbx_uint64_t itemid,zbx_uint64_t interfaceid,unsigned char type,const char * key)297 static zbx_uint64_t	get_item_nextcheck_seed(zbx_uint64_t itemid, zbx_uint64_t interfaceid, unsigned char type,
298 		const char *key)
299 {
300 	if (ITEM_TYPE_JMX == type)
301 		return interfaceid;
302 
303 	if (ITEM_TYPE_SNMP == type)
304 	{
305 		ZBX_DC_SNMPINTERFACE	*snmp;
306 
307 		if (NULL == (snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid))
308 				|| SNMP_BULK_ENABLED != snmp->bulk)
309 		{
310 			return itemid;
311 		}
312 
313 		return interfaceid;
314 	}
315 
316 	if (ITEM_TYPE_SIMPLE == type)
317 	{
318 		if (SUCCEED == cmp_key_id(key, SERVER_ICMPPING_KEY) ||
319 				SUCCEED == cmp_key_id(key, SERVER_ICMPPINGSEC_KEY) ||
320 				SUCCEED == cmp_key_id(key, SERVER_ICMPPINGLOSS_KEY))
321 		{
322 			return interfaceid;
323 		}
324 	}
325 
326 	return itemid;
327 }
328 
329 #define ZBX_ITEM_COLLECTED		0x01	/* force item rescheduling after new value collection */
330 #define ZBX_HOST_UNREACHABLE		0x02
331 #define ZBX_ITEM_KEY_CHANGED		0x04
332 #define ZBX_ITEM_TYPE_CHANGED		0x08
333 #define ZBX_ITEM_DELAY_CHANGED		0x10
334 
DCget_disable_until(const ZBX_DC_ITEM * item,const ZBX_DC_INTERFACE * interface)335 static int	DCget_disable_until(const ZBX_DC_ITEM *item, const ZBX_DC_INTERFACE *interface)
336 {
337 	switch (item->type)
338 	{
339 		case ITEM_TYPE_ZABBIX:
340 		case ITEM_TYPE_SNMP:
341 		case ITEM_TYPE_IPMI:
342 		case ITEM_TYPE_JMX:
343 			return (NULL == interface) ? 0 : interface->disable_until;
344 		default:
345 			return 0;
346 	}
347 }
348 
DCitem_nextcheck_update(ZBX_DC_ITEM * item,const ZBX_DC_INTERFACE * interface,int flags,int now,char ** error)349 static int	DCitem_nextcheck_update(ZBX_DC_ITEM *item, const ZBX_DC_INTERFACE *interface, int flags, int now,
350 		char **error)
351 {
352 	zbx_uint64_t		seed;
353 	int			simple_interval;
354 	zbx_custom_interval_t	*custom_intervals;
355 	int			disable_until;
356 
357 	if (0 == (flags & ZBX_ITEM_COLLECTED) && 0 != item->nextcheck &&
358 			0 == (flags & ZBX_ITEM_KEY_CHANGED) && 0 == (flags & ZBX_ITEM_TYPE_CHANGED) &&
359 			0 == (flags & ZBX_ITEM_DELAY_CHANGED))
360 	{
361 		return SUCCEED;	/* avoid unnecessary nextcheck updates when syncing items in cache */
362 	}
363 
364 	seed = get_item_nextcheck_seed(item->itemid, item->interfaceid, item->type, item->key);
365 
366 	if (SUCCEED != zbx_interval_preproc(item->delay, &simple_interval, &custom_intervals, error))
367 	{
368 		/* Polling items with invalid update intervals repeatedly does not make sense because they */
369 		/* can only be healed by editing configuration (either update interval or macros involved) */
370 		/* and such changes will be detected during configuration synchronization. DCsync_items()  */
371 		/* detects item configuration changes affecting check scheduling and passes them in flags. */
372 
373 		item->nextcheck = ZBX_JAN_2038;
374 		item->schedulable = 0;
375 		return FAIL;
376 	}
377 
378 	if (0 != (flags & ZBX_HOST_UNREACHABLE) && NULL != interface && 0 != (disable_until =
379 			DCget_disable_until(item, interface)))
380 	{
381 		item->nextcheck = calculate_item_nextcheck_unreachable(simple_interval,
382 				custom_intervals, disable_until);
383 	}
384 	else
385 	{
386 		/* supported items and items that could not have been scheduled previously, but had */
387 		/* their update interval fixed, should be scheduled using their update intervals */
388 		item->nextcheck = calculate_item_nextcheck(seed, item->type, simple_interval,
389 				custom_intervals, now);
390 	}
391 
392 	zbx_custom_interval_free(custom_intervals);
393 
394 	item->schedulable = 1;
395 
396 	return SUCCEED;
397 }
398 
DCitem_poller_type_update(ZBX_DC_ITEM * dc_item,const ZBX_DC_HOST * dc_host,int flags)399 static void	DCitem_poller_type_update(ZBX_DC_ITEM *dc_item, const ZBX_DC_HOST *dc_host, int flags)
400 {
401 	unsigned char	poller_type;
402 
403 	if (0 != dc_host->proxy_hostid && SUCCEED != is_item_processed_by_server(dc_item->type, dc_item->key))
404 	{
405 		dc_item->poller_type = ZBX_NO_POLLER;
406 		return;
407 	}
408 
409 	poller_type = poller_by_item(dc_item->type, dc_item->key);
410 
411 	if (0 != (flags & ZBX_HOST_UNREACHABLE))
412 	{
413 		if (ZBX_POLLER_TYPE_NORMAL == poller_type || ZBX_POLLER_TYPE_JAVA == poller_type)
414 			poller_type = ZBX_POLLER_TYPE_UNREACHABLE;
415 
416 		dc_item->poller_type = poller_type;
417 		return;
418 	}
419 
420 	if (0 != (flags & ZBX_ITEM_COLLECTED))
421 	{
422 		dc_item->poller_type = poller_type;
423 		return;
424 	}
425 
426 	if (ZBX_POLLER_TYPE_UNREACHABLE != dc_item->poller_type ||
427 			(ZBX_POLLER_TYPE_NORMAL != poller_type && ZBX_POLLER_TYPE_JAVA != poller_type))
428 	{
429 		dc_item->poller_type = poller_type;
430 	}
431 }
432 
DCincrease_disable_until(ZBX_DC_INTERFACE * interface,int now)433 static void	DCincrease_disable_until(ZBX_DC_INTERFACE *interface, int now)
434 {
435 	if (NULL != interface && 0 != interface->errors_from)
436 		interface->disable_until = now + CONFIG_TIMEOUT;
437 }
438 
439 /******************************************************************************
440  *                                                                            *
441  * Function: DCfind_id                                                        *
442  *                                                                            *
443  * Purpose: Find an element in a hashset by its 'id' or create the element if *
444  *          it does not exist                                                 *
445  *                                                                            *
446  * Parameters:                                                                *
447  *     hashset - [IN] hashset to search                                       *
448  *     id      - [IN] id of element to search for                             *
449  *     size    - [IN] size of element to search for                           *
450  *     found   - [OUT flag. 0 - element did not exist, it was created.        *
451  *                          1 - existing element was found.                   *
452  *                                                                            *
453  * Return value: pointer to the found or created element                      *
454  *                                                                            *
455  ******************************************************************************/
DCfind_id(zbx_hashset_t * hashset,zbx_uint64_t id,size_t size,int * found)456 void	*DCfind_id(zbx_hashset_t *hashset, zbx_uint64_t id, size_t size, int *found)
457 {
458 	void		*ptr;
459 	zbx_uint64_t	buffer[1024];	/* adjust buffer size to accommodate any type DCfind_id() can be called for */
460 
461 	if (NULL == (ptr = zbx_hashset_search(hashset, &id)))
462 	{
463 		*found = 0;
464 
465 		buffer[0] = id;
466 		ptr = zbx_hashset_insert(hashset, &buffer[0], size);
467 	}
468 	else
469 	{
470 		*found = 1;
471 	}
472 
473 	return ptr;
474 }
475 
DCfind_item(zbx_uint64_t hostid,const char * key)476 static ZBX_DC_ITEM	*DCfind_item(zbx_uint64_t hostid, const char *key)
477 {
478 	ZBX_DC_ITEM_HK	*item_hk, item_hk_local;
479 
480 	item_hk_local.hostid = hostid;
481 	item_hk_local.key = key;
482 
483 	if (NULL == (item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk, &item_hk_local)))
484 		return NULL;
485 	else
486 		return item_hk->item_ptr;
487 }
488 
DCfind_host(const char * host)489 static ZBX_DC_HOST	*DCfind_host(const char *host)
490 {
491 	ZBX_DC_HOST_H	*host_h, host_h_local;
492 
493 	host_h_local.host = host;
494 
495 	if (NULL == (host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local)))
496 		return NULL;
497 	else
498 		return host_h->host_ptr;
499 }
500 
501 /******************************************************************************
502  *                                                                            *
503  * Function: DCfind_proxy                                                     *
504  *                                                                            *
505  * Purpose: Find a record with proxy details in configuration cache using the *
506  *          proxy name                                                        *
507  *                                                                            *
508  * Parameters: host - [IN] proxy name                                         *
509  *                                                                            *
510  * Return value: pointer to record if found or NULL otherwise                 *
511  *                                                                            *
512  ******************************************************************************/
DCfind_proxy(const char * host)513 static ZBX_DC_HOST	*DCfind_proxy(const char *host)
514 {
515 	ZBX_DC_HOST_H	*host_p, host_p_local;
516 
517 	host_p_local.host = host;
518 
519 	if (NULL == (host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local)))
520 		return NULL;
521 	else
522 		return host_p->host_ptr;
523 }
524 
525 /* private strpool functions */
526 
527 #define	REFCOUNT_FIELD_SIZE	sizeof(zbx_uint32_t)
528 
__config_strpool_hash(const void * data)529 static zbx_hash_t	__config_strpool_hash(const void *data)
530 {
531 	return ZBX_DEFAULT_STRING_HASH_FUNC((char *)data + REFCOUNT_FIELD_SIZE);
532 }
533 
__config_strpool_compare(const void * d1,const void * d2)534 static int	__config_strpool_compare(const void *d1, const void *d2)
535 {
536 	return strcmp((char *)d1 + REFCOUNT_FIELD_SIZE, (char *)d2 + REFCOUNT_FIELD_SIZE);
537 }
538 
zbx_strpool_intern(const char * str)539 static const char	*zbx_strpool_intern(const char *str)
540 {
541 	void		*record;
542 	zbx_uint32_t	*refcount;
543 
544 	record = zbx_hashset_search(&config->strpool, str - REFCOUNT_FIELD_SIZE);
545 
546 	if (NULL == record)
547 	{
548 		record = zbx_hashset_insert_ext(&config->strpool, str - REFCOUNT_FIELD_SIZE,
549 				REFCOUNT_FIELD_SIZE + strlen(str) + 1, REFCOUNT_FIELD_SIZE);
550 		*(zbx_uint32_t *)record = 0;
551 	}
552 
553 	refcount = (zbx_uint32_t *)record;
554 	(*refcount)++;
555 
556 	return (char *)record + REFCOUNT_FIELD_SIZE;
557 }
558 
zbx_strpool_release(const char * str)559 void	zbx_strpool_release(const char *str)
560 {
561 	zbx_uint32_t	*refcount;
562 
563 	refcount = (zbx_uint32_t *)(str - REFCOUNT_FIELD_SIZE);
564 	if (0 == --(*refcount))
565 		zbx_hashset_remove(&config->strpool, str - REFCOUNT_FIELD_SIZE);
566 }
567 
zbx_strpool_acquire(const char * str)568 static const char	*zbx_strpool_acquire(const char *str)
569 {
570 	zbx_uint32_t	*refcount;
571 
572 	refcount = (zbx_uint32_t *)(str - REFCOUNT_FIELD_SIZE);
573 	(*refcount)++;
574 
575 	return str;
576 }
577 
DCstrpool_replace(int found,const char ** curr,const char * new_str)578 int	DCstrpool_replace(int found, const char **curr, const char *new_str)
579 {
580 	if (1 == found)
581 	{
582 		if (0 == strcmp(*curr, new_str))
583 			return FAIL;
584 
585 		zbx_strpool_release(*curr);
586 	}
587 
588 	*curr = zbx_strpool_intern(new_str);
589 
590 	return SUCCEED;	/* indicate that the string has been replaced */
591 }
592 
DCupdate_item_queue(ZBX_DC_ITEM * item,unsigned char old_poller_type,int old_nextcheck)593 static void	DCupdate_item_queue(ZBX_DC_ITEM *item, unsigned char old_poller_type, int old_nextcheck)
594 {
595 	zbx_binary_heap_elem_t	elem;
596 
597 	if (ZBX_LOC_POLLER == item->location)
598 		return;
599 
600 	if (ZBX_LOC_QUEUE == item->location && old_poller_type != item->poller_type)
601 	{
602 		item->location = ZBX_LOC_NOWHERE;
603 		zbx_binary_heap_remove_direct(&config->queues[old_poller_type], item->itemid);
604 	}
605 
606 	if (item->poller_type == ZBX_NO_POLLER)
607 		return;
608 
609 	if (ZBX_LOC_QUEUE == item->location && old_nextcheck == item->nextcheck)
610 		return;
611 
612 	elem.key = item->itemid;
613 	elem.data = (const void *)item;
614 
615 	if (ZBX_LOC_QUEUE != item->location)
616 	{
617 		item->location = ZBX_LOC_QUEUE;
618 		zbx_binary_heap_insert(&config->queues[item->poller_type], &elem);
619 	}
620 	else
621 		zbx_binary_heap_update_direct(&config->queues[item->poller_type], &elem);
622 }
623 
DCupdate_proxy_queue(ZBX_DC_PROXY * proxy)624 static void	DCupdate_proxy_queue(ZBX_DC_PROXY *proxy)
625 {
626 	zbx_binary_heap_elem_t	elem;
627 
628 	if (ZBX_LOC_POLLER == proxy->location)
629 		return;
630 
631 	proxy->nextcheck = proxy->proxy_tasks_nextcheck;
632 	if (proxy->proxy_data_nextcheck < proxy->nextcheck)
633 		proxy->nextcheck = proxy->proxy_data_nextcheck;
634 	if (proxy->proxy_config_nextcheck < proxy->nextcheck)
635 		proxy->nextcheck = proxy->proxy_config_nextcheck;
636 
637 	elem.key = proxy->hostid;
638 	elem.data = (const void *)proxy;
639 
640 	if (ZBX_LOC_QUEUE != proxy->location)
641 	{
642 		proxy->location = ZBX_LOC_QUEUE;
643 		zbx_binary_heap_insert(&config->pqueue, &elem);
644 	}
645 	else
646 		zbx_binary_heap_update_direct(&config->pqueue, &elem);
647 }
648 
649 /******************************************************************************
650  *                                                                            *
651  * Function: config_gmacro_add_index                                          *
652  *                                                                            *
653  * Purpose: adds global macro index                                           *
654  *                                                                            *
655  * Parameters: gmacro_index - [IN/OUT] a global macro index hashset           *
656  *             gmacro       - [IN] the macro to index                         *
657  *                                                                            *
658  * Return value: The macro index record.                                      *
659  *                                                                            *
660  ******************************************************************************/
config_gmacro_add_index(zbx_hashset_t * gmacro_index,ZBX_DC_GMACRO * gmacro)661 static ZBX_DC_GMACRO_M	*config_gmacro_add_index(zbx_hashset_t *gmacro_index, ZBX_DC_GMACRO *gmacro)
662 {
663 	ZBX_DC_GMACRO_M	*gmacro_m, gmacro_m_local;
664 
665 	gmacro_m_local.macro = gmacro->macro;
666 
667 	if (NULL == (gmacro_m = (ZBX_DC_GMACRO_M *)zbx_hashset_search(gmacro_index, &gmacro_m_local)))
668 	{
669 		gmacro_m_local.macro = zbx_strpool_acquire(gmacro->macro);
670 		zbx_vector_ptr_create_ext(&gmacro_m_local.gmacros, __config_mem_malloc_func, __config_mem_realloc_func,
671 				__config_mem_free_func);
672 
673 		gmacro_m = (ZBX_DC_GMACRO_M *)zbx_hashset_insert(gmacro_index, &gmacro_m_local, sizeof(ZBX_DC_GMACRO_M));
674 	}
675 
676 	zbx_vector_ptr_append(&gmacro_m->gmacros, gmacro);
677 	return gmacro_m;
678 }
679 
680 /******************************************************************************
681  *                                                                            *
682  * Function: config_gmacro_remove_index                                       *
683  *                                                                            *
684  * Purpose: removes global macro index                                        *
685  *                                                                            *
686  * Parameters: gmacro_index - [IN/OUT] a global macro index hashset           *
687  *             gmacro       - [IN] the macro to remove                        *
688  *                                                                            *
689  ******************************************************************************/
config_gmacro_remove_index(zbx_hashset_t * gmacro_index,ZBX_DC_GMACRO * gmacro)690 static ZBX_DC_GMACRO_M	*config_gmacro_remove_index(zbx_hashset_t *gmacro_index, ZBX_DC_GMACRO *gmacro)
691 {
692 	ZBX_DC_GMACRO_M	*gmacro_m, gmacro_m_local;
693 	int		index;
694 
695 	gmacro_m_local.macro = gmacro->macro;
696 
697 	if (NULL != (gmacro_m = (ZBX_DC_GMACRO_M *)zbx_hashset_search(gmacro_index, &gmacro_m_local)))
698 	{
699 		if (FAIL != (index = zbx_vector_ptr_search(&gmacro_m->gmacros, gmacro, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
700 			zbx_vector_ptr_remove(&gmacro_m->gmacros, index);
701 	}
702 	return gmacro_m;
703 }
704 
705 /******************************************************************************
706  *                                                                            *
707  * Function: config_gmacro_context_compare                                    *
708  *                                                                            *
709  * Purpose: comparison function to sort global macro vector by context        *
710  *          operator, value and macro name                                    *
711  *                                                                            *
712  ******************************************************************************/
config_gmacro_context_compare(const void * d1,const void * d2)713 static int	config_gmacro_context_compare(const void *d1, const void *d2)
714 {
715 	const ZBX_DC_GMACRO	*m1 = *(const ZBX_DC_GMACRO **)d1;
716 	const ZBX_DC_GMACRO	*m2 = *(const ZBX_DC_GMACRO **)d2;
717 
718 	/* macros without context have higher priority than macros with */
719 	if (NULL == m1->context)
720 		return NULL == m2->context ? 0 : -1;
721 
722 	if (NULL == m2->context)
723 		return 1;
724 
725 	/* CONDITION_OPERATOR_EQUAL (0) has higher priority than CONDITION_OPERATOR_REGEXP (8) */
726 	ZBX_RETURN_IF_NOT_EQUAL(m1->context_op, m2->context_op);
727 
728 	return strcmp(m1->context, m2->context);
729 }
730 
731 /******************************************************************************
732  *                                                                            *
733  * Function: config_hmacro_add_index                                          *
734  *                                                                            *
735  * Purpose: adds host macro index                                             *
736  *                                                                            *
737  * Parameters: hmacro_index - [IN/OUT] a host macro index hashset             *
738  *             hmacro       - [IN] the macro to index                         *
739  *                                                                            *
740  ******************************************************************************/
config_hmacro_add_index(zbx_hashset_t * hmacro_index,ZBX_DC_HMACRO * hmacro)741 static ZBX_DC_HMACRO_HM	*config_hmacro_add_index(zbx_hashset_t *hmacro_index, ZBX_DC_HMACRO *hmacro)
742 {
743 	ZBX_DC_HMACRO_HM	*hmacro_hm, hmacro_hm_local;
744 
745 	hmacro_hm_local.hostid = hmacro->hostid;
746 	hmacro_hm_local.macro = hmacro->macro;
747 
748 	if (NULL == (hmacro_hm = (ZBX_DC_HMACRO_HM *)zbx_hashset_search(hmacro_index, &hmacro_hm_local)))
749 	{
750 		hmacro_hm_local.macro = zbx_strpool_acquire(hmacro->macro);
751 		zbx_vector_ptr_create_ext(&hmacro_hm_local.hmacros, __config_mem_malloc_func, __config_mem_realloc_func,
752 				__config_mem_free_func);
753 
754 		hmacro_hm = (ZBX_DC_HMACRO_HM *)zbx_hashset_insert(hmacro_index, &hmacro_hm_local, sizeof(ZBX_DC_HMACRO_HM));
755 	}
756 
757 	zbx_vector_ptr_append(&hmacro_hm->hmacros, hmacro);
758 	return hmacro_hm;
759 }
760 
761 /******************************************************************************
762  *                                                                            *
763  * Function: config_hmacro_remove_index                                       *
764  *                                                                            *
765  * Purpose: removes host macro index                                          *
766  *                                                                            *
767  * Parameters: hmacro_index - [IN/OUT] a host macro index hashset             *
768  *             hmacro       - [IN] the macro name to remove                   *
769  *                                                                            *
770  ******************************************************************************/
config_hmacro_remove_index(zbx_hashset_t * hmacro_index,ZBX_DC_HMACRO * hmacro)771 static ZBX_DC_HMACRO_HM	*config_hmacro_remove_index(zbx_hashset_t *hmacro_index, ZBX_DC_HMACRO *hmacro)
772 {
773 	ZBX_DC_HMACRO_HM	*hmacro_hm, hmacro_hm_local;
774 	int			index;
775 
776 	hmacro_hm_local.hostid = hmacro->hostid;
777 	hmacro_hm_local.macro = hmacro->macro;
778 
779 	if (NULL != (hmacro_hm = (ZBX_DC_HMACRO_HM *)zbx_hashset_search(hmacro_index, &hmacro_hm_local)))
780 	{
781 		if (FAIL != (index = zbx_vector_ptr_search(&hmacro_hm->hmacros, hmacro, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
782 			zbx_vector_ptr_remove(&hmacro_hm->hmacros, index);
783 	}
784 	return hmacro_hm;
785 }
786 
787 /******************************************************************************
788  *                                                                            *
789  * Function: config_hmacro_context_compare                                    *
790  *                                                                            *
791  * Purpose: comparison function to sort host macro vector by context          *
792  *          operator, value and macro name                                    *
793  *                                                                            *
794  ******************************************************************************/
config_hmacro_context_compare(const void * d1,const void * d2)795 static int	config_hmacro_context_compare(const void *d1, const void *d2)
796 {
797 	const ZBX_DC_HMACRO	*m1 = *(const ZBX_DC_HMACRO **)d1;
798 	const ZBX_DC_HMACRO	*m2 = *(const ZBX_DC_HMACRO **)d2;
799 
800 	/* macros without context have higher priority than macros with */
801 	if (NULL == m1->context)
802 		return NULL == m2->context ? 0 : -1;
803 
804 	if (NULL == m2->context)
805 		return 1;
806 
807 	/* CONDITION_OPERATOR_EQUAL (0) has higher priority than CONDITION_OPERATOR_REGEXP (8) */
808 	ZBX_RETURN_IF_NOT_EQUAL(m1->context_op, m2->context_op);
809 
810 	return strcmp(m1->context, m2->context);
811 }
812 
dc_compare_kvs_path(const void * d1,const void * d2)813 static int	dc_compare_kvs_path(const void *d1, const void *d2)
814 {
815 	const zbx_dc_kvs_path_t	*ptr1 = *((const zbx_dc_kvs_path_t **)d1);
816 	const zbx_dc_kvs_path_t	*ptr2 = *((const zbx_dc_kvs_path_t **)d2);
817 
818 	return strcmp(ptr1->path, ptr2->path);
819 }
820 
dc_kv_hash(const void * data)821 static zbx_hash_t	dc_kv_hash(const void *data)
822 {
823 	return ZBX_DEFAULT_STRING_HASH_FUNC(((zbx_dc_kv_t *)data)->key);
824 }
825 
dc_kv_compare(const void * d1,const void * d2)826 static int	dc_kv_compare(const void *d1, const void *d2)
827 {
828 	return strcmp(((zbx_dc_kv_t *)d1)->key, ((zbx_dc_kv_t *)d2)->key);
829 }
830 
config_kvs_path_add(const char * path,const char * key)831 static zbx_dc_kv_t	*config_kvs_path_add(const char *path, const char *key)
832 {
833 	zbx_dc_kvs_path_t	*kvs_path, kvs_path_local;
834 	zbx_dc_kv_t		*kv, kv_local;
835 	int			i;
836 
837 	kvs_path_local.path = path;
838 
839 	if (FAIL == (i = zbx_vector_ptr_search(&config->kvs_paths, &kvs_path_local, dc_compare_kvs_path)))
840 	{
841 		kvs_path = (zbx_dc_kvs_path_t *)__config_mem_malloc_func(NULL, sizeof(zbx_dc_kvs_path_t));
842 		DCstrpool_replace(0, &kvs_path->path, path);
843 		zbx_vector_ptr_append(&config->kvs_paths, kvs_path);
844 
845 		zbx_hashset_create_ext(&kvs_path->kvs, 0, dc_kv_hash, dc_kv_compare, NULL,
846 				__config_mem_malloc_func, __config_mem_realloc_func, __config_mem_free_func);
847 		kv = NULL;
848 	}
849 	else
850 	{
851 		kvs_path = (zbx_dc_kvs_path_t *)config->kvs_paths.values[i];
852 		kv_local.key = key;
853 		kv = (zbx_dc_kv_t *)zbx_hashset_search(&kvs_path->kvs, &kv_local);
854 	}
855 
856 	if (NULL == kv)
857 	{
858 		DCstrpool_replace(0, &kv_local.key, key);
859 		kv_local.value = NULL;
860 		kv_local.refcount = 0;
861 
862 		kv = (zbx_dc_kv_t *)zbx_hashset_insert(&kvs_path->kvs, &kv_local, sizeof(zbx_dc_kv_t));
863 	}
864 
865 	kv->refcount++;
866 
867 	return kv;
868 }
869 
config_kvs_path_remove(const char * value,zbx_dc_kv_t * kv)870 static void	config_kvs_path_remove(const char *value, zbx_dc_kv_t *kv)
871 {
872 	zbx_dc_kvs_path_t	*kvs_path, kvs_path_local;
873 	int			i;
874 	char			*path, *key;
875 
876 	if (0 != --kv->refcount)
877 		return;
878 
879 	zbx_strsplit(value, ':', &path, &key);
880 	zbx_free(key);
881 
882 	zbx_strpool_release(kv->key);
883 	if (NULL != kv->value)
884 		zbx_strpool_release(kv->value);
885 
886 	kvs_path_local.path = path;
887 
888 	if (FAIL == (i = zbx_vector_ptr_search(&config->kvs_paths, &kvs_path_local, dc_compare_kvs_path)))
889 	{
890 		THIS_SHOULD_NEVER_HAPPEN;
891 		goto clean;
892 	}
893 	kvs_path = (zbx_dc_kvs_path_t *)config->kvs_paths.values[i];
894 
895 	zbx_hashset_remove_direct(&kvs_path->kvs, kv);
896 
897 	if (0 == kvs_path->kvs.num_data)
898 	{
899 		zbx_strpool_release(kvs_path->path);
900 		__config_mem_free_func(kvs_path);
901 		zbx_vector_ptr_remove_noorder(&config->kvs_paths, i);
902 	}
903 clean:
904 	zbx_free(path);
905 }
906 
907 /******************************************************************************
908  *                                                                            *
909  * Function: set_hk_opt                                                       *
910  *                                                                            *
911  * Purpose: sets and validates global housekeeping option                     *
912  *                                                                            *
913  * Parameters: value     - [OUT] housekeeping setting                         *
914  *             non_zero  - [IN] 0 if value is allowed to be zero, 1 otherwise *
915  *             value_min - [IN] minimal acceptable setting value              *
916  *             value_raw - [IN] setting value to validate                     *
917  *                                                                            *
918  ******************************************************************************/
set_hk_opt(int * value,int non_zero,int value_min,const char * value_raw)919 static int	set_hk_opt(int *value, int non_zero, int value_min, const char *value_raw)
920 {
921 	if (SUCCEED != is_time_suffix(value_raw, value, ZBX_LENGTH_UNLIMITED))
922 		return FAIL;
923 
924 	if (0 != non_zero && 0 == *value)
925 		return FAIL;
926 
927 	if (0 != *value && (value_min > *value || ZBX_HK_PERIOD_MAX < *value))
928 		return FAIL;
929 
930 	return SUCCEED;
931 }
932 
DCsync_config(zbx_dbsync_t * sync,int * flags)933 static int	DCsync_config(zbx_dbsync_t *sync, int *flags)
934 {
935 	const ZBX_TABLE	*config_table;
936 
937 	const char	*selected_fields[] = {"discovery_groupid", "snmptrap_logging",
938 					"severity_name_0", "severity_name_1", "severity_name_2", "severity_name_3",
939 					"severity_name_4", "severity_name_5", "hk_events_mode", "hk_events_trigger",
940 					"hk_events_internal", "hk_events_discovery", "hk_events_autoreg",
941 					"hk_services_mode", "hk_services", "hk_audit_mode", "hk_audit",
942 					"hk_sessions_mode", "hk_sessions", "hk_history_mode", "hk_history_global",
943 					"hk_history", "hk_trends_mode", "hk_trends_global", "hk_trends",
944 					"default_inventory_mode", "db_extension", "autoreg_tls_accept",
945 					"compression_status", "compress_older", "instanceid",
946 					"default_timezone"};	/* sync with zbx_dbsync_compare_config() */
947 	const char	*row[ARRSIZE(selected_fields)];
948 	size_t		i;
949 	int		j, found = 1, ret;
950 	char		**db_row;
951 	zbx_uint64_t	rowid;
952 	unsigned char	tag;
953 
954 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
955 
956 	*flags = 0;
957 
958 	if (NULL == config->config)
959 	{
960 		found = 0;
961 		config->config = (ZBX_DC_CONFIG_TABLE *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_CONFIG_TABLE));
962 	}
963 
964 	if (SUCCEED != (ret = zbx_dbsync_next(sync, &rowid, &db_row, &tag)))
965 	{
966 		/* load default config data */
967 
968 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
969 			zabbix_log(LOG_LEVEL_ERR, "no records in table 'config'");
970 
971 		config_table = DBget_table("config");
972 
973 		for (i = 0; i < ARRSIZE(selected_fields); i++)
974 			row[i] = DBget_field(config_table, selected_fields[i])->default_value;
975 	}
976 	else
977 	{
978 		for (i = 0; i < ARRSIZE(selected_fields); i++)
979 			row[i] = db_row[i];
980 	}
981 
982 	/* store the config data */
983 
984 	if (NULL != row[0])
985 		ZBX_STR2UINT64(config->config->discovery_groupid, row[0]);
986 	else
987 		config->config->discovery_groupid = ZBX_DISCOVERY_GROUPID_UNDEFINED;
988 
989 	ZBX_STR2UCHAR(config->config->snmptrap_logging, row[1]);
990 	config->config->default_inventory_mode = atoi(row[25]);
991 	DCstrpool_replace(found, (const char **)&config->config->db.extension, row[26]);
992 	ZBX_STR2UCHAR(config->config->autoreg_tls_accept, row[27]);
993 	ZBX_STR2UCHAR(config->config->db.history_compression_status, row[28]);
994 
995 	if (SUCCEED != is_time_suffix(row[29], &config->config->db.history_compress_older, ZBX_LENGTH_UNLIMITED))
996 	{
997 		zabbix_log(LOG_LEVEL_WARNING, "invalid history compression age: %s", row[29]);
998 		config->config->db.history_compress_older = 0;
999 	}
1000 
1001 	for (j = 0; TRIGGER_SEVERITY_COUNT > j; j++)
1002 		DCstrpool_replace(found, &config->config->severity_name[j], row[2 + j]);
1003 
1004 	/* instance id cannot be changed - update it only at first sync to avoid read locks later */
1005 	if (0 == found)
1006 		DCstrpool_replace(found, &config->config->instanceid, row[30]);
1007 
1008 #if TRIGGER_SEVERITY_COUNT != 6
1009 #	error "row indexes below are based on assumption of six trigger severity levels"
1010 #endif
1011 
1012 	/* read housekeeper configuration */
1013 
1014 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.events_mode = atoi(row[8])) &&
1015 			(SUCCEED != set_hk_opt(&config->config->hk.events_trigger, 1, SEC_PER_DAY, row[9]) ||
1016 			SUCCEED != set_hk_opt(&config->config->hk.events_internal, 1, SEC_PER_DAY, row[10]) ||
1017 			SUCCEED != set_hk_opt(&config->config->hk.events_discovery, 1, SEC_PER_DAY, row[11]) ||
1018 			SUCCEED != set_hk_opt(&config->config->hk.events_autoreg, 1, SEC_PER_DAY, row[12])))
1019 	{
1020 		zabbix_log(LOG_LEVEL_WARNING, "trigger, internal, network discovery and auto-registration data"
1021 				" housekeeping will be disabled due to invalid settings");
1022 		config->config->hk.events_mode = ZBX_HK_OPTION_DISABLED;
1023 	}
1024 
1025 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.services_mode = atoi(row[13])) &&
1026 			SUCCEED != set_hk_opt(&config->config->hk.services, 1, SEC_PER_DAY, row[14]))
1027 	{
1028 		zabbix_log(LOG_LEVEL_WARNING, "IT services data housekeeping will be disabled due to invalid"
1029 				" settings");
1030 		config->config->hk.services_mode = ZBX_HK_OPTION_DISABLED;
1031 	}
1032 
1033 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.audit_mode = atoi(row[15])) &&
1034 			SUCCEED != set_hk_opt(&config->config->hk.audit, 1, SEC_PER_DAY, row[16]))
1035 	{
1036 		zabbix_log(LOG_LEVEL_WARNING, "audit data housekeeping will be disabled due to invalid"
1037 				" settings");
1038 		config->config->hk.audit_mode = ZBX_HK_OPTION_DISABLED;
1039 	}
1040 
1041 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.sessions_mode = atoi(row[17])) &&
1042 			SUCCEED != set_hk_opt(&config->config->hk.sessions, 1, SEC_PER_DAY, row[18]))
1043 	{
1044 		zabbix_log(LOG_LEVEL_WARNING, "user sessions data housekeeping will be disabled due to invalid"
1045 				" settings");
1046 		config->config->hk.sessions_mode = ZBX_HK_OPTION_DISABLED;
1047 	}
1048 
1049 	config->config->hk.history_mode = atoi(row[19]);
1050 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.history_global = atoi(row[20])) &&
1051 			SUCCEED != set_hk_opt(&config->config->hk.history, 0, ZBX_HK_HISTORY_MIN, row[21]))
1052 	{
1053 		zabbix_log(LOG_LEVEL_WARNING, "history data housekeeping will be disabled and all items will"
1054 				" store their history due to invalid global override settings");
1055 		config->config->hk.history_mode = ZBX_HK_MODE_DISABLED;
1056 		config->config->hk.history = 1;	/* just enough to make 0 == items[i].history condition fail */
1057 	}
1058 
1059 #ifdef HAVE_POSTGRESQL
1060 	if (ZBX_HK_MODE_DISABLED != config->config->hk.history_mode &&
1061 			ZBX_HK_OPTION_ENABLED == config->config->hk.history_global &&
1062 			0 == zbx_strcmp_null(config->config->db.extension, ZBX_CONFIG_DB_EXTENSION_TIMESCALE))
1063 	{
1064 		config->config->hk.history_mode = ZBX_HK_MODE_PARTITION;
1065 	}
1066 #endif
1067 
1068 	config->config->hk.trends_mode = atoi(row[22]);
1069 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.trends_global = atoi(row[23])) &&
1070 			SUCCEED != set_hk_opt(&config->config->hk.trends, 0, ZBX_HK_TRENDS_MIN, row[24]))
1071 	{
1072 		zabbix_log(LOG_LEVEL_WARNING, "trends data housekeeping will be disabled and all numeric items"
1073 				" will store their history due to invalid global override settings");
1074 		config->config->hk.trends_mode = ZBX_HK_MODE_DISABLED;
1075 		config->config->hk.trends = 1;	/* just enough to make 0 == items[i].trends condition fail */
1076 	}
1077 
1078 #ifdef HAVE_POSTGRESQL
1079 	if (ZBX_HK_MODE_DISABLED != config->config->hk.trends_mode &&
1080 			ZBX_HK_OPTION_ENABLED == config->config->hk.trends_global &&
1081 			0 == zbx_strcmp_null(config->config->db.extension, ZBX_CONFIG_DB_EXTENSION_TIMESCALE))
1082 	{
1083 		config->config->hk.trends_mode = ZBX_HK_MODE_PARTITION;
1084 	}
1085 #endif
1086 	DCstrpool_replace(found, &config->config->default_timezone, row[31]);
1087 
1088 	if (SUCCEED == ret && SUCCEED == zbx_dbsync_next(sync, &rowid, &db_row, &tag))	/* table must have */
1089 		zabbix_log(LOG_LEVEL_ERR, "table 'config' has multiple records");	/* only one record */
1090 
1091 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1092 
1093 	return SUCCEED;
1094 }
1095 
DCsync_autoreg_config(zbx_dbsync_t * sync)1096 static void	DCsync_autoreg_config(zbx_dbsync_t *sync)
1097 {
1098 	/* sync this function with zbx_dbsync_compare_autoreg_psk() */
1099 	char		**db_row;
1100 	zbx_uint64_t	rowid;
1101 	unsigned char	tag;
1102 
1103 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1104 
1105 	if (SUCCEED == zbx_dbsync_next(sync, &rowid, &db_row, &tag))
1106 	{
1107 		switch (tag)
1108 		{
1109 			case ZBX_DBSYNC_ROW_ADD:
1110 			case ZBX_DBSYNC_ROW_UPDATE:
1111 				zbx_strlcpy(config->autoreg_psk_identity, db_row[0],
1112 						sizeof(config->autoreg_psk_identity));
1113 				zbx_strlcpy(config->autoreg_psk, db_row[1], sizeof(config->autoreg_psk));
1114 				break;
1115 			case ZBX_DBSYNC_ROW_REMOVE:
1116 				config->autoreg_psk_identity[0] = '\0';
1117 				zbx_guaranteed_memset(config->autoreg_psk, 0, sizeof(config->autoreg_psk));
1118 				break;
1119 			default:
1120 				THIS_SHOULD_NEVER_HAPPEN;
1121 		}
1122 	}
1123 
1124 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1125 }
1126 
DCsync_proxy_remove(ZBX_DC_PROXY * proxy)1127 static void	DCsync_proxy_remove(ZBX_DC_PROXY *proxy)
1128 {
1129 	if (ZBX_LOC_QUEUE == proxy->location)
1130 	{
1131 		zbx_binary_heap_remove_direct(&config->pqueue, proxy->hostid);
1132 		proxy->location = ZBX_LOC_NOWHERE;
1133 	}
1134 
1135 	zbx_strpool_release(proxy->proxy_address);
1136 	zbx_hashset_remove_direct(&config->proxies, proxy);
1137 }
1138 
DCsync_hosts(zbx_dbsync_t * sync)1139 static void	DCsync_hosts(zbx_dbsync_t *sync)
1140 {
1141 	char		**row;
1142 	zbx_uint64_t	rowid;
1143 	unsigned char	tag;
1144 
1145 	ZBX_DC_HOST	*host;
1146 	ZBX_DC_IPMIHOST	*ipmihost;
1147 	ZBX_DC_PROXY	*proxy;
1148 	ZBX_DC_HOST_H	*host_h, host_h_local, *host_p, host_p_local;
1149 
1150 	int		found;
1151 	int		update_index_h, update_index_p, ret;
1152 	zbx_uint64_t	hostid, proxy_hostid;
1153 	unsigned char	status;
1154 	time_t		now;
1155 	signed char	ipmi_authtype;
1156 	unsigned char	ipmi_privilege;
1157 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1158 	ZBX_DC_PSK	*psk_i, psk_i_local;
1159 	zbx_ptr_pair_t	*psk_owner, psk_owner_local;
1160 	zbx_hashset_t	psk_owners;
1161 #endif
1162 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1163 
1164 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1165 	zbx_hashset_create(&psk_owners, 0, ZBX_DEFAULT_PTR_HASH_FUNC, ZBX_DEFAULT_PTR_COMPARE_FUNC);
1166 #endif
1167 	now = time(NULL);
1168 
1169 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1170 	{
1171 		/* removed rows will be always added at the end */
1172 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1173 			break;
1174 
1175 		ZBX_STR2UINT64(hostid, row[0]);
1176 		ZBX_DBROW2UINT64(proxy_hostid, row[1]);
1177 		ZBX_STR2UCHAR(status, row[10]);
1178 
1179 		host = (ZBX_DC_HOST *)DCfind_id(&config->hosts, hostid, sizeof(ZBX_DC_HOST), &found);
1180 
1181 		/* see whether we should and can update 'hosts_h' and 'hosts_p' indexes at this point */
1182 
1183 		update_index_h = 0;
1184 		update_index_p = 0;
1185 
1186 		if ((HOST_STATUS_MONITORED == status || HOST_STATUS_NOT_MONITORED == status) &&
1187 				(0 == found || 0 != strcmp(host->host, row[2])))
1188 		{
1189 			if (1 == found)
1190 			{
1191 				host_h_local.host = host->host;
1192 				host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local);
1193 
1194 				if (NULL != host_h && host == host_h->host_ptr)	/* see ZBX-4045 for NULL check */
1195 				{
1196 					zbx_strpool_release(host_h->host);
1197 					zbx_hashset_remove_direct(&config->hosts_h, host_h);
1198 				}
1199 			}
1200 
1201 			host_h_local.host = row[2];
1202 			host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local);
1203 
1204 			if (NULL != host_h)
1205 				host_h->host_ptr = host;
1206 			else
1207 				update_index_h = 1;
1208 		}
1209 		else if ((HOST_STATUS_PROXY_ACTIVE == status || HOST_STATUS_PROXY_PASSIVE == status) &&
1210 				(0 == found || 0 != strcmp(host->host, row[2])))
1211 		{
1212 			if (1 == found)
1213 			{
1214 				host_p_local.host = host->host;
1215 				host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local);
1216 
1217 				if (NULL != host_p && host == host_p->host_ptr)
1218 				{
1219 					zbx_strpool_release(host_p->host);
1220 					zbx_hashset_remove_direct(&config->hosts_p, host_p);
1221 				}
1222 			}
1223 
1224 			host_p_local.host = row[2];
1225 			host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local);
1226 
1227 			if (NULL != host_p)
1228 				host_p->host_ptr = host;
1229 			else
1230 				update_index_p = 1;
1231 		}
1232 
1233 		/* store new information in host structure */
1234 
1235 		DCstrpool_replace(found, &host->host, row[2]);
1236 		DCstrpool_replace(found, &host->name, row[11]);
1237 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1238 		DCstrpool_replace(found, &host->tls_issuer, row[15]);
1239 		DCstrpool_replace(found, &host->tls_subject, row[16]);
1240 
1241 		/* maintain 'config->psks' in configuration cache */
1242 
1243 		/*****************************************************************************/
1244 		/*                                                                           */
1245 		/* cases to cover (PSKid means PSK identity):                                */
1246 		/*                                                                           */
1247 		/*                                  Incoming data record                     */
1248 		/*                                  /                   \                    */
1249 		/*                                new                   new                  */
1250 		/*                               PSKid                 PSKid                 */
1251 		/*                             non-empty               empty                 */
1252 		/*                             /      \                /    \                */
1253 		/*                            /        \              /      \               */
1254 		/*                       'host'        'host'      'host'    'host'          */
1255 		/*                       record        record      record    record          */
1256 		/*                        has           has         has       has            */
1257 		/*                     non-empty       empty     non-empty  empty PSK        */
1258 		/*                        PSK           PSK         PSK      |     \         */
1259 		/*                       /   \           |           |       |      \        */
1260 		/*                      /     \          |           |       |       \       */
1261 		/*                     /       \         |           |       |        \      */
1262 		/*            new PSKid       new PSKid  |           |   existing     new    */
1263 		/*             same as         differs   |           |    record     record  */
1264 		/*            old PSKid         from     |           |      |          |     */
1265 		/*           /    |           old PSKid  |           |     done        |     */
1266 		/*          /     |              |       |           |                 |     */
1267 		/*   new PSK    new PSK        delete    |        delete               |     */
1268 		/*    value      value        old PSKid  |       old PSKid             |     */
1269 		/*   same as    differs       and value  |       and value             |     */
1270 		/*     old       from         from psks  |       from psks             |     */
1271 		/*      |        old          hashset    |        hashset              |     */
1272 		/*     done       /           (if ref    |        (if ref              |     */
1273 		/*               /            count=0)   |        count=0)             |     */
1274 		/*              /              /     \  /|           \                /      */
1275 		/*             /              /--------- |            \              /       */
1276 		/*            /              /         \ |             \            /        */
1277 		/*       delete          new PSKid   new PSKid         set pointer in        */
1278 		/*       old PSK          already     not in           'hosts' record        */
1279 		/*        value           in psks      psks             to NULL PSK          */
1280 		/*        from            hashset     hashset                |               */
1281 		/*       string            /   \          \                 done             */
1282 		/*        pool            /     \          \                                 */
1283 		/*         |             /       \          \                                */
1284 		/*       change    PSK value   PSK value    insert                           */
1285 		/*      PSK value  in hashset  in hashset  new PSKid                         */
1286 		/*      for this    same as     differs    and value                         */
1287 		/*       PSKid      new PSK     from new   into psks                         */
1288 		/*         |        value      PSK value    hashset                          */
1289 		/*        done        \           |            /                             */
1290 		/*                     \       replace        /                              */
1291 		/*                      \      PSK value     /                               */
1292 		/*                       \     in hashset   /                                */
1293 		/*                        \    with new    /                                 */
1294 		/*                         \   PSK value  /                                  */
1295 		/*                          \     |      /                                   */
1296 		/*                           \    |     /                                    */
1297 		/*                            set pointer                                    */
1298 		/*                            in 'host'                                      */
1299 		/*                            record to                                      */
1300 		/*                            new PSKid                                      */
1301 		/*                                |                                          */
1302 		/*                               done                                        */
1303 		/*                                                                           */
1304 		/*****************************************************************************/
1305 
1306 		psk_owner = NULL;
1307 
1308 		if ('\0' == *row[17] || '\0' == *row[18])	/* new PSKid or value empty */
1309 		{
1310 			/* In case of "impossible" errors ("PSK value without identity" or "PSK identity without */
1311 			/* value") assume empty PSK identity and value. These errors should have been prevented */
1312 			/* by validation in frontend/API. Be prepared when making a connection requiring PSK - */
1313 			/* the PSK might not be available. */
1314 
1315 			if (1 == found)
1316 			{
1317 				if (NULL == host->tls_dc_psk)	/* 'host' record has empty PSK */
1318 					goto done;
1319 
1320 				/* 'host' record has non-empty PSK. Unlink and delete PSK. */
1321 
1322 				psk_i_local.tls_psk_identity = host->tls_dc_psk->tls_psk_identity;
1323 
1324 				if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)) &&
1325 						0 == --(psk_i->refcount))
1326 				{
1327 					zbx_strpool_release(psk_i->tls_psk_identity);
1328 					zbx_strpool_release(psk_i->tls_psk);
1329 					zbx_hashset_remove_direct(&config->psks, psk_i);
1330 				}
1331 			}
1332 
1333 			host->tls_dc_psk = NULL;
1334 			goto done;
1335 		}
1336 
1337 		/* new PSKid and value non-empty */
1338 
1339 		zbx_strlower(row[18]);
1340 
1341 		if (1 == found && NULL != host->tls_dc_psk)	/* 'host' record has non-empty PSK */
1342 		{
1343 			if (0 == strcmp(host->tls_dc_psk->tls_psk_identity, row[17]))	/* new PSKid same as */
1344 											/* old PSKid */
1345 			{
1346 				if (0 != strcmp(host->tls_dc_psk->tls_psk, row[18]))	/* new PSK value */
1347 											/* differs from old */
1348 				{
1349 					if (NULL == (psk_owner = (zbx_ptr_pair_t *)zbx_hashset_search(&psk_owners,
1350 							&host->tls_dc_psk->tls_psk_identity)))
1351 					{
1352 						/* change underlying PSK value and 'config->psks' is updated, too */
1353 						DCstrpool_replace(1, &host->tls_dc_psk->tls_psk, row[18]);
1354 					}
1355 					else
1356 					{
1357 						zabbix_log(LOG_LEVEL_WARNING, "conflicting PSK values for PSK identity"
1358 								" \"%s\" on hosts \"%s\" and \"%s\" (and maybe others)",
1359 								(char *)psk_owner->first, (char *)psk_owner->second,
1360 								host->host);
1361 					}
1362 				}
1363 
1364 				goto done;
1365 			}
1366 
1367 			/* New PSKid differs from old PSKid. Unlink and delete old PSK. */
1368 
1369 			psk_i_local.tls_psk_identity = host->tls_dc_psk->tls_psk_identity;
1370 
1371 			if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)) &&
1372 					0 == --(psk_i->refcount))
1373 			{
1374 				zbx_strpool_release(psk_i->tls_psk_identity);
1375 				zbx_strpool_release(psk_i->tls_psk);
1376 				zbx_hashset_remove_direct(&config->psks, psk_i);
1377 			}
1378 
1379 			host->tls_dc_psk = NULL;
1380 		}
1381 
1382 		/* new PSK identity already stored? */
1383 
1384 		psk_i_local.tls_psk_identity = row[17];
1385 
1386 		if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)))
1387 		{
1388 			/* new PSKid already in psks hashset */
1389 
1390 			if (0 != strcmp(psk_i->tls_psk, row[18]))	/* PSKid stored but PSK value is different */
1391 			{
1392 				if (NULL == (psk_owner = (zbx_ptr_pair_t *)zbx_hashset_search(&psk_owners, &psk_i->tls_psk_identity)))
1393 				{
1394 					DCstrpool_replace(1, &psk_i->tls_psk, row[18]);
1395 				}
1396 				else
1397 				{
1398 					zabbix_log(LOG_LEVEL_WARNING, "conflicting PSK values for PSK identity"
1399 							" \"%s\" on hosts \"%s\" and \"%s\" (and maybe others)",
1400 							(char *)psk_owner->first, (char *)psk_owner->second,
1401 							host->host);
1402 				}
1403 			}
1404 
1405 			host->tls_dc_psk = psk_i;
1406 			psk_i->refcount++;
1407 			goto done;
1408 		}
1409 
1410 		/* insert new PSKid and value into psks hashset */
1411 
1412 		DCstrpool_replace(0, &psk_i_local.tls_psk_identity, row[17]);
1413 		DCstrpool_replace(0, &psk_i_local.tls_psk, row[18]);
1414 		psk_i_local.refcount = 1;
1415 		host->tls_dc_psk = zbx_hashset_insert(&config->psks, &psk_i_local, sizeof(ZBX_DC_PSK));
1416 done:
1417 		if (NULL != host->tls_dc_psk && NULL == psk_owner)
1418 		{
1419 			if (NULL == zbx_hashset_search(&psk_owners, &host->tls_dc_psk->tls_psk_identity))
1420 			{
1421 				/* register this host as the PSK identity owner, against which to report conflicts */
1422 
1423 				psk_owner_local.first = (char *)host->tls_dc_psk->tls_psk_identity;
1424 				psk_owner_local.second = (char *)host->host;
1425 
1426 				zbx_hashset_insert(&psk_owners, &psk_owner_local, sizeof(psk_owner_local));
1427 			}
1428 		}
1429 #endif
1430 		ZBX_STR2UCHAR(host->tls_connect, row[13]);
1431 		ZBX_STR2UCHAR(host->tls_accept, row[14]);
1432 
1433 		if ((HOST_STATUS_PROXY_PASSIVE == status && 0 != (ZBX_TCP_SEC_UNENCRYPTED & host->tls_connect)) ||
1434 				(HOST_STATUS_PROXY_ACTIVE == status && 0 != (ZBX_TCP_SEC_UNENCRYPTED & host->tls_accept)))
1435 		{
1436 			if (NULL != CONFIG_VAULTTOKEN)
1437 			{
1438 				zabbix_log(LOG_LEVEL_WARNING, "connection with Zabbix proxy \"%s\" should not be"
1439 						" unencrypted when using Vault", host->host);
1440 			}
1441 		}
1442 
1443 		if (0 == found)
1444 		{
1445 			ZBX_DBROW2UINT64(host->maintenanceid, row[17 + ZBX_HOST_TLS_OFFSET]);
1446 			host->maintenance_status = (unsigned char)atoi(row[7]);
1447 			host->maintenance_type = (unsigned char)atoi(row[8]);
1448 			host->maintenance_from = atoi(row[9]);
1449 			host->data_expected_from = now;
1450 			host->update_items = 0;
1451 
1452 			zbx_vector_ptr_create_ext(&host->interfaces_v, __config_mem_malloc_func,
1453 					__config_mem_realloc_func, __config_mem_free_func);
1454 		}
1455 		else
1456 		{
1457 			int reset_availability = 0;
1458 
1459 			if (HOST_STATUS_MONITORED == status && HOST_STATUS_MONITORED != host->status)
1460 				host->data_expected_from = now;
1461 
1462 			/* reset host status if host status has been changed (e.g., if host has been disabled) */
1463 			if (status != host->status)
1464 				reset_availability = 1;
1465 
1466 			/* reset host status if host proxy assignment has been changed */
1467 			if (proxy_hostid != host->proxy_hostid)
1468 				reset_availability = 1;
1469 
1470 			if (0 != reset_availability)
1471 			{
1472 				int			i;
1473 				ZBX_DC_INTERFACE	*interface;
1474 
1475 				for (i = 0; i < host->interfaces_v.values_num; i++)
1476 				{
1477 					interface = (ZBX_DC_INTERFACE *)host->interfaces_v.values[i];
1478 					interface->reset_availability = 1;
1479 				}
1480 			}
1481 
1482 		}
1483 
1484 		host->proxy_hostid = proxy_hostid;
1485 
1486 		/* update 'hosts_h' and 'hosts_p' indexes using new data, if not done already */
1487 
1488 		if (1 == update_index_h)
1489 		{
1490 			host_h_local.host = zbx_strpool_acquire(host->host);
1491 			host_h_local.host_ptr = host;
1492 			zbx_hashset_insert(&config->hosts_h, &host_h_local, sizeof(ZBX_DC_HOST_H));
1493 		}
1494 
1495 		if (1 == update_index_p)
1496 		{
1497 			host_p_local.host = zbx_strpool_acquire(host->host);
1498 			host_p_local.host_ptr = host;
1499 			zbx_hashset_insert(&config->hosts_p, &host_p_local, sizeof(ZBX_DC_HOST_H));
1500 		}
1501 
1502 		/* IPMI hosts */
1503 
1504 		ipmi_authtype = (signed char)atoi(row[3]);
1505 		ipmi_privilege = (unsigned char)atoi(row[4]);
1506 
1507 		if (ZBX_IPMI_DEFAULT_AUTHTYPE != ipmi_authtype || ZBX_IPMI_DEFAULT_PRIVILEGE != ipmi_privilege ||
1508 				'\0' != *row[5] || '\0' != *row[6])	/* useipmi */
1509 		{
1510 			ipmihost = (ZBX_DC_IPMIHOST *)DCfind_id(&config->ipmihosts, hostid, sizeof(ZBX_DC_IPMIHOST), &found);
1511 
1512 			ipmihost->ipmi_authtype = ipmi_authtype;
1513 			ipmihost->ipmi_privilege = ipmi_privilege;
1514 			DCstrpool_replace(found, &ipmihost->ipmi_username, row[5]);
1515 			DCstrpool_replace(found, &ipmihost->ipmi_password, row[6]);
1516 		}
1517 		else if (NULL != (ipmihost = (ZBX_DC_IPMIHOST *)zbx_hashset_search(&config->ipmihosts, &hostid)))
1518 		{
1519 			/* remove IPMI connection parameters for hosts without IPMI */
1520 
1521 			zbx_strpool_release(ipmihost->ipmi_username);
1522 			zbx_strpool_release(ipmihost->ipmi_password);
1523 
1524 			zbx_hashset_remove_direct(&config->ipmihosts, ipmihost);
1525 		}
1526 
1527 		/* proxies */
1528 
1529 		if (HOST_STATUS_PROXY_ACTIVE == status || HOST_STATUS_PROXY_PASSIVE == status)
1530 		{
1531 			proxy = (ZBX_DC_PROXY *)DCfind_id(&config->proxies, hostid, sizeof(ZBX_DC_PROXY), &found);
1532 
1533 			if (0 == found)
1534 			{
1535 				proxy->location = ZBX_LOC_NOWHERE;
1536 				proxy->version = 0;
1537 				proxy->lastaccess = atoi(row[12]);
1538 				proxy->last_cfg_error_time = 0;
1539 				proxy->proxy_delay = 0;
1540 				proxy->nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
1541 				proxy->nodata_win.values_num = 0;
1542 				proxy->nodata_win.period_end = 0;
1543 			}
1544 
1545 			proxy->auto_compress = atoi(row[16 + ZBX_HOST_TLS_OFFSET]);
1546 			DCstrpool_replace(found, &proxy->proxy_address, row[15 + ZBX_HOST_TLS_OFFSET]);
1547 
1548 			if (HOST_STATUS_PROXY_PASSIVE == status && (0 == found || status != host->status))
1549 			{
1550 				proxy->proxy_config_nextcheck = (int)calculate_proxy_nextcheck(
1551 						hostid, CONFIG_PROXYCONFIG_FREQUENCY, now);
1552 				proxy->proxy_data_nextcheck = (int)calculate_proxy_nextcheck(
1553 						hostid, CONFIG_PROXYDATA_FREQUENCY, now);
1554 				proxy->proxy_tasks_nextcheck = (int)calculate_proxy_nextcheck(
1555 						hostid, ZBX_TASK_UPDATE_FREQUENCY, now);
1556 
1557 				DCupdate_proxy_queue(proxy);
1558 			}
1559 			else if (HOST_STATUS_PROXY_ACTIVE == status && ZBX_LOC_QUEUE == proxy->location)
1560 			{
1561 				zbx_binary_heap_remove_direct(&config->pqueue, proxy->hostid);
1562 				proxy->location = ZBX_LOC_NOWHERE;
1563 			}
1564 			proxy->last_version_error_time = time(NULL);
1565 		}
1566 		else if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
1567 			DCsync_proxy_remove(proxy);
1568 
1569 		host->status = status;
1570 	}
1571 
1572 	/* remove deleted hosts from buffer */
1573 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1574 	{
1575 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &rowid)))
1576 			continue;
1577 
1578 		hostid = host->hostid;
1579 
1580 		/* IPMI hosts */
1581 
1582 		if (NULL != (ipmihost = (ZBX_DC_IPMIHOST *)zbx_hashset_search(&config->ipmihosts, &hostid)))
1583 		{
1584 			zbx_strpool_release(ipmihost->ipmi_username);
1585 			zbx_strpool_release(ipmihost->ipmi_password);
1586 
1587 			zbx_hashset_remove_direct(&config->ipmihosts, ipmihost);
1588 		}
1589 
1590 		/* proxies */
1591 
1592 		if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
1593 			DCsync_proxy_remove(proxy);
1594 
1595 		/* hosts */
1596 
1597 		if (HOST_STATUS_MONITORED == host->status || HOST_STATUS_NOT_MONITORED == host->status)
1598 		{
1599 			host_h_local.host = host->host;
1600 			host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local);
1601 
1602 			if (NULL != host_h && host == host_h->host_ptr)	/* see ZBX-4045 for NULL check */
1603 			{
1604 				zbx_strpool_release(host_h->host);
1605 				zbx_hashset_remove_direct(&config->hosts_h, host_h);
1606 			}
1607 		}
1608 		else if (HOST_STATUS_PROXY_ACTIVE == host->status || HOST_STATUS_PROXY_PASSIVE == host->status)
1609 		{
1610 			host_p_local.host = host->host;
1611 			host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local);
1612 
1613 			if (NULL != host_p && host == host_p->host_ptr)
1614 			{
1615 				zbx_strpool_release(host_p->host);
1616 				zbx_hashset_remove_direct(&config->hosts_p, host_p);
1617 			}
1618 		}
1619 
1620 		zbx_strpool_release(host->host);
1621 		zbx_strpool_release(host->name);
1622 
1623 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1624 		zbx_strpool_release(host->tls_issuer);
1625 		zbx_strpool_release(host->tls_subject);
1626 
1627 		/* Maintain 'psks' index. Unlink and delete the PSK identity. */
1628 		if (NULL != host->tls_dc_psk)
1629 		{
1630 			psk_i_local.tls_psk_identity = host->tls_dc_psk->tls_psk_identity;
1631 
1632 			if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)) &&
1633 					0 == --(psk_i->refcount))
1634 			{
1635 				zbx_strpool_release(psk_i->tls_psk_identity);
1636 				zbx_strpool_release(psk_i->tls_psk);
1637 				zbx_hashset_remove_direct(&config->psks, psk_i);
1638 			}
1639 		}
1640 #endif
1641 		zbx_vector_ptr_destroy(&host->interfaces_v);
1642 		zbx_hashset_remove_direct(&config->hosts, host);
1643 	}
1644 
1645 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1646 	zbx_hashset_destroy(&psk_owners);
1647 #endif
1648 
1649 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1650 }
1651 
DCsync_host_inventory(zbx_dbsync_t * sync)1652 static void	DCsync_host_inventory(zbx_dbsync_t *sync)
1653 {
1654 	ZBX_DC_HOST_INVENTORY	*host_inventory, *host_inventory_auto;
1655 	zbx_uint64_t		rowid, hostid;
1656 	int			found, ret, i;
1657 	char			**row;
1658 	unsigned char		tag;
1659 
1660 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1661 
1662 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1663 	{
1664 		/* removed rows will be always added at the end */
1665 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1666 			break;
1667 
1668 		ZBX_STR2UINT64(hostid, row[0]);
1669 
1670 		host_inventory = (ZBX_DC_HOST_INVENTORY *)DCfind_id(&config->host_inventories, hostid, sizeof(ZBX_DC_HOST_INVENTORY), &found);
1671 
1672 		ZBX_STR2UCHAR(host_inventory->inventory_mode, row[1]);
1673 
1674 		/* store new information in host_inventory structure */
1675 		for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1676 			DCstrpool_replace(found, &(host_inventory->values[i]), row[i + 2]);
1677 
1678 		host_inventory_auto = (ZBX_DC_HOST_INVENTORY *)DCfind_id(&config->host_inventories_auto, hostid, sizeof(ZBX_DC_HOST_INVENTORY),
1679 				&found);
1680 
1681 		host_inventory_auto->inventory_mode = host_inventory->inventory_mode;
1682 
1683 		if (1 == found)
1684 		{
1685 			for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1686 			{
1687 				if (NULL == host_inventory_auto->values[i])
1688 					continue;
1689 
1690 				zbx_strpool_release(host_inventory_auto->values[i]);
1691 				host_inventory_auto->values[i] = NULL;
1692 			}
1693 		}
1694 		else
1695 		{
1696 			for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1697 				host_inventory_auto->values[i] = NULL;
1698 		}
1699 	}
1700 
1701 	/* remove deleted host inventory from cache */
1702 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1703 	{
1704 		if (NULL == (host_inventory = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories, &rowid)))
1705 			continue;
1706 
1707 		for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1708 			zbx_strpool_release(host_inventory->values[i]);
1709 
1710 		zbx_hashset_remove_direct(&config->host_inventories, host_inventory);
1711 
1712 		if (NULL == (host_inventory_auto = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories_auto, &rowid)))
1713 		{
1714 			THIS_SHOULD_NEVER_HAPPEN;
1715 			continue;
1716 		}
1717 
1718 		for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1719 		{
1720 			if (NULL != host_inventory_auto->values[i])
1721 				zbx_strpool_release(host_inventory_auto->values[i]);
1722 		}
1723 
1724 		zbx_hashset_remove_direct(&config->host_inventories_auto, host_inventory_auto);
1725 	}
1726 
1727 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1728 }
1729 
DCsync_htmpls(zbx_dbsync_t * sync)1730 static void	DCsync_htmpls(zbx_dbsync_t *sync)
1731 {
1732 	char			**row;
1733 	zbx_uint64_t		rowid;
1734 	unsigned char		tag;
1735 
1736 	ZBX_DC_HTMPL		*htmpl = NULL;
1737 
1738 	int			found, i, index, ret;
1739 	zbx_uint64_t		_hostid = 0, hostid, templateid;
1740 	zbx_vector_ptr_t	sort;
1741 
1742 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1743 
1744 	zbx_vector_ptr_create(&sort);
1745 
1746 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1747 	{
1748 		/* removed rows will be always added at the end */
1749 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1750 			break;
1751 
1752 		ZBX_STR2UINT64(hostid, row[0]);
1753 		ZBX_STR2UINT64(templateid, row[1]);
1754 
1755 		if (_hostid != hostid || 0 == _hostid)
1756 		{
1757 			_hostid = hostid;
1758 
1759 			htmpl = (ZBX_DC_HTMPL *)DCfind_id(&config->htmpls, hostid, sizeof(ZBX_DC_HTMPL), &found);
1760 
1761 			if (0 == found)
1762 			{
1763 				zbx_vector_uint64_create_ext(&htmpl->templateids,
1764 						__config_mem_malloc_func,
1765 						__config_mem_realloc_func,
1766 						__config_mem_free_func);
1767 				zbx_vector_uint64_reserve(&htmpl->templateids, 1);
1768 			}
1769 
1770 			zbx_vector_ptr_append(&sort, htmpl);
1771 		}
1772 
1773 		zbx_vector_uint64_append(&htmpl->templateids, templateid);
1774 	}
1775 
1776 	/* remove deleted host templates from cache */
1777 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1778 	{
1779 		ZBX_STR2UINT64(hostid, row[0]);
1780 
1781 		if (NULL == (htmpl = (ZBX_DC_HTMPL *)zbx_hashset_search(&config->htmpls, &hostid)))
1782 			continue;
1783 
1784 		ZBX_STR2UINT64(templateid, row[1]);
1785 
1786 		if (-1 == (index = zbx_vector_uint64_search(&htmpl->templateids, templateid,
1787 				ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
1788 		{
1789 			continue;
1790 		}
1791 
1792 		if (1 == htmpl->templateids.values_num)
1793 		{
1794 			zbx_vector_uint64_destroy(&htmpl->templateids);
1795 			zbx_hashset_remove_direct(&config->htmpls, htmpl);
1796 		}
1797 		else
1798 		{
1799 			zbx_vector_uint64_remove_noorder(&htmpl->templateids, index);
1800 			zbx_vector_ptr_append(&sort, htmpl);
1801 		}
1802 	}
1803 
1804 	/* sort the changed template lists */
1805 
1806 	zbx_vector_ptr_sort(&sort, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1807 	zbx_vector_ptr_uniq(&sort, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1808 
1809 	for (i = 0; i < sort.values_num; i++)
1810 	{
1811 		htmpl = (ZBX_DC_HTMPL *)sort.values[i];
1812 		zbx_vector_uint64_sort(&htmpl->templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1813 	}
1814 
1815 	zbx_vector_ptr_destroy(&sort);
1816 
1817 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1818 }
1819 
DCsync_gmacros(zbx_dbsync_t * sync)1820 static void	DCsync_gmacros(zbx_dbsync_t *sync)
1821 {
1822 	char			**row;
1823 	zbx_uint64_t		rowid;
1824 	unsigned char		tag, context_op, type;
1825 	ZBX_DC_GMACRO		*gmacro;
1826 	int			found, context_existed, update_index, ret, i;
1827 	zbx_uint64_t		globalmacroid;
1828 	char			*macro = NULL, *context = NULL, *path = NULL, *key = NULL;
1829 	zbx_vector_ptr_t	indexes;
1830 	ZBX_DC_GMACRO_M		*gmacro_m;
1831 
1832 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1833 
1834 	zbx_vector_ptr_create(&indexes);
1835 
1836 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1837 	{
1838 		/* removed rows will be always added at the end */
1839 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1840 			break;
1841 
1842 		ZBX_STR2UINT64(globalmacroid, row[0]);
1843 		ZBX_STR2UCHAR(type, row[3]);
1844 
1845 		if (SUCCEED != zbx_user_macro_parse_dyn(row[1], &macro, &context, NULL, &context_op))
1846 		{
1847 			zabbix_log(LOG_LEVEL_WARNING, "cannot parse user macro \"%s\"", row[1]);
1848 			continue;
1849 		}
1850 
1851 		if (ZBX_MACRO_VALUE_VAULT == type)
1852 		{
1853 			zbx_free(path);
1854 			zbx_free(key);
1855 			zbx_strsplit(row[2], ':', &path, &key);
1856 			if (NULL == key)
1857 			{
1858 				zabbix_log(LOG_LEVEL_WARNING, "cannot parse user macro \"%s\" Vault location \"%s\":"
1859 						" missing separator \":\"", row[1], row[2]);
1860 				continue;
1861 			}
1862 
1863 			if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && NULL != CONFIG_VAULTDBPATH &&
1864 					0 == strcasecmp(CONFIG_VAULTDBPATH, path) &&
1865 					(0 == strcasecmp(key, ZBX_PROTO_TAG_PASSWORD)
1866 							|| 0 == strcasecmp(key, ZBX_PROTO_TAG_USERNAME)))
1867 			{
1868 				zabbix_log(LOG_LEVEL_WARNING, "cannot parse macro \"%s\" Vault location \"%s\":"
1869 						" database credentials should not be used with Vault macros",
1870 						row[1], row[2]);
1871 				continue;
1872 			}
1873 		}
1874 
1875 		gmacro = (ZBX_DC_GMACRO *)DCfind_id(&config->gmacros, globalmacroid, sizeof(ZBX_DC_GMACRO), &found);
1876 
1877 		/* see whether we should and can update gmacros_m index at this point */
1878 		update_index = 0;
1879 
1880 		if (0 == found || 0 != strcmp(gmacro->macro, macro) || 0 != zbx_strcmp_null(gmacro->context, context) ||
1881 				gmacro->context_op != context_op)
1882 		{
1883 			if (1 == found)
1884 			{
1885 				gmacro_m = config_gmacro_remove_index(&config->gmacros_m, gmacro);
1886 				zbx_vector_ptr_append(&indexes, gmacro_m);
1887 			}
1888 
1889 			update_index = 1;
1890 		}
1891 
1892 		if (0 != found && NULL != gmacro->kv)
1893 			config_kvs_path_remove(gmacro->value, gmacro->kv);
1894 
1895 		if (ZBX_MACRO_VALUE_VAULT == type)
1896 			gmacro->kv = config_kvs_path_add(path, key);
1897 		else
1898 			gmacro->kv = NULL;
1899 
1900 		/* store new information in macro structure */
1901 		gmacro->type = type;
1902 		gmacro->context_op = context_op;
1903 		DCstrpool_replace(found, &gmacro->macro, macro);
1904 		DCstrpool_replace(found, &gmacro->value, row[2]);
1905 
1906 		context_existed = (1 == found && NULL != gmacro->context);
1907 
1908 		if (NULL == context)
1909 		{
1910 			/* release the context if it was removed from the macro */
1911 			if (1 == context_existed)
1912 				zbx_strpool_release(gmacro->context);
1913 
1914 			gmacro->context = NULL;
1915 		}
1916 		else
1917 		{
1918 			/* replace the existing context (1) or add context to macro (0) */
1919 			DCstrpool_replace(context_existed, &gmacro->context, context);
1920 		}
1921 
1922 		/* update gmacros_m index using new data */
1923 		if (1 == update_index)
1924 		{
1925 			gmacro_m = config_gmacro_add_index(&config->gmacros_m, gmacro);
1926 			zbx_vector_ptr_append(&indexes, gmacro_m);
1927 		}
1928 	}
1929 
1930 	/* remove deleted global macros from cache */
1931 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1932 	{
1933 		if (NULL == (gmacro = (ZBX_DC_GMACRO *)zbx_hashset_search(&config->gmacros, &rowid)))
1934 			continue;
1935 
1936 		if (NULL != gmacro->kv)
1937 			config_kvs_path_remove(gmacro->value, gmacro->kv);
1938 
1939 		gmacro_m = config_gmacro_remove_index(&config->gmacros_m, gmacro);
1940 		zbx_vector_ptr_append(&indexes, gmacro_m);
1941 
1942 		zbx_strpool_release(gmacro->macro);
1943 		zbx_strpool_release(gmacro->value);
1944 
1945 		if (NULL != gmacro->context)
1946 			zbx_strpool_release(gmacro->context);
1947 
1948 		zbx_hashset_remove_direct(&config->gmacros, gmacro);
1949 	}
1950 
1951 	zbx_vector_ptr_sort(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
1952 	zbx_vector_ptr_uniq(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
1953 
1954 	for (i = 0; i < indexes.values_num; i++)
1955 	{
1956 		gmacro_m = (ZBX_DC_GMACRO_M *)indexes.values[i];
1957 		if (0 == gmacro_m->gmacros.values_num)
1958 		{
1959 			zbx_strpool_release(gmacro_m->macro);
1960 			zbx_vector_ptr_destroy(&gmacro_m->gmacros);
1961 			zbx_hashset_remove_direct(&config->gmacros_m, gmacro_m);
1962 		}
1963 		else
1964 			zbx_vector_ptr_sort(&gmacro_m->gmacros, config_gmacro_context_compare);
1965 	}
1966 
1967 	zbx_free(key);
1968 	zbx_free(path);
1969 	zbx_free(context);
1970 	zbx_free(macro);
1971 	zbx_vector_ptr_destroy(&indexes);
1972 
1973 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1974 }
1975 
DCsync_hmacros(zbx_dbsync_t * sync)1976 static void	DCsync_hmacros(zbx_dbsync_t *sync)
1977 {
1978 	char			**row;
1979 	zbx_uint64_t		rowid;
1980 	unsigned char		tag, context_op, type;
1981 	ZBX_DC_HMACRO		*hmacro;
1982 	int			found, context_existed, update_index, ret, i;
1983 	zbx_uint64_t		hostmacroid, hostid;
1984 	char			*macro = NULL, *context = NULL, *path = NULL, *key = NULL;
1985 	zbx_vector_ptr_t	indexes;
1986 	ZBX_DC_HMACRO_HM	*hmacro_hm;
1987 
1988 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1989 
1990 	zbx_vector_ptr_create(&indexes);
1991 
1992 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1993 	{
1994 		/* removed rows will be always added at the end */
1995 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1996 			break;
1997 
1998 		ZBX_STR2UINT64(hostmacroid, row[0]);
1999 		ZBX_STR2UINT64(hostid, row[1]);
2000 		ZBX_STR2UCHAR(type, row[4]);
2001 
2002 		if (SUCCEED != zbx_user_macro_parse_dyn(row[2], &macro, &context, NULL, &context_op))
2003 		{
2004 			zabbix_log(LOG_LEVEL_WARNING, "cannot parse host \"%s\" macro \"%s\"", row[1], row[2]);
2005 			continue;
2006 		}
2007 
2008 		if (ZBX_MACRO_VALUE_VAULT == type)
2009 		{
2010 			zbx_free(path);
2011 			zbx_free(key);
2012 			zbx_strsplit(row[3], ':', &path, &key);
2013 			if (NULL == key)
2014 			{
2015 				zabbix_log(LOG_LEVEL_WARNING, "cannot parse host \"%s\" macro \"%s\" Vault location"
2016 						" \"%s\": missing separator \":\"", row[1], row[2], row[3]);
2017 				continue;
2018 			}
2019 
2020 			if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && NULL != CONFIG_VAULTDBPATH &&
2021 					0 == strcasecmp(CONFIG_VAULTDBPATH, path) &&
2022 					(0 == strcasecmp(key, ZBX_PROTO_TAG_PASSWORD)
2023 							|| 0 == strcasecmp(key, ZBX_PROTO_TAG_USERNAME)))
2024 			{
2025 				zabbix_log(LOG_LEVEL_WARNING, "cannot parse host \"%s\" macro \"%s\" Vault location"
2026 						" \"%s\": database credentials should not be used with Vault macros",
2027 						row[1], row[2], row[3]);
2028 				continue;
2029 			}
2030 		}
2031 
2032 		hmacro = (ZBX_DC_HMACRO *)DCfind_id(&config->hmacros, hostmacroid, sizeof(ZBX_DC_HMACRO), &found);
2033 
2034 		/* see whether we should and can update hmacros_hm index at this point */
2035 		update_index = 0;
2036 
2037 		if (0 == found || hmacro->hostid != hostid || 0 != strcmp(hmacro->macro, macro) ||
2038 				0 != zbx_strcmp_null(hmacro->context, context) || hmacro->context_op != context_op)
2039 		{
2040 			if (1 == found)
2041 			{
2042 				hmacro_hm = config_hmacro_remove_index(&config->hmacros_hm, hmacro);
2043 				zbx_vector_ptr_append(&indexes, hmacro_hm);
2044 			}
2045 
2046 			update_index = 1;
2047 		}
2048 
2049 		if (0 != found && NULL != hmacro->kv)
2050 			config_kvs_path_remove(hmacro->value, hmacro->kv);
2051 
2052 		if (ZBX_MACRO_VALUE_VAULT == type)
2053 			hmacro->kv = config_kvs_path_add(path, key);
2054 		else
2055 			hmacro->kv = NULL;
2056 
2057 		/* store new information in macro structure */
2058 		hmacro->hostid = hostid;
2059 		hmacro->type = type;
2060 		hmacro->context_op = context_op;
2061 		DCstrpool_replace(found, &hmacro->macro, macro);
2062 		DCstrpool_replace(found, &hmacro->value, row[3]);
2063 
2064 		context_existed = (1 == found && NULL != hmacro->context);
2065 
2066 		if (NULL == context)
2067 		{
2068 			/* release the context if it was removed from the macro */
2069 			if (1 == context_existed)
2070 				zbx_strpool_release(hmacro->context);
2071 
2072 			hmacro->context = NULL;
2073 		}
2074 		else
2075 		{
2076 			/* replace the existing context (1) or add context to macro (0) */
2077 			DCstrpool_replace(context_existed, &hmacro->context, context);
2078 		}
2079 
2080 		/* update hmacros_hm index using new data */
2081 		if (1 == update_index)
2082 		{
2083 			hmacro_hm = config_hmacro_add_index(&config->hmacros_hm, hmacro);
2084 			zbx_vector_ptr_append(&indexes, hmacro_hm);
2085 		}
2086 	}
2087 
2088 	/* remove deleted host macros from buffer */
2089 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
2090 	{
2091 		if (NULL == (hmacro = (ZBX_DC_HMACRO *)zbx_hashset_search(&config->hmacros, &rowid)))
2092 			continue;
2093 
2094 		if (NULL != hmacro->kv)
2095 			config_kvs_path_remove(hmacro->value, hmacro->kv);
2096 
2097 		hmacro_hm = config_hmacro_remove_index(&config->hmacros_hm, hmacro);
2098 		zbx_vector_ptr_append(&indexes, hmacro_hm);
2099 
2100 		zbx_strpool_release(hmacro->macro);
2101 		zbx_strpool_release(hmacro->value);
2102 
2103 		if (NULL != hmacro->context)
2104 			zbx_strpool_release(hmacro->context);
2105 
2106 		zbx_hashset_remove_direct(&config->hmacros, hmacro);
2107 	}
2108 
2109 	zbx_vector_ptr_sort(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
2110 	zbx_vector_ptr_uniq(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
2111 
2112 	for (i = 0; i < indexes.values_num; i++)
2113 	{
2114 		hmacro_hm = (ZBX_DC_HMACRO_HM *)indexes.values[i];
2115 		if (0 == hmacro_hm->hmacros.values_num)
2116 		{
2117 			zbx_strpool_release(hmacro_hm->macro);
2118 			zbx_vector_ptr_destroy(&hmacro_hm->hmacros);
2119 			zbx_hashset_remove_direct(&config->hmacros_hm, hmacro_hm);
2120 		}
2121 		else
2122 			zbx_vector_ptr_sort(&hmacro_hm->hmacros, config_hmacro_context_compare);
2123 	}
2124 
2125 	zbx_free(key);
2126 	zbx_free(path);
2127 	zbx_free(context);
2128 	zbx_free(macro);
2129 	zbx_vector_ptr_destroy(&indexes);
2130 
2131 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2132 }
2133 
DCsync_kvs_paths(const struct zbx_json_parse * jp_kvs_paths)2134 static int	DCsync_kvs_paths(const struct zbx_json_parse *jp_kvs_paths)
2135 {
2136 	zbx_dc_kvs_path_t	*dc_kvs_path;
2137 	zbx_dc_kv_t		*dc_kv;
2138 	zbx_hashset_t		kvs;
2139 	zbx_hashset_iter_t	iter;
2140 	int			i, j, ret;
2141 	zbx_vector_ptr_pair_t	diff;
2142 
2143 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2144 
2145 	zbx_vector_ptr_pair_create(&diff);
2146 	zbx_hashset_create_ext(&kvs, 100, zbx_vault_kv_hash, zbx_vault_kv_compare, zbx_vault_kv_clean,
2147 			ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
2148 
2149 	for (i = 0; i < config->kvs_paths.values_num; i++)
2150 	{
2151 		char	*error = NULL;
2152 
2153 		dc_kvs_path = (zbx_dc_kvs_path_t *)config->kvs_paths.values[i];
2154 
2155 		if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER))
2156 		{
2157 			if (NULL == jp_kvs_paths)
2158 			{
2159 				ret = FAIL;
2160 				goto fail;
2161 			}
2162 
2163 			if (FAIL == zbx_vault_json_kvs_get(dc_kvs_path->path, jp_kvs_paths, &kvs, &error))
2164 			{
2165 				zabbix_log(LOG_LEVEL_WARNING, "cannot get secrets for path \"%s\": %s",
2166 						dc_kvs_path->path, error);
2167 				zbx_free(error);
2168 				continue;
2169 			}
2170 
2171 		}
2172 		else if (FAIL == zbx_vault_kvs_get(dc_kvs_path->path, &kvs, &error))
2173 		{
2174 			zabbix_log(LOG_LEVEL_WARNING, "cannot get secrets for path \"%s\": %s", dc_kvs_path->path, error);
2175 			zbx_free(error);
2176 			continue;
2177 		}
2178 
2179 		zbx_hashset_iter_reset(&dc_kvs_path->kvs, &iter);
2180 		while (NULL != (dc_kv = (zbx_dc_kv_t *)zbx_hashset_iter_next(&iter)))
2181 		{
2182 			zbx_kv_t	*kv, kv_local;
2183 			zbx_ptr_pair_t	pair;
2184 
2185 			kv_local.key = (char *)dc_kv->key;
2186 			if (NULL != (kv = zbx_hashset_search(&kvs, &kv_local)))
2187 			{
2188 				if (0 == zbx_strcmp_null(dc_kv->value, kv->value))
2189 					continue;
2190 			}
2191 			else if (NULL == dc_kv->value)
2192 				continue;
2193 
2194 			pair.first = dc_kv;
2195 			pair.second = kv;
2196 			zbx_vector_ptr_pair_append(&diff, pair);
2197 		}
2198 
2199 		if (0 != diff.values_num)
2200 		{
2201 			START_SYNC;
2202 
2203 			for (j = 0; j < diff.values_num; j++)
2204 			{
2205 				zbx_kv_t	*kv;
2206 
2207 				dc_kv = (zbx_dc_kv_t *)diff.values[j].first;
2208 				kv = (zbx_kv_t *)diff.values[j].second;
2209 
2210 				if (NULL != kv)
2211 				{
2212 					DCstrpool_replace(dc_kv->value != NULL ? 1 : 0, &dc_kv->value, kv->value);
2213 					continue;
2214 				}
2215 
2216 				zbx_strpool_release(dc_kv->value);
2217 				dc_kv->value = NULL;
2218 			}
2219 
2220 			FINISH_SYNC;
2221 		}
2222 
2223 		zbx_vector_ptr_pair_clear(&diff);
2224 		zbx_hashset_clear(&kvs);
2225 	}
2226 	ret = SUCCEED;
2227 fail:
2228 	zbx_vector_ptr_pair_destroy(&diff);
2229 	zbx_hashset_destroy(&kvs);
2230 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2231 
2232 	return ret;
2233 }
2234 
2235 /******************************************************************************
2236  *                                                                            *
2237  * Function: substitute_host_interface_macros                                 *
2238  *                                                                            *
2239  * Purpose: trying to resolve the macros in host interface                    *
2240  *                                                                            *
2241  ******************************************************************************/
substitute_host_interface_macros(ZBX_DC_INTERFACE * interface)2242 static void	substitute_host_interface_macros(ZBX_DC_INTERFACE *interface)
2243 {
2244 	int	macros;
2245 	char	*addr;
2246 	DC_HOST	host;
2247 
2248 	macros = STR_CONTAINS_MACROS(interface->ip) ? 0x01 : 0;
2249 	macros |= STR_CONTAINS_MACROS(interface->dns) ? 0x02 : 0;
2250 
2251 	if (0 != macros)
2252 	{
2253 		DCget_host_by_hostid(&host, interface->hostid);
2254 
2255 		if (0 != (macros & 0x01))
2256 		{
2257 			addr = zbx_strdup(NULL, interface->ip);
2258 			substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL, NULL, NULL,
2259 					&addr, MACRO_TYPE_INTERFACE_ADDR, NULL, 0);
2260 			if (SUCCEED == is_ip(addr) || SUCCEED == zbx_validate_hostname(addr))
2261 				DCstrpool_replace(1, &interface->ip, addr);
2262 			zbx_free(addr);
2263 		}
2264 
2265 		if (0 != (macros & 0x02))
2266 		{
2267 			addr = zbx_strdup(NULL, interface->dns);
2268 			substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL, NULL, NULL,
2269 					&addr, MACRO_TYPE_INTERFACE_ADDR, NULL, 0);
2270 			if (SUCCEED == is_ip(addr) || SUCCEED == zbx_validate_hostname(addr))
2271 				DCstrpool_replace(1, &interface->dns, addr);
2272 			zbx_free(addr);
2273 		}
2274 	}
2275 }
2276 
2277 /******************************************************************************
2278  *                                                                            *
2279  * Function: dc_interface_snmpaddrs_remove                                    *
2280  *                                                                            *
2281  * Purpose: remove interface from SNMP address -> interfaceid index           *
2282  *                                                                            *
2283  * Parameters: interface - [IN] the interface                                 *
2284  *                                                                            *
2285  ******************************************************************************/
dc_interface_snmpaddrs_remove(ZBX_DC_INTERFACE * interface)2286 static void	dc_interface_snmpaddrs_remove(ZBX_DC_INTERFACE *interface)
2287 {
2288 	ZBX_DC_INTERFACE_ADDR	*ifaddr, ifaddr_local;
2289 	int			index;
2290 
2291 	ifaddr_local.addr = (0 != interface->useip ? interface->ip : interface->dns);
2292 
2293 	if ('\0' == *ifaddr_local.addr)
2294 		return;
2295 
2296 	if (NULL == (ifaddr = (ZBX_DC_INTERFACE_ADDR *)zbx_hashset_search(&config->interface_snmpaddrs, &ifaddr_local)))
2297 		return;
2298 
2299 	if (FAIL == (index = zbx_vector_uint64_search(&ifaddr->interfaceids, interface->interfaceid,
2300 			ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2301 	{
2302 		return;
2303 	}
2304 
2305 	zbx_vector_uint64_remove_noorder(&ifaddr->interfaceids, index);
2306 
2307 	if (0 == ifaddr->interfaceids.values_num)
2308 	{
2309 		zbx_strpool_release(ifaddr->addr);
2310 		zbx_vector_uint64_destroy(&ifaddr->interfaceids);
2311 		zbx_hashset_remove_direct(&config->interface_snmpaddrs, ifaddr);
2312 	}
2313 }
2314 
2315 /******************************************************************************
2316  *                                                                            *
2317  * Function: dc_interface_snmp_set                                            *
2318  *                                                                            *
2319  * Purpose: setup SNMP attributes for interface with interfaceid index        *
2320  *                                                                            *
2321  * Parameters: interface - [IN] the interface                                 *
2322  *             row       - [IN] the row data from DB                          *
2323  *
2324  *                                                                            *
2325  ******************************************************************************/
dc_interface_snmp_set(zbx_uint64_t interfaceid,const char ** row,unsigned char * bulk_changed)2326 static ZBX_DC_SNMPINTERFACE	*dc_interface_snmp_set(zbx_uint64_t interfaceid, const char **row,
2327 		unsigned char *bulk_changed)
2328 {
2329 	int			found;
2330 	ZBX_DC_SNMPINTERFACE	*snmp;
2331 	unsigned char		bulk;
2332 
2333 	snmp = (ZBX_DC_SNMPINTERFACE *)DCfind_id(&config->interfaces_snmp, interfaceid, sizeof(ZBX_DC_SNMPINTERFACE),
2334 			&found);
2335 
2336 	ZBX_STR2UCHAR(bulk, row[13]);
2337 
2338 	if (0 == found)
2339 		*bulk_changed = 1;
2340 	else if (snmp->bulk != bulk)
2341 		*bulk_changed = 1;
2342 	else
2343 		*bulk_changed = 0;
2344 
2345 	if (0 != *bulk_changed)
2346 		snmp->bulk = bulk;
2347 
2348 	ZBX_STR2UCHAR(snmp->version, row[12]);
2349 	DCstrpool_replace(found, &snmp->community, row[14]);
2350 	DCstrpool_replace(found, &snmp->securityname, row[15]);
2351 	ZBX_STR2UCHAR(snmp->securitylevel, row[16]);
2352 	DCstrpool_replace(found, &snmp->authpassphrase, row[17]);
2353 	DCstrpool_replace(found, &snmp->privpassphrase, row[18]);
2354 	ZBX_STR2UCHAR(snmp->authprotocol, row[19]);
2355 	ZBX_STR2UCHAR(snmp->privprotocol, row[20]);
2356 	DCstrpool_replace(found, &snmp->contextname, row[21]);
2357 
2358 	return snmp;
2359 }
2360 
2361 /******************************************************************************
2362  *                                                                            *
2363  * Function: dc_interface_snmp_remove                                    *
2364  *                                                                            *
2365  * Purpose: remove interface from SNMP address -> interfaceid index           *
2366  *                                                                            *
2367  * Parameters: interface - [IN] the interface                                 *
2368  *                                                                            *
2369  ******************************************************************************/
dc_interface_snmp_remove(zbx_uint64_t interfaceid)2370 static void	dc_interface_snmp_remove(zbx_uint64_t interfaceid)
2371 {
2372 	ZBX_DC_SNMPINTERFACE	*snmp;
2373 
2374 	if (NULL == (snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid)))
2375 		return;
2376 
2377 	zbx_strpool_release(snmp->community);
2378 	zbx_strpool_release(snmp->securityname);
2379 	zbx_strpool_release(snmp->authpassphrase);
2380 	zbx_strpool_release(snmp->privpassphrase);
2381 	zbx_strpool_release(snmp->contextname);
2382 
2383 	zbx_hashset_remove_direct(&config->interfaces_snmp, snmp);
2384 
2385 	return;
2386 }
2387 
DCsync_interfaces(zbx_dbsync_t * sync)2388 static void	DCsync_interfaces(zbx_dbsync_t *sync)
2389 {
2390 	char			**row;
2391 	zbx_uint64_t		rowid;
2392 	unsigned char		tag;
2393 
2394 	ZBX_DC_INTERFACE	*interface;
2395 	ZBX_DC_INTERFACE_HT	*interface_ht, interface_ht_local;
2396 	ZBX_DC_INTERFACE_ADDR	*interface_snmpaddr, interface_snmpaddr_local;
2397 	ZBX_DC_HOST		*host;
2398 
2399 	int			found, update_index, ret, i;
2400 	zbx_uint64_t		interfaceid, hostid;
2401 	unsigned char		type, main_, useip;
2402 	unsigned char		reset_snmp_stats;
2403 	zbx_vector_ptr_t	interfaces;
2404 
2405 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2406 
2407 	zbx_vector_ptr_create(&interfaces);
2408 
2409 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
2410 	{
2411 		/* removed rows will be always added at the end */
2412 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
2413 			break;
2414 
2415 		ZBX_STR2UINT64(interfaceid, row[0]);
2416 		ZBX_STR2UINT64(hostid, row[1]);
2417 		ZBX_STR2UCHAR(type, row[2]);
2418 		ZBX_STR2UCHAR(main_, row[3]);
2419 		ZBX_STR2UCHAR(useip, row[4]);
2420 
2421 		/* If there is no host for this interface, skip it. */
2422 		/* This may be possible if the host was added after we synced config for hosts. */
2423 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
2424 			continue;
2425 
2426 		interface = (ZBX_DC_INTERFACE *)DCfind_id(&config->interfaces, interfaceid, sizeof(ZBX_DC_INTERFACE), &found);
2427 		zbx_vector_ptr_append(&interfaces, interface);
2428 
2429 		/* remove old address->interfaceid index */
2430 		if (0 != found && INTERFACE_TYPE_SNMP == interface->type)
2431 			dc_interface_snmpaddrs_remove(interface);
2432 
2433 		/* see whether we should and can update interfaces_ht index at this point */
2434 
2435 		update_index = 0;
2436 
2437 		if (0 == found || interface->hostid != hostid || interface->type != type || interface->main != main_)
2438 		{
2439 			if (1 == found && 1 == interface->main)
2440 			{
2441 				interface_ht_local.hostid = interface->hostid;
2442 				interface_ht_local.type = interface->type;
2443 				interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local);
2444 
2445 				if (NULL != interface_ht && interface == interface_ht->interface_ptr)
2446 				{
2447 					/* see ZBX-4045 for NULL check in the conditional */
2448 					zbx_hashset_remove(&config->interfaces_ht, &interface_ht_local);
2449 				}
2450 			}
2451 
2452 			if (1 == main_)
2453 			{
2454 				interface_ht_local.hostid = hostid;
2455 				interface_ht_local.type = type;
2456 				interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local);
2457 
2458 				if (NULL != interface_ht)
2459 					interface_ht->interface_ptr = interface;
2460 				else
2461 					update_index = 1;
2462 			}
2463 		}
2464 
2465 		/* store new information in interface structure */
2466 
2467 		reset_snmp_stats = (0 == found || interface->hostid != hostid || interface->type != type ||
2468 				interface->useip != useip);
2469 
2470 		interface->hostid = hostid;
2471 		interface->type = type;
2472 		interface->main = main_;
2473 		interface->useip = useip;
2474 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->ip, row[5]));
2475 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->dns, row[6]));
2476 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->port, row[7]));
2477 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->error, row[10]));
2478 
2479 		if (0 == found)
2480 		{
2481 			interface->errors_from = atoi(row[11]);
2482 			interface->available = (unsigned char)atoi(row[8]);
2483 			interface->disable_until = atoi(row[9]);
2484 			interface->availability_ts = time(NULL);
2485 			interface->reset_availability = 0;
2486 			interface->items_num = 0;
2487 		}
2488 
2489 		/* update interfaces_ht index using new data, if not done already */
2490 
2491 		if (1 == update_index)
2492 		{
2493 			interface_ht_local.hostid = interface->hostid;
2494 			interface_ht_local.type = interface->type;
2495 			interface_ht_local.interface_ptr = interface;
2496 			zbx_hashset_insert(&config->interfaces_ht, &interface_ht_local, sizeof(ZBX_DC_INTERFACE_HT));
2497 		}
2498 
2499 		/* update interface_snmpaddrs for SNMP traps or reset bulk request statistics */
2500 
2501 		if (INTERFACE_TYPE_SNMP == interface->type)
2502 		{
2503 			ZBX_DC_SNMPINTERFACE	*snmp;
2504 			unsigned char		bulk_changed;
2505 
2506 			interface_snmpaddr_local.addr = (0 != interface->useip ? interface->ip : interface->dns);
2507 
2508 			if ('\0' != *interface_snmpaddr_local.addr)
2509 			{
2510 				if (NULL == (interface_snmpaddr = (ZBX_DC_INTERFACE_ADDR *)zbx_hashset_search(&config->interface_snmpaddrs,
2511 						&interface_snmpaddr_local)))
2512 				{
2513 					zbx_strpool_acquire(interface_snmpaddr_local.addr);
2514 
2515 					interface_snmpaddr = (ZBX_DC_INTERFACE_ADDR *)zbx_hashset_insert(&config->interface_snmpaddrs,
2516 							&interface_snmpaddr_local, sizeof(ZBX_DC_INTERFACE_ADDR));
2517 					zbx_vector_uint64_create_ext(&interface_snmpaddr->interfaceids,
2518 							__config_mem_malloc_func,
2519 							__config_mem_realloc_func,
2520 							__config_mem_free_func);
2521 				}
2522 
2523 				zbx_vector_uint64_append(&interface_snmpaddr->interfaceids, interfaceid);
2524 			}
2525 
2526 			if (FAIL == DBis_null(row[12]))
2527 			{
2528 				snmp = dc_interface_snmp_set(interfaceid, (const char **)row, &bulk_changed);
2529 
2530 				if (1 == reset_snmp_stats || 0 != bulk_changed)
2531 				{
2532 					snmp->max_succeed = 0;
2533 					snmp->min_fail = MAX_SNMP_ITEMS + 1;
2534 				}
2535 			}
2536 			else
2537 				THIS_SHOULD_NEVER_HAPPEN;
2538 		}
2539 
2540 		/* first resolve macros for ip and dns fields in main agent interface  */
2541 		/* because other interfaces might reference main interfaces ip and dns */
2542 		/* with {HOST.IP} and {HOST.DNS} macros                                */
2543 		if (1 == interface->main && INTERFACE_TYPE_AGENT == interface->type)
2544 			substitute_host_interface_macros(interface);
2545 
2546 		if (0 == found)
2547 		{
2548 			/* new interface - add it to a list of host interfaces in 'config->hosts' hashset */
2549 
2550 			int	exists = 0;
2551 
2552 			/* It is an error if the pointer is already in the list. Detect it. */
2553 
2554 			for (i = 0; i < host->interfaces_v.values_num; i++)
2555 			{
2556 				if (interface == host->interfaces_v.values[i])
2557 				{
2558 					exists = 1;
2559 					break;
2560 				}
2561 			}
2562 
2563 			if (0 == exists)
2564 				zbx_vector_ptr_append(&host->interfaces_v, interface);
2565 			else
2566 				THIS_SHOULD_NEVER_HAPPEN;
2567 		}
2568 	}
2569 
2570 	/* resolve macros in other interfaces */
2571 
2572 	for (i = 0; i < interfaces.values_num; i++)
2573 	{
2574 		interface = (ZBX_DC_INTERFACE *)interfaces.values[i];
2575 
2576 		if (1 != interface->main || INTERFACE_TYPE_AGENT != interface->type)
2577 			substitute_host_interface_macros(interface);
2578 	}
2579 
2580 	/* remove deleted interfaces from buffer */
2581 
2582 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
2583 	{
2584 		if (NULL == (interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &rowid)))
2585 			continue;
2586 
2587 		/* remove interface from the list of host interfaces in 'config->hosts' hashset */
2588 
2589 		if (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &interface->hostid)))
2590 		{
2591 			for (i = 0; i < host->interfaces_v.values_num; i++)
2592 			{
2593 				if (interface == host->interfaces_v.values[i])
2594 				{
2595 					zbx_vector_ptr_remove(&host->interfaces_v, i);
2596 					break;
2597 				}
2598 			}
2599 		}
2600 
2601 		if (INTERFACE_TYPE_SNMP == interface->type)
2602 		{
2603 			dc_interface_snmpaddrs_remove(interface);
2604 			dc_interface_snmp_remove(interface->interfaceid);
2605 		}
2606 
2607 		if (1 == interface->main)
2608 		{
2609 			interface_ht_local.hostid = interface->hostid;
2610 			interface_ht_local.type = interface->type;
2611 			interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local);
2612 
2613 			if (NULL != interface_ht && interface == interface_ht->interface_ptr)
2614 			{
2615 				/* see ZBX-4045 for NULL check in the conditional */
2616 				zbx_hashset_remove(&config->interfaces_ht, &interface_ht_local);
2617 			}
2618 		}
2619 
2620 		zbx_strpool_release(interface->ip);
2621 		zbx_strpool_release(interface->dns);
2622 		zbx_strpool_release(interface->port);
2623 		zbx_strpool_release(interface->error);
2624 
2625 		zbx_hashset_remove_direct(&config->interfaces, interface);
2626 	}
2627 
2628 	zbx_vector_ptr_destroy(&interfaces);
2629 
2630 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2631 }
2632 
2633 /******************************************************************************
2634  *                                                                            *
2635  * Function: dc_interface_snmpitems_remove                                    *
2636  *                                                                            *
2637  * Purpose: remove item from interfaceid -> itemid index                      *
2638  *                                                                            *
2639  * Parameters: interface - [IN] the item                                      *
2640  *                                                                            *
2641  ******************************************************************************/
dc_interface_snmpitems_remove(ZBX_DC_ITEM * item)2642 static void	dc_interface_snmpitems_remove(ZBX_DC_ITEM *item)
2643 {
2644 	ZBX_DC_INTERFACE_ITEM	*ifitem;
2645 	int			index;
2646 	zbx_uint64_t		interfaceid;
2647 
2648 	if (0 == (interfaceid = item->interfaceid))
2649 		return;
2650 
2651 	if (NULL == (ifitem = (ZBX_DC_INTERFACE_ITEM *)zbx_hashset_search(&config->interface_snmpitems, &interfaceid)))
2652 		return;
2653 
2654 	if (FAIL == (index = zbx_vector_uint64_search(&ifitem->itemids, item->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2655 		return;
2656 
2657 	zbx_vector_uint64_remove_noorder(&ifitem->itemids, index);
2658 
2659 	if (0 == ifitem->itemids.values_num)
2660 	{
2661 		zbx_vector_uint64_destroy(&ifitem->itemids);
2662 		zbx_hashset_remove_direct(&config->interface_snmpitems, ifitem);
2663 	}
2664 }
2665 
2666 /******************************************************************************
2667  *                                                                            *
2668  * Function: dc_masteritem_remove_depitem                                     *
2669  *                                                                            *
2670  * Purpose: remove itemid from master item dependent itemid vector            *
2671  *                                                                            *
2672  * Parameters: master_itemid - [IN] the master item identifier                *
2673  *             dep_itemid    - [IN] the dependent item identifier             *
2674  *                                                                            *
2675  ******************************************************************************/
dc_masteritem_remove_depitem(zbx_uint64_t master_itemid,zbx_uint64_t dep_itemid)2676 static void	dc_masteritem_remove_depitem(zbx_uint64_t master_itemid, zbx_uint64_t dep_itemid)
2677 {
2678 	ZBX_DC_MASTERITEM	*masteritem;
2679 	int			index;
2680 	zbx_uint64_pair_t	pair;
2681 
2682 	if (NULL == (masteritem = (ZBX_DC_MASTERITEM *)zbx_hashset_search(&config->masteritems, &master_itemid)))
2683 		return;
2684 
2685 	pair.first = dep_itemid;
2686 	if (FAIL == (index = zbx_vector_uint64_pair_search(&masteritem->dep_itemids, pair,
2687 			ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2688 	{
2689 		return;
2690 	}
2691 
2692 	zbx_vector_uint64_pair_remove_noorder(&masteritem->dep_itemids, index);
2693 
2694 	if (0 == masteritem->dep_itemids.values_num)
2695 	{
2696 		zbx_vector_uint64_pair_destroy(&masteritem->dep_itemids);
2697 		zbx_hashset_remove_direct(&config->masteritems, masteritem);
2698 	}
2699 }
2700 
2701 /******************************************************************************
2702  *                                                                            *
2703  * Function: dc_interface_update_agent_stats                                  *
2704  *                                                                            *
2705  * Purpose: update number of items per agent statistics                       *
2706  *                                                                            *
2707  * Parameters: interface - [IN/OUT] the interface                             *
2708  * *           type      - [IN] the item type (ITEM_TYPE_*)                   *
2709  *             num       - [IN] the number of items (+) added, (-) removed    *
2710  *                                                                            *
2711  ******************************************************************************/
dc_interface_update_agent_stats(ZBX_DC_INTERFACE * interface,unsigned char type,int num)2712 static void	dc_interface_update_agent_stats(ZBX_DC_INTERFACE *interface, unsigned char type, int num)
2713 {
2714 	if ((NULL != interface) && ((ITEM_TYPE_ZABBIX == type && INTERFACE_TYPE_AGENT == interface->type) ||
2715 			(ITEM_TYPE_SNMP == type && INTERFACE_TYPE_SNMP == interface->type) ||
2716 			(ITEM_TYPE_JMX == type && INTERFACE_TYPE_JMX == interface->type) ||
2717 			(ITEM_TYPE_IPMI == type && INTERFACE_TYPE_IPMI == interface->type)))
2718 		interface->items_num += num;
2719 }
2720 
dup_serialized_expression(const unsigned char * src)2721 static unsigned char	*dup_serialized_expression(const unsigned char *src)
2722 {
2723 	zbx_uint32_t	offset, len;
2724 	unsigned char	*dst;
2725 
2726 	if (NULL == src || '\0' == *src)
2727 		return NULL;
2728 
2729 	offset = zbx_deserialize_uint31_compact(src, &len);
2730 	if (0 == len)
2731 		return NULL;
2732 
2733 	dst = (unsigned char *)zbx_malloc(NULL, offset + len);
2734 	memcpy(dst, src, offset + len);
2735 
2736 	return dst;
2737 }
2738 
config_decode_serialized_expression(const char * src)2739 static unsigned char	*config_decode_serialized_expression(const char *src)
2740 {
2741 	unsigned char	*dst;
2742 	int		data_len, src_len;
2743 
2744 	if (NULL == src || '\0' == *src)
2745 		return NULL;
2746 
2747 	src_len = strlen(src) * 3 / 4;
2748 	dst = __config_mem_malloc_func(NULL, src_len);
2749 	str_base64_decode(src, (char *)dst, src_len, &data_len);
2750 
2751 	return dst;
2752 }
2753 
DCsync_items(zbx_dbsync_t * sync,int flags)2754 static void	DCsync_items(zbx_dbsync_t *sync, int flags)
2755 {
2756 	char			**row;
2757 	zbx_uint64_t		rowid;
2758 	unsigned char		tag;
2759 
2760 	ZBX_DC_HOST		*host;
2761 
2762 	ZBX_DC_ITEM		*item;
2763 	ZBX_DC_NUMITEM		*numitem;
2764 	ZBX_DC_SNMPITEM		*snmpitem;
2765 	ZBX_DC_IPMIITEM		*ipmiitem;
2766 	ZBX_DC_TRAPITEM		*trapitem;
2767 	ZBX_DC_DEPENDENTITEM	*depitem;
2768 	ZBX_DC_LOGITEM		*logitem;
2769 	ZBX_DC_DBITEM		*dbitem;
2770 	ZBX_DC_SSHITEM		*sshitem;
2771 	ZBX_DC_TELNETITEM	*telnetitem;
2772 	ZBX_DC_SIMPLEITEM	*simpleitem;
2773 	ZBX_DC_JMXITEM		*jmxitem;
2774 	ZBX_DC_CALCITEM		*calcitem;
2775 	ZBX_DC_INTERFACE_ITEM	*interface_snmpitem;
2776 	ZBX_DC_MASTERITEM	*master;
2777 	ZBX_DC_PREPROCITEM	*preprocitem;
2778 	ZBX_DC_HTTPITEM		*httpitem;
2779 	ZBX_DC_SCRIPTITEM	*scriptitem;
2780 	ZBX_DC_ITEM_HK		*item_hk, item_hk_local;
2781 	ZBX_DC_INTERFACE	*interface;
2782 
2783 	time_t			now;
2784 	unsigned char		status, type, value_type, old_poller_type;
2785 	int			found, update_index, ret, i,  old_nextcheck;
2786 	zbx_uint64_t		itemid, hostid, interfaceid;
2787 	zbx_vector_ptr_t	dep_items;
2788 
2789 	zbx_vector_ptr_create(&dep_items);
2790 
2791 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2792 
2793 	now = time(NULL);
2794 
2795 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
2796 	{
2797 		/* removed rows will be always added at the end */
2798 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
2799 			break;
2800 
2801 		ZBX_STR2UINT64(itemid, row[0]);
2802 		ZBX_STR2UINT64(hostid, row[1]);
2803 		ZBX_STR2UCHAR(status, row[2]);
2804 		ZBX_STR2UCHAR(type, row[3]);
2805 
2806 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
2807 			continue;
2808 
2809 		item = (ZBX_DC_ITEM *)DCfind_id(&config->items, itemid, sizeof(ZBX_DC_ITEM), &found);
2810 
2811 		/* template item */
2812 		ZBX_DBROW2UINT64(item->templateid, row[48]);
2813 
2814 		/* LLD item prototype */
2815 		ZBX_DBROW2UINT64(item->parent_itemid, row[49]);
2816 
2817 		if (0 != found && ITEM_TYPE_SNMPTRAP == item->type)
2818 			dc_interface_snmpitems_remove(item);
2819 
2820 		/* see whether we should and can update items_hk index at this point */
2821 
2822 		update_index = 0;
2823 
2824 		if (0 == found || item->hostid != hostid || 0 != strcmp(item->key, row[5]))
2825 		{
2826 			if (1 == found)
2827 			{
2828 				item_hk_local.hostid = item->hostid;
2829 				item_hk_local.key = item->key;
2830 
2831 				if (NULL == (item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk,
2832 						&item_hk_local)))
2833 				{
2834 					/* item keys should be unique for items within a host, otherwise items with  */
2835 					/* same key share index and removal of last added item already cleared index */
2836 					THIS_SHOULD_NEVER_HAPPEN;
2837 				}
2838 				else if (item == item_hk->item_ptr)
2839 				{
2840 					zbx_strpool_release(item_hk->key);
2841 					zbx_hashset_remove_direct(&config->items_hk, item_hk);
2842 				}
2843 			}
2844 
2845 			item_hk_local.hostid = hostid;
2846 			item_hk_local.key = row[5];
2847 			item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk, &item_hk_local);
2848 
2849 			if (NULL != item_hk)
2850 				item_hk->item_ptr = item;
2851 			else
2852 				update_index = 1;
2853 		}
2854 
2855 		/* store new information in item structure */
2856 
2857 		item->hostid = hostid;
2858 		item->flags = (unsigned char)atoi(row[18]);
2859 		ZBX_DBROW2UINT64(interfaceid, row[19]);
2860 
2861 		if (SUCCEED != is_time_suffix(row[22], &item->history_sec, ZBX_LENGTH_UNLIMITED))
2862 			item->history_sec = ZBX_HK_PERIOD_MAX;
2863 
2864 		if (0 != item->history_sec && ZBX_HK_OPTION_ENABLED == config->config->hk.history_global)
2865 			item->history_sec = config->config->hk.history;
2866 
2867 		item->history = (0 != item->history_sec);
2868 
2869 		ZBX_STR2UCHAR(item->inventory_link, row[24]);
2870 		ZBX_DBROW2UINT64(item->valuemapid, row[25]);
2871 
2872 		if (0 != (ZBX_FLAG_DISCOVERY_RULE & item->flags))
2873 			value_type = ITEM_VALUE_TYPE_TEXT;
2874 		else
2875 			ZBX_STR2UCHAR(value_type, row[4]);
2876 
2877 		if (SUCCEED == DCstrpool_replace(found, &item->key, row[5]))
2878 			flags |= ZBX_ITEM_KEY_CHANGED;
2879 
2880 		if (0 == found)
2881 		{
2882 			item->triggers = NULL;
2883 			item->update_triggers = 0;
2884 			item->nextcheck = 0;
2885 			item->state = (unsigned char)atoi(row[12]);
2886 			ZBX_STR2UINT64(item->lastlogsize, row[20]);
2887 			item->mtime = atoi(row[21]);
2888 			DCstrpool_replace(found, &item->error, row[27]);
2889 			item->data_expected_from = now;
2890 			item->location = ZBX_LOC_NOWHERE;
2891 			item->poller_type = ZBX_NO_POLLER;
2892 			item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
2893 			item->schedulable = 1;
2894 
2895 			zbx_vector_ptr_create_ext(&item->tags, __config_mem_malloc_func, __config_mem_realloc_func,
2896 					__config_mem_free_func);
2897 		}
2898 		else
2899 		{
2900 			if (item->type != type)
2901 				flags |= ZBX_ITEM_TYPE_CHANGED;
2902 
2903 			if (ITEM_STATUS_ACTIVE == status && ITEM_STATUS_ACTIVE != item->status)
2904 				item->data_expected_from = now;
2905 
2906 			if (ITEM_STATUS_ACTIVE == item->status)
2907 			{
2908 				ZBX_DC_INTERFACE	*interface_old;
2909 
2910 				interface_old = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces,
2911 						&item->interfaceid);
2912 				dc_interface_update_agent_stats(interface_old, item->type, -1);
2913 			}
2914 		}
2915 
2916 		if (ITEM_STATUS_ACTIVE == status)
2917 		{
2918 			interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &interfaceid);
2919 			dc_interface_update_agent_stats(interface, type, 1);
2920 		}
2921 
2922 		item->type = type;
2923 		item->status = status;
2924 		item->value_type = value_type;
2925 		item->interfaceid = interfaceid;
2926 
2927 		/* update items_hk index using new data, if not done already */
2928 
2929 		if (1 == update_index)
2930 		{
2931 			item_hk_local.hostid = item->hostid;
2932 			item_hk_local.key = zbx_strpool_acquire(item->key);
2933 			item_hk_local.item_ptr = item;
2934 			zbx_hashset_insert(&config->items_hk, &item_hk_local, sizeof(ZBX_DC_ITEM_HK));
2935 		}
2936 
2937 		/* process item intervals and update item nextcheck */
2938 
2939 		if (SUCCEED == DCstrpool_replace(found, &item->delay, row[8]))
2940 			flags |= ZBX_ITEM_DELAY_CHANGED;
2941 
2942 		/* numeric items */
2943 
2944 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type || ITEM_VALUE_TYPE_UINT64 == item->value_type)
2945 		{
2946 			int	trends_sec;
2947 
2948 			numitem = (ZBX_DC_NUMITEM *)DCfind_id(&config->numitems, itemid, sizeof(ZBX_DC_NUMITEM), &found);
2949 
2950 			if (SUCCEED != is_time_suffix(row[23], &trends_sec, ZBX_LENGTH_UNLIMITED))
2951 				trends_sec = ZBX_HK_PERIOD_MAX;
2952 
2953 			if (0 != trends_sec && ZBX_HK_OPTION_ENABLED == config->config->hk.trends_global)
2954 				trends_sec = config->config->hk.trends;
2955 
2956 			numitem->trends = (0 != trends_sec);
2957 			numitem->trends_sec = trends_sec;
2958 
2959 			DCstrpool_replace(found, &numitem->units, row[26]);
2960 		}
2961 		else if (NULL != (numitem = (ZBX_DC_NUMITEM *)zbx_hashset_search(&config->numitems, &itemid)))
2962 		{
2963 			/* remove parameters for non-numeric item */
2964 
2965 			zbx_strpool_release(numitem->units);
2966 
2967 			zbx_hashset_remove_direct(&config->numitems, numitem);
2968 		}
2969 
2970 		/* SNMP items */
2971 
2972 		if (ITEM_TYPE_SNMP == item->type)
2973 		{
2974 			snmpitem = (ZBX_DC_SNMPITEM *)DCfind_id(&config->snmpitems, itemid, sizeof(ZBX_DC_SNMPITEM), &found);
2975 
2976 			if (SUCCEED == DCstrpool_replace(found, &snmpitem->snmp_oid, row[6]))
2977 			{
2978 				if (NULL != strchr(snmpitem->snmp_oid, '{'))
2979 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_MACRO;
2980 				else if (NULL != strchr(snmpitem->snmp_oid, '['))
2981 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_DYNAMIC;
2982 				else
2983 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_NORMAL;
2984 			}
2985 		}
2986 		else if (NULL != (snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &itemid)))
2987 		{
2988 			/* remove SNMP parameters for non-SNMP item */
2989 
2990 			zbx_strpool_release(snmpitem->snmp_oid);
2991 			zbx_hashset_remove_direct(&config->snmpitems, snmpitem);
2992 		}
2993 
2994 		/* IPMI items */
2995 
2996 		if (ITEM_TYPE_IPMI == item->type)
2997 		{
2998 			ipmiitem = (ZBX_DC_IPMIITEM *)DCfind_id(&config->ipmiitems, itemid, sizeof(ZBX_DC_IPMIITEM), &found);
2999 
3000 			DCstrpool_replace(found, &ipmiitem->ipmi_sensor, row[7]);
3001 		}
3002 		else if (NULL != (ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &itemid)))
3003 		{
3004 			/* remove IPMI parameters for non-IPMI item */
3005 			zbx_strpool_release(ipmiitem->ipmi_sensor);
3006 			zbx_hashset_remove_direct(&config->ipmiitems, ipmiitem);
3007 		}
3008 
3009 		/* trapper items */
3010 
3011 		if (ITEM_TYPE_TRAPPER == item->type && '\0' != *row[9])
3012 		{
3013 			trapitem = (ZBX_DC_TRAPITEM *)DCfind_id(&config->trapitems, itemid, sizeof(ZBX_DC_TRAPITEM), &found);
3014 			DCstrpool_replace(found, &trapitem->trapper_hosts, row[9]);
3015 		}
3016 		else if (NULL != (trapitem = (ZBX_DC_TRAPITEM *)zbx_hashset_search(&config->trapitems, &itemid)))
3017 		{
3018 			/* remove trapper_hosts parameter */
3019 			zbx_strpool_release(trapitem->trapper_hosts);
3020 			zbx_hashset_remove_direct(&config->trapitems, trapitem);
3021 		}
3022 
3023 		/* dependent items */
3024 
3025 		if (ITEM_TYPE_DEPENDENT == item->type && SUCCEED != DBis_null(row[29]))
3026 		{
3027 			depitem = (ZBX_DC_DEPENDENTITEM *)DCfind_id(&config->dependentitems, itemid,
3028 					sizeof(ZBX_DC_DEPENDENTITEM), &found);
3029 
3030 			if (1 == found)
3031 				depitem->last_master_itemid = depitem->master_itemid;
3032 			else
3033 				depitem->last_master_itemid = 0;
3034 
3035 			depitem->flags = item->flags;
3036 			ZBX_STR2UINT64(depitem->master_itemid, row[29]);
3037 
3038 			if (depitem->last_master_itemid != depitem->master_itemid)
3039 				zbx_vector_ptr_append(&dep_items, depitem);
3040 		}
3041 		else if (NULL != (depitem = (ZBX_DC_DEPENDENTITEM *)zbx_hashset_search(&config->dependentitems, &itemid)))
3042 		{
3043 			dc_masteritem_remove_depitem(depitem->master_itemid, itemid);
3044 			zbx_hashset_remove_direct(&config->dependentitems, depitem);
3045 		}
3046 
3047 		/* log items */
3048 
3049 		if (ITEM_VALUE_TYPE_LOG == item->value_type && '\0' != *row[10])
3050 		{
3051 			logitem = (ZBX_DC_LOGITEM *)DCfind_id(&config->logitems, itemid, sizeof(ZBX_DC_LOGITEM), &found);
3052 
3053 			DCstrpool_replace(found, &logitem->logtimefmt, row[10]);
3054 		}
3055 		else if (NULL != (logitem = (ZBX_DC_LOGITEM *)zbx_hashset_search(&config->logitems, &itemid)))
3056 		{
3057 			/* remove logtimefmt parameter */
3058 			zbx_strpool_release(logitem->logtimefmt);
3059 			zbx_hashset_remove_direct(&config->logitems, logitem);
3060 		}
3061 
3062 		/* db items */
3063 
3064 		if (ITEM_TYPE_DB_MONITOR == item->type && '\0' != *row[11])
3065 		{
3066 			dbitem = (ZBX_DC_DBITEM *)DCfind_id(&config->dbitems, itemid, sizeof(ZBX_DC_DBITEM), &found);
3067 
3068 			DCstrpool_replace(found, &dbitem->params, row[11]);
3069 			DCstrpool_replace(found, &dbitem->username, row[14]);
3070 			DCstrpool_replace(found, &dbitem->password, row[15]);
3071 		}
3072 		else if (NULL != (dbitem = (ZBX_DC_DBITEM *)zbx_hashset_search(&config->dbitems, &itemid)))
3073 		{
3074 			/* remove db item parameters */
3075 			zbx_strpool_release(dbitem->params);
3076 			zbx_strpool_release(dbitem->username);
3077 			zbx_strpool_release(dbitem->password);
3078 
3079 			zbx_hashset_remove_direct(&config->dbitems, dbitem);
3080 		}
3081 
3082 		/* SSH items */
3083 
3084 		if (ITEM_TYPE_SSH == item->type)
3085 		{
3086 			sshitem = (ZBX_DC_SSHITEM *)DCfind_id(&config->sshitems, itemid, sizeof(ZBX_DC_SSHITEM), &found);
3087 
3088 			sshitem->authtype = (unsigned short)atoi(row[13]);
3089 			DCstrpool_replace(found, &sshitem->username, row[14]);
3090 			DCstrpool_replace(found, &sshitem->password, row[15]);
3091 			DCstrpool_replace(found, &sshitem->publickey, row[16]);
3092 			DCstrpool_replace(found, &sshitem->privatekey, row[17]);
3093 			DCstrpool_replace(found, &sshitem->params, row[11]);
3094 		}
3095 		else if (NULL != (sshitem = (ZBX_DC_SSHITEM *)zbx_hashset_search(&config->sshitems, &itemid)))
3096 		{
3097 			/* remove SSH item parameters */
3098 
3099 			zbx_strpool_release(sshitem->username);
3100 			zbx_strpool_release(sshitem->password);
3101 			zbx_strpool_release(sshitem->publickey);
3102 			zbx_strpool_release(sshitem->privatekey);
3103 			zbx_strpool_release(sshitem->params);
3104 
3105 			zbx_hashset_remove_direct(&config->sshitems, sshitem);
3106 		}
3107 
3108 		/* TELNET items */
3109 
3110 		if (ITEM_TYPE_TELNET == item->type)
3111 		{
3112 			telnetitem = (ZBX_DC_TELNETITEM *)DCfind_id(&config->telnetitems, itemid, sizeof(ZBX_DC_TELNETITEM), &found);
3113 
3114 			DCstrpool_replace(found, &telnetitem->username, row[14]);
3115 			DCstrpool_replace(found, &telnetitem->password, row[15]);
3116 			DCstrpool_replace(found, &telnetitem->params, row[11]);
3117 		}
3118 		else if (NULL != (telnetitem = (ZBX_DC_TELNETITEM *)zbx_hashset_search(&config->telnetitems, &itemid)))
3119 		{
3120 			/* remove TELNET item parameters */
3121 
3122 			zbx_strpool_release(telnetitem->username);
3123 			zbx_strpool_release(telnetitem->password);
3124 			zbx_strpool_release(telnetitem->params);
3125 
3126 			zbx_hashset_remove_direct(&config->telnetitems, telnetitem);
3127 		}
3128 
3129 		/* simple items */
3130 
3131 		if (ITEM_TYPE_SIMPLE == item->type)
3132 		{
3133 			simpleitem = (ZBX_DC_SIMPLEITEM *)DCfind_id(&config->simpleitems, itemid, sizeof(ZBX_DC_SIMPLEITEM), &found);
3134 
3135 			DCstrpool_replace(found, &simpleitem->username, row[14]);
3136 			DCstrpool_replace(found, &simpleitem->password, row[15]);
3137 		}
3138 		else if (NULL != (simpleitem = (ZBX_DC_SIMPLEITEM *)zbx_hashset_search(&config->simpleitems, &itemid)))
3139 		{
3140 			/* remove simple item parameters */
3141 
3142 			zbx_strpool_release(simpleitem->username);
3143 			zbx_strpool_release(simpleitem->password);
3144 
3145 			zbx_hashset_remove_direct(&config->simpleitems, simpleitem);
3146 		}
3147 
3148 		/* JMX items */
3149 
3150 		if (ITEM_TYPE_JMX == item->type)
3151 		{
3152 			jmxitem = (ZBX_DC_JMXITEM *)DCfind_id(&config->jmxitems, itemid, sizeof(ZBX_DC_JMXITEM), &found);
3153 
3154 			DCstrpool_replace(found, &jmxitem->username, row[14]);
3155 			DCstrpool_replace(found, &jmxitem->password, row[15]);
3156 			DCstrpool_replace(found, &jmxitem->jmx_endpoint, row[28]);
3157 		}
3158 		else if (NULL != (jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &itemid)))
3159 		{
3160 			/* remove JMX item parameters */
3161 
3162 			zbx_strpool_release(jmxitem->username);
3163 			zbx_strpool_release(jmxitem->password);
3164 			zbx_strpool_release(jmxitem->jmx_endpoint);
3165 
3166 			zbx_hashset_remove_direct(&config->jmxitems, jmxitem);
3167 		}
3168 
3169 		/* SNMP trap items for current server/proxy */
3170 
3171 		if (ITEM_TYPE_SNMPTRAP == item->type && 0 == host->proxy_hostid)
3172 		{
3173 			interface_snmpitem = (ZBX_DC_INTERFACE_ITEM *)DCfind_id(&config->interface_snmpitems,
3174 					item->interfaceid, sizeof(ZBX_DC_INTERFACE_ITEM), &found);
3175 
3176 			if (0 == found)
3177 			{
3178 				zbx_vector_uint64_create_ext(&interface_snmpitem->itemids,
3179 						__config_mem_malloc_func,
3180 						__config_mem_realloc_func,
3181 						__config_mem_free_func);
3182 			}
3183 
3184 			zbx_vector_uint64_append(&interface_snmpitem->itemids, itemid);
3185 		}
3186 
3187 		/* calculated items */
3188 
3189 		if (ITEM_TYPE_CALCULATED == item->type)
3190 		{
3191 			calcitem = (ZBX_DC_CALCITEM *)DCfind_id(&config->calcitems, itemid, sizeof(ZBX_DC_CALCITEM),
3192 					&found);
3193 
3194 			DCstrpool_replace(found, &calcitem->params, row[11]);
3195 
3196 			if (1 == found && NULL != calcitem->formula_bin)
3197 				__config_mem_free_func((void *)calcitem->formula_bin);
3198 
3199 			calcitem->formula_bin = config_decode_serialized_expression(row[50]);
3200 		}
3201 		else if (NULL != (calcitem = (ZBX_DC_CALCITEM *)zbx_hashset_search(&config->calcitems, &itemid)))
3202 		{
3203 			/* remove calculated item parameters */
3204 
3205 			if (NULL != calcitem->formula_bin)
3206 				__config_mem_free_func((void *)calcitem->formula_bin);
3207 			zbx_strpool_release(calcitem->params);
3208 			zbx_hashset_remove_direct(&config->calcitems, calcitem);
3209 		}
3210 
3211 		/* HTTP agent items */
3212 
3213 		if (ITEM_TYPE_HTTPAGENT == item->type)
3214 		{
3215 			httpitem = (ZBX_DC_HTTPITEM *)DCfind_id(&config->httpitems, itemid, sizeof(ZBX_DC_HTTPITEM),
3216 					&found);
3217 
3218 			DCstrpool_replace(found, &httpitem->timeout, row[30]);
3219 			DCstrpool_replace(found, &httpitem->url, row[31]);
3220 			DCstrpool_replace(found, &httpitem->query_fields, row[32]);
3221 			DCstrpool_replace(found, &httpitem->posts, row[33]);
3222 			DCstrpool_replace(found, &httpitem->status_codes, row[34]);
3223 			httpitem->follow_redirects = (unsigned char)atoi(row[35]);
3224 			httpitem->post_type = (unsigned char)atoi(row[36]);
3225 			DCstrpool_replace(found, &httpitem->http_proxy, row[37]);
3226 			DCstrpool_replace(found, &httpitem->headers, row[38]);
3227 			httpitem->retrieve_mode = (unsigned char)atoi(row[39]);
3228 			httpitem->request_method = (unsigned char)atoi(row[40]);
3229 			httpitem->output_format = (unsigned char)atoi(row[41]);
3230 			DCstrpool_replace(found, &httpitem->ssl_cert_file, row[42]);
3231 			DCstrpool_replace(found, &httpitem->ssl_key_file, row[43]);
3232 			DCstrpool_replace(found, &httpitem->ssl_key_password, row[44]);
3233 			httpitem->verify_peer = (unsigned char)atoi(row[45]);
3234 			httpitem->verify_host = (unsigned char)atoi(row[46]);
3235 			httpitem->allow_traps = (unsigned char)atoi(row[47]);
3236 
3237 			httpitem->authtype = (unsigned char)atoi(row[13]);
3238 			DCstrpool_replace(found, &httpitem->username, row[14]);
3239 			DCstrpool_replace(found, &httpitem->password, row[15]);
3240 			DCstrpool_replace(found, &httpitem->trapper_hosts, row[9]);
3241 		}
3242 		else if (NULL != (httpitem = (ZBX_DC_HTTPITEM *)zbx_hashset_search(&config->httpitems, &itemid)))
3243 		{
3244 			zbx_strpool_release(httpitem->timeout);
3245 			zbx_strpool_release(httpitem->url);
3246 			zbx_strpool_release(httpitem->query_fields);
3247 			zbx_strpool_release(httpitem->posts);
3248 			zbx_strpool_release(httpitem->status_codes);
3249 			zbx_strpool_release(httpitem->http_proxy);
3250 			zbx_strpool_release(httpitem->headers);
3251 			zbx_strpool_release(httpitem->ssl_cert_file);
3252 			zbx_strpool_release(httpitem->ssl_key_file);
3253 			zbx_strpool_release(httpitem->ssl_key_password);
3254 			zbx_strpool_release(httpitem->username);
3255 			zbx_strpool_release(httpitem->password);
3256 			zbx_strpool_release(httpitem->trapper_hosts);
3257 
3258 			zbx_hashset_remove_direct(&config->httpitems, httpitem);
3259 		}
3260 
3261 		/* Script items */
3262 
3263 		if (ITEM_TYPE_SCRIPT == item->type)
3264 		{
3265 			scriptitem = (ZBX_DC_SCRIPTITEM *)DCfind_id(&config->scriptitems, itemid,
3266 					sizeof(ZBX_DC_SCRIPTITEM), &found);
3267 
3268 			DCstrpool_replace(found, &scriptitem->timeout, row[30]);
3269 			DCstrpool_replace(found, &scriptitem->script, row[11]);
3270 
3271 			if (0 == found)
3272 			{
3273 				zbx_vector_ptr_create_ext(&scriptitem->params, __config_mem_malloc_func,
3274 						__config_mem_realloc_func, __config_mem_free_func);
3275 			}
3276 		}
3277 		else if (NULL != (scriptitem = (ZBX_DC_SCRIPTITEM *)zbx_hashset_search(&config->scriptitems, &itemid)))
3278 		{
3279 			zbx_strpool_release(scriptitem->timeout);
3280 			zbx_strpool_release(scriptitem->script);
3281 
3282 			zbx_vector_ptr_destroy(&scriptitem->params);
3283 			zbx_hashset_remove_direct(&config->scriptitems, scriptitem);
3284 		}
3285 
3286 		/* it is crucial to update type specific (config->snmpitems, config->ipmiitems, etc.) hashsets before */
3287 		/* attempting to requeue an item because type specific properties are used to arrange items in queues */
3288 
3289 		old_poller_type = item->poller_type;
3290 		old_nextcheck = item->nextcheck;
3291 
3292 		if (ITEM_STATUS_ACTIVE == item->status && HOST_STATUS_MONITORED == host->status)
3293 		{
3294 			DCitem_poller_type_update(item, host, flags);
3295 
3296 			if (SUCCEED == zbx_is_counted_in_item_queue(item->type, item->key))
3297 			{
3298 				char	*error = NULL;
3299 
3300 				if (FAIL == DCitem_nextcheck_update(item, interface, flags, now, &error))
3301 				{
3302 					zbx_timespec_t	ts = {now, 0};
3303 
3304 					/* Usual way for an item to become not supported is to receive an error     */
3305 					/* instead of value. Item state and error will be updated by history syncer */
3306 					/* during history sync following a regular procedure with item update in    */
3307 					/* database and config cache, logging etc. There is no need to set          */
3308 					/* ITEM_STATE_NOTSUPPORTED here.                                            */
3309 
3310 					if (0 == host->proxy_hostid)
3311 					{
3312 						dc_add_history(item->itemid, item->value_type, 0, NULL, &ts,
3313 								ITEM_STATE_NOTSUPPORTED, error);
3314 					}
3315 					zbx_free(error);
3316 				}
3317 			}
3318 		}
3319 		else
3320 		{
3321 			item->nextcheck = 0;
3322 			item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
3323 			item->poller_type = ZBX_NO_POLLER;
3324 		}
3325 
3326 		DCupdate_item_queue(item, old_poller_type, old_nextcheck);
3327 	}
3328 
3329 	/* update dependent item vectors within master items */
3330 
3331 	for (i = 0; i < dep_items.values_num; i++)
3332 	{
3333 		zbx_uint64_pair_t	pair;
3334 
3335 		depitem = (ZBX_DC_DEPENDENTITEM *)dep_items.values[i];
3336 		dc_masteritem_remove_depitem(depitem->last_master_itemid, depitem->itemid);
3337 		pair.first = depitem->itemid;
3338 		pair.second = depitem->flags;
3339 
3340 		/* append item to dependent item vector of master item */
3341 		if (NULL == (master = (ZBX_DC_MASTERITEM *)zbx_hashset_search(&config->masteritems, &depitem->master_itemid)))
3342 		{
3343 			ZBX_DC_MASTERITEM	master_local;
3344 
3345 			master_local.itemid = depitem->master_itemid;
3346 			master = (ZBX_DC_MASTERITEM *)zbx_hashset_insert(&config->masteritems, &master_local, sizeof(master_local));
3347 
3348 			zbx_vector_uint64_pair_create_ext(&master->dep_itemids, __config_mem_malloc_func,
3349 					__config_mem_realloc_func, __config_mem_free_func);
3350 		}
3351 
3352 		zbx_vector_uint64_pair_append(&master->dep_itemids, pair);
3353 	}
3354 
3355 	zbx_vector_ptr_destroy(&dep_items);
3356 
3357 	/* remove deleted items from buffer */
3358 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3359 	{
3360 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &rowid)))
3361 			continue;
3362 
3363 		if (ITEM_STATUS_ACTIVE == item->status)
3364 		{
3365 			interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &item->interfaceid);
3366 			dc_interface_update_agent_stats(interface, item->type, -1);
3367 		}
3368 
3369 		itemid = item->itemid;
3370 
3371 		if (ITEM_TYPE_SNMPTRAP == item->type)
3372 			dc_interface_snmpitems_remove(item);
3373 
3374 		/* numeric items */
3375 
3376 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type || ITEM_VALUE_TYPE_UINT64 == item->value_type)
3377 		{
3378 			numitem = (ZBX_DC_NUMITEM *)zbx_hashset_search(&config->numitems, &itemid);
3379 
3380 			zbx_strpool_release(numitem->units);
3381 
3382 			zbx_hashset_remove_direct(&config->numitems, numitem);
3383 		}
3384 
3385 		/* SNMP items */
3386 
3387 		if (ITEM_TYPE_SNMP == item->type)
3388 		{
3389 			snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &itemid);
3390 			zbx_strpool_release(snmpitem->snmp_oid);
3391 			zbx_hashset_remove_direct(&config->snmpitems, snmpitem);
3392 		}
3393 
3394 		/* IPMI items */
3395 
3396 		if (ITEM_TYPE_IPMI == item->type)
3397 		{
3398 			ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &itemid);
3399 			zbx_strpool_release(ipmiitem->ipmi_sensor);
3400 			zbx_hashset_remove_direct(&config->ipmiitems, ipmiitem);
3401 		}
3402 
3403 		/* trapper items */
3404 
3405 		if (ITEM_TYPE_TRAPPER == item->type &&
3406 				NULL != (trapitem = (ZBX_DC_TRAPITEM *)zbx_hashset_search(&config->trapitems, &itemid)))
3407 		{
3408 			zbx_strpool_release(trapitem->trapper_hosts);
3409 			zbx_hashset_remove_direct(&config->trapitems, trapitem);
3410 		}
3411 
3412 		/* dependent items */
3413 
3414 		if (NULL != (depitem = (ZBX_DC_DEPENDENTITEM *)zbx_hashset_search(&config->dependentitems, &itemid)))
3415 		{
3416 			dc_masteritem_remove_depitem(depitem->master_itemid, itemid);
3417 			zbx_hashset_remove_direct(&config->dependentitems, depitem);
3418 		}
3419 
3420 		/* log items */
3421 
3422 		if (ITEM_VALUE_TYPE_LOG == item->value_type &&
3423 				NULL != (logitem = (ZBX_DC_LOGITEM *)zbx_hashset_search(&config->logitems, &itemid)))
3424 		{
3425 			zbx_strpool_release(logitem->logtimefmt);
3426 			zbx_hashset_remove_direct(&config->logitems, logitem);
3427 		}
3428 
3429 		/* db items */
3430 
3431 		if (ITEM_TYPE_DB_MONITOR == item->type &&
3432 				NULL != (dbitem = (ZBX_DC_DBITEM *)zbx_hashset_search(&config->dbitems, &itemid)))
3433 		{
3434 			zbx_strpool_release(dbitem->params);
3435 			zbx_strpool_release(dbitem->username);
3436 			zbx_strpool_release(dbitem->password);
3437 
3438 			zbx_hashset_remove_direct(&config->dbitems, dbitem);
3439 		}
3440 
3441 		/* SSH items */
3442 
3443 		if (ITEM_TYPE_SSH == item->type)
3444 		{
3445 			sshitem = (ZBX_DC_SSHITEM *)zbx_hashset_search(&config->sshitems, &itemid);
3446 
3447 			zbx_strpool_release(sshitem->username);
3448 			zbx_strpool_release(sshitem->password);
3449 			zbx_strpool_release(sshitem->publickey);
3450 			zbx_strpool_release(sshitem->privatekey);
3451 			zbx_strpool_release(sshitem->params);
3452 
3453 			zbx_hashset_remove_direct(&config->sshitems, sshitem);
3454 		}
3455 
3456 		/* TELNET items */
3457 
3458 		if (ITEM_TYPE_TELNET == item->type)
3459 		{
3460 			telnetitem = (ZBX_DC_TELNETITEM *)zbx_hashset_search(&config->telnetitems, &itemid);
3461 
3462 			zbx_strpool_release(telnetitem->username);
3463 			zbx_strpool_release(telnetitem->password);
3464 			zbx_strpool_release(telnetitem->params);
3465 
3466 			zbx_hashset_remove_direct(&config->telnetitems, telnetitem);
3467 		}
3468 
3469 		/* simple items */
3470 
3471 		if (ITEM_TYPE_SIMPLE == item->type)
3472 		{
3473 			simpleitem = (ZBX_DC_SIMPLEITEM *)zbx_hashset_search(&config->simpleitems, &itemid);
3474 
3475 			zbx_strpool_release(simpleitem->username);
3476 			zbx_strpool_release(simpleitem->password);
3477 
3478 			zbx_hashset_remove_direct(&config->simpleitems, simpleitem);
3479 		}
3480 
3481 		/* JMX items */
3482 
3483 		if (ITEM_TYPE_JMX == item->type)
3484 		{
3485 			jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &itemid);
3486 
3487 			zbx_strpool_release(jmxitem->username);
3488 			zbx_strpool_release(jmxitem->password);
3489 			zbx_strpool_release(jmxitem->jmx_endpoint);
3490 
3491 			zbx_hashset_remove_direct(&config->jmxitems, jmxitem);
3492 		}
3493 
3494 		/* calculated items */
3495 
3496 		if (ITEM_TYPE_CALCULATED == item->type)
3497 		{
3498 			calcitem = (ZBX_DC_CALCITEM *)zbx_hashset_search(&config->calcitems, &itemid);
3499 			zbx_strpool_release(calcitem->params);
3500 
3501 			if (NULL != calcitem->formula_bin)
3502 				__config_mem_free_func((void *)calcitem->formula_bin);
3503 
3504 			zbx_hashset_remove_direct(&config->calcitems, calcitem);
3505 		}
3506 
3507 		/* HTTP agent items */
3508 
3509 		if (ITEM_TYPE_HTTPAGENT == item->type)
3510 		{
3511 			httpitem = (ZBX_DC_HTTPITEM *)zbx_hashset_search(&config->httpitems, &itemid);
3512 
3513 			zbx_strpool_release(httpitem->timeout);
3514 			zbx_strpool_release(httpitem->url);
3515 			zbx_strpool_release(httpitem->query_fields);
3516 			zbx_strpool_release(httpitem->posts);
3517 			zbx_strpool_release(httpitem->status_codes);
3518 			zbx_strpool_release(httpitem->http_proxy);
3519 			zbx_strpool_release(httpitem->headers);
3520 			zbx_strpool_release(httpitem->ssl_cert_file);
3521 			zbx_strpool_release(httpitem->ssl_key_file);
3522 			zbx_strpool_release(httpitem->ssl_key_password);
3523 			zbx_strpool_release(httpitem->username);
3524 			zbx_strpool_release(httpitem->password);
3525 			zbx_strpool_release(httpitem->trapper_hosts);
3526 
3527 			zbx_hashset_remove_direct(&config->httpitems, httpitem);
3528 		}
3529 
3530 		/* Script items */
3531 
3532 		if (ITEM_TYPE_SCRIPT == item->type)
3533 		{
3534 			scriptitem = (ZBX_DC_SCRIPTITEM *)zbx_hashset_search(&config->scriptitems, &itemid);
3535 
3536 			zbx_strpool_release(scriptitem->timeout);
3537 			zbx_strpool_release(scriptitem->script);
3538 
3539 			zbx_vector_ptr_destroy(&scriptitem->params);
3540 			zbx_hashset_remove_direct(&config->scriptitems, scriptitem);
3541 		}
3542 
3543 		/* items */
3544 
3545 		item_hk_local.hostid = item->hostid;
3546 		item_hk_local.key = item->key;
3547 
3548 		if (NULL == (item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk, &item_hk_local)))
3549 		{
3550 			/* item keys should be unique for items within a host, otherwise items with  */
3551 			/* same key share index and removal of last added item already cleared index */
3552 			THIS_SHOULD_NEVER_HAPPEN;
3553 		}
3554 		else if (item == item_hk->item_ptr)
3555 		{
3556 			zbx_strpool_release(item_hk->key);
3557 			zbx_hashset_remove_direct(&config->items_hk, item_hk);
3558 		}
3559 
3560 		if (ZBX_LOC_QUEUE == item->location)
3561 			zbx_binary_heap_remove_direct(&config->queues[item->poller_type], item->itemid);
3562 
3563 		zbx_strpool_release(item->key);
3564 		zbx_strpool_release(item->error);
3565 		zbx_strpool_release(item->delay);
3566 
3567 		if (NULL != item->triggers)
3568 			config->items.mem_free_func(item->triggers);
3569 
3570 		zbx_vector_ptr_destroy(&item->tags);
3571 
3572 		if (NULL != (preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_search(&config->preprocitems, &item->itemid)))
3573 		{
3574 			zbx_vector_ptr_destroy(&preprocitem->preproc_ops);
3575 			zbx_hashset_remove_direct(&config->preprocitems, preprocitem);
3576 		}
3577 
3578 		zbx_hashset_remove_direct(&config->items, item);
3579 	}
3580 
3581 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3582 }
3583 
DCsync_template_items(zbx_dbsync_t * sync)3584 static void	DCsync_template_items(zbx_dbsync_t *sync)
3585 {
3586 	char			**row;
3587 	zbx_uint64_t		rowid, itemid;
3588 	unsigned char		tag;
3589 	int			ret, found;
3590 	ZBX_DC_TEMPLATE_ITEM 	*item;
3591 
3592 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3593 
3594 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3595 	{
3596 		/* removed rows will be always added at the end */
3597 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3598 			break;
3599 
3600 		ZBX_STR2UINT64(itemid, row[0]);
3601 		item = (ZBX_DC_TEMPLATE_ITEM *)DCfind_id(&config->template_items, itemid, sizeof(ZBX_DC_TEMPLATE_ITEM),
3602 				&found);
3603 
3604 		ZBX_STR2UINT64(item->hostid, row[1]);
3605 		ZBX_DBROW2UINT64(item->templateid, row[2]);
3606 	}
3607 
3608 	/* remove deleted template items from buffer */
3609 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3610 	{
3611 		if (NULL == (item = (ZBX_DC_TEMPLATE_ITEM *)zbx_hashset_search(&config->template_items, &rowid)))
3612 			continue;
3613 
3614 		zbx_hashset_remove_direct(&config->template_items, item);
3615 	}
3616 
3617 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3618 }
3619 
DCsync_prototype_items(zbx_dbsync_t * sync)3620 static void	DCsync_prototype_items(zbx_dbsync_t *sync)
3621 {
3622 	char			**row;
3623 	zbx_uint64_t		rowid, itemid;
3624 	unsigned char		tag;
3625 	int			ret, found;
3626 	ZBX_DC_PROTOTYPE_ITEM 	*item;
3627 
3628 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3629 
3630 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3631 	{
3632 		/* removed rows will be always added at the end */
3633 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3634 			break;
3635 
3636 		ZBX_STR2UINT64(itemid, row[0]);
3637 		item = (ZBX_DC_PROTOTYPE_ITEM *)DCfind_id(&config->prototype_items, itemid,
3638 				sizeof(ZBX_DC_PROTOTYPE_ITEM), &found);
3639 
3640 		ZBX_STR2UINT64(item->hostid, row[1]);
3641 		ZBX_DBROW2UINT64(item->templateid, row[2]);
3642 	}
3643 
3644 	/* remove deleted prototype items from buffer */
3645 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3646 	{
3647 		if (NULL == (item = (ZBX_DC_PROTOTYPE_ITEM *)zbx_hashset_search(&config->prototype_items, &rowid)))
3648 			continue;
3649 
3650 		zbx_hashset_remove_direct(&config->prototype_items, item);
3651 	}
3652 
3653 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3654 }
3655 
DCsync_triggers(zbx_dbsync_t * sync)3656 static void	DCsync_triggers(zbx_dbsync_t *sync)
3657 {
3658 	char		**row;
3659 	zbx_uint64_t	rowid;
3660 	unsigned char	tag;
3661 
3662 	ZBX_DC_TRIGGER	*trigger;
3663 
3664 	int		found, ret;
3665 	zbx_uint64_t	triggerid;
3666 
3667 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3668 
3669 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3670 	{
3671 		/* removed rows will be always added at the end */
3672 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3673 			break;
3674 
3675 		ZBX_STR2UINT64(triggerid, row[0]);
3676 
3677 		trigger = (ZBX_DC_TRIGGER *)DCfind_id(&config->triggers, triggerid, sizeof(ZBX_DC_TRIGGER), &found);
3678 
3679 		/* store new information in trigger structure */
3680 
3681 		DCstrpool_replace(found, &trigger->description, row[1]);
3682 		DCstrpool_replace(found, &trigger->expression, row[2]);
3683 		DCstrpool_replace(found, &trigger->recovery_expression, row[11]);
3684 		DCstrpool_replace(found, &trigger->correlation_tag, row[13]);
3685 		DCstrpool_replace(found, &trigger->opdata, row[14]);
3686 		DCstrpool_replace(found, &trigger->event_name, row[15]);
3687 		ZBX_STR2UCHAR(trigger->priority, row[4]);
3688 		ZBX_STR2UCHAR(trigger->type, row[5]);
3689 		ZBX_STR2UCHAR(trigger->status, row[9]);
3690 		ZBX_STR2UCHAR(trigger->recovery_mode, row[10]);
3691 		ZBX_STR2UCHAR(trigger->correlation_mode, row[12]);
3692 
3693 		if (0 == found)
3694 		{
3695 			DCstrpool_replace(found, &trigger->error, row[3]);
3696 			ZBX_STR2UCHAR(trigger->value, row[6]);
3697 			ZBX_STR2UCHAR(trigger->state, row[7]);
3698 			trigger->lastchange = atoi(row[8]);
3699 			trigger->locked = 0;
3700 			trigger->timer_revision = 0;
3701 
3702 			zbx_vector_ptr_create_ext(&trigger->tags, __config_mem_malloc_func, __config_mem_realloc_func,
3703 					__config_mem_free_func);
3704 			trigger->topoindex = 1;
3705 		}
3706 		else
3707 		{
3708 			if (NULL != trigger->expression_bin)
3709 				__config_mem_free_func((void *)trigger->expression_bin);
3710 			if (NULL != trigger->recovery_expression_bin)
3711 				__config_mem_free_func((void *)trigger->recovery_expression_bin);
3712 		}
3713 
3714 		trigger->expression_bin = config_decode_serialized_expression(row[16]);
3715 		trigger->recovery_expression_bin = config_decode_serialized_expression(row[17]);
3716 		trigger->timer = atoi(row[18]);
3717 		trigger->revision = config->sync_start_ts;
3718 	}
3719 
3720 	/* remove deleted triggers from buffer */
3721 	if (SUCCEED == ret)
3722 	{
3723 		zbx_vector_uint64_t	functionids;
3724 		int			i;
3725 		ZBX_DC_ITEM		*item;
3726 		ZBX_DC_FUNCTION		*function;
3727 
3728 		zbx_vector_uint64_create(&functionids);
3729 
3730 		for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3731 		{
3732 			if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &rowid)))
3733 				continue;
3734 
3735 			/* force trigger list update for items used in removed trigger */
3736 
3737 			if (NULL != trigger->expression_bin)
3738 			{
3739 				zbx_get_serialized_expression_functionids(trigger->expression, trigger->expression_bin,
3740 						&functionids);
3741 			}
3742 
3743 			if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode &&
3744 					NULL != trigger->recovery_expression_bin)
3745 			{
3746 				zbx_get_serialized_expression_functionids(trigger->recovery_expression,
3747 						trigger->recovery_expression_bin, &functionids);
3748 			}
3749 
3750 			for (i = 0; i < functionids.values_num; i++)
3751 			{
3752 				if (NULL == (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids.values[i])))
3753 					continue;
3754 
3755 				if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
3756 					continue;
3757 
3758 				item->update_triggers = 1;
3759 				if (NULL != item->triggers)
3760 				{
3761 					config->items.mem_free_func(item->triggers);
3762 					item->triggers = NULL;
3763 				}
3764 			}
3765 			zbx_vector_uint64_clear(&functionids);
3766 
3767 			zbx_strpool_release(trigger->description);
3768 			zbx_strpool_release(trigger->expression);
3769 			zbx_strpool_release(trigger->recovery_expression);
3770 			zbx_strpool_release(trigger->error);
3771 			zbx_strpool_release(trigger->correlation_tag);
3772 			zbx_strpool_release(trigger->opdata);
3773 			zbx_strpool_release(trigger->event_name);
3774 
3775 			zbx_vector_ptr_destroy(&trigger->tags);
3776 
3777 			if (NULL != trigger->expression_bin)
3778 				__config_mem_free_func((void *)trigger->expression_bin);
3779 			if (NULL != trigger->recovery_expression_bin)
3780 				__config_mem_free_func((void *)trigger->recovery_expression_bin);
3781 
3782 			zbx_hashset_remove_direct(&config->triggers, trigger);
3783 		}
3784 		zbx_vector_uint64_destroy(&functionids);
3785 	}
3786 
3787 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3788 }
3789 
3790 static void	DCconfig_sort_triggers_topologically(void);
3791 
3792 /******************************************************************************
3793  *                                                                            *
3794  * Function: dc_trigger_deplist_release                                       *
3795  *                                                                            *
3796  * Purpose: releases trigger dependency list, removing it if necessary        *
3797  *                                                                            *
3798  ******************************************************************************/
dc_trigger_deplist_release(ZBX_DC_TRIGGER_DEPLIST * trigdep)3799 static int	dc_trigger_deplist_release(ZBX_DC_TRIGGER_DEPLIST *trigdep)
3800 {
3801 	if (0 == --trigdep->refcount)
3802 	{
3803 		zbx_vector_ptr_destroy(&trigdep->dependencies);
3804 		zbx_hashset_remove_direct(&config->trigdeps, trigdep);
3805 		return SUCCEED;
3806 	}
3807 
3808 	return FAIL;
3809 }
3810 
3811 /******************************************************************************
3812  *                                                                            *
3813  * Function: dc_trigger_deplist_init                                          *
3814  *                                                                            *
3815  * Purpose: initializes trigger dependency list                               *
3816  *                                                                            *
3817  ******************************************************************************/
dc_trigger_deplist_init(ZBX_DC_TRIGGER_DEPLIST * trigdep,ZBX_DC_TRIGGER * trigger)3818 static void	dc_trigger_deplist_init(ZBX_DC_TRIGGER_DEPLIST *trigdep, ZBX_DC_TRIGGER *trigger)
3819 {
3820 	trigdep->refcount = 1;
3821 	trigdep->trigger = trigger;
3822 	zbx_vector_ptr_create_ext(&trigdep->dependencies, __config_mem_malloc_func, __config_mem_realloc_func,
3823 			__config_mem_free_func);
3824 }
3825 
3826 /******************************************************************************
3827  *                                                                            *
3828  * Function: dc_trigger_deplist_reset                                         *
3829  *                                                                            *
3830  * Purpose: resets trigger dependency list to release memory allocated by     *
3831  *          dependencies vector                                               *
3832  *                                                                            *
3833  ******************************************************************************/
dc_trigger_deplist_reset(ZBX_DC_TRIGGER_DEPLIST * trigdep)3834 static void	dc_trigger_deplist_reset(ZBX_DC_TRIGGER_DEPLIST *trigdep)
3835 {
3836 	zbx_vector_ptr_destroy(&trigdep->dependencies);
3837 	zbx_vector_ptr_create_ext(&trigdep->dependencies, __config_mem_malloc_func, __config_mem_realloc_func,
3838 			__config_mem_free_func);
3839 }
3840 
DCsync_trigdeps(zbx_dbsync_t * sync)3841 static void	DCsync_trigdeps(zbx_dbsync_t *sync)
3842 {
3843 	char			**row;
3844 	zbx_uint64_t		rowid;
3845 	unsigned char		tag;
3846 
3847 	ZBX_DC_TRIGGER_DEPLIST	*trigdep_down, *trigdep_up;
3848 
3849 	int			found, index, ret;
3850 	zbx_uint64_t		triggerid_down, triggerid_up;
3851 	ZBX_DC_TRIGGER		*trigger_up, *trigger_down;
3852 
3853 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3854 
3855 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3856 	{
3857 		/* removed rows will be always added at the end */
3858 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3859 			break;
3860 
3861 		/* find trigdep_down pointer */
3862 
3863 		ZBX_STR2UINT64(triggerid_down, row[0]);
3864 		if (NULL == (trigger_down = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerid_down)))
3865 			continue;
3866 
3867 		ZBX_STR2UINT64(triggerid_up, row[1]);
3868 		if (NULL == (trigger_up = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerid_up)))
3869 			continue;
3870 
3871 		trigdep_down = (ZBX_DC_TRIGGER_DEPLIST *)DCfind_id(&config->trigdeps, triggerid_down, sizeof(ZBX_DC_TRIGGER_DEPLIST), &found);
3872 		if (0 == found)
3873 			dc_trigger_deplist_init(trigdep_down, trigger_down);
3874 		else
3875 			trigdep_down->refcount++;
3876 
3877 		trigdep_up = (ZBX_DC_TRIGGER_DEPLIST *)DCfind_id(&config->trigdeps, triggerid_up, sizeof(ZBX_DC_TRIGGER_DEPLIST), &found);
3878 		if (0 == found)
3879 			dc_trigger_deplist_init(trigdep_up, trigger_up);
3880 		else
3881 			trigdep_up->refcount++;
3882 
3883 		zbx_vector_ptr_append(&trigdep_down->dependencies, trigdep_up);
3884 	}
3885 
3886 	/* remove deleted trigger dependencies from buffer */
3887 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3888 	{
3889 		ZBX_STR2UINT64(triggerid_down, row[0]);
3890 		if (NULL == (trigdep_down = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps,
3891 				&triggerid_down)))
3892 		{
3893 			continue;
3894 		}
3895 
3896 		ZBX_STR2UINT64(triggerid_up, row[1]);
3897 		if (NULL != (trigdep_up = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps,
3898 				&triggerid_up)))
3899 		{
3900 			dc_trigger_deplist_release(trigdep_up);
3901 		}
3902 
3903 		if (SUCCEED != dc_trigger_deplist_release(trigdep_down))
3904 		{
3905 			if (FAIL == (index = zbx_vector_ptr_search(&trigdep_down->dependencies, &triggerid_up,
3906 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
3907 			{
3908 				continue;
3909 			}
3910 
3911 			if (1 == trigdep_down->dependencies.values_num)
3912 				dc_trigger_deplist_reset(trigdep_down);
3913 			else
3914 				zbx_vector_ptr_remove_noorder(&trigdep_down->dependencies, index);
3915 		}
3916 	}
3917 
3918 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3919 }
3920 
3921 #define ZBX_TIMER_DELAY		30
3922 
dc_function_calculate_trends_nextcheck(time_t from,const char * period_shift,zbx_time_unit_t base,time_t * nextcheck,char ** error)3923 static int	dc_function_calculate_trends_nextcheck(time_t from, const char *period_shift, zbx_time_unit_t base,
3924 		time_t *nextcheck, char **error)
3925 {
3926 	time_t		next = from;
3927 	struct tm	tm;
3928 
3929 	localtime_r(&next, &tm);
3930 
3931 	while (SUCCEED == zbx_trends_parse_nextcheck(next, period_shift, nextcheck, error))
3932 	{
3933 		if (*nextcheck > from)
3934 			return SUCCEED;
3935 
3936 		zbx_tm_add(&tm, 1, base);
3937 		if (-1 == (next = mktime(&tm)))
3938 		{
3939 			*error = zbx_strdup(*error, zbx_strerror(errno));
3940 			return FAIL;
3941 		}
3942 	}
3943 
3944 	return FAIL;
3945 }
3946 
dc_function_calculate_nextcheck(const zbx_trigger_timer_t * timer,time_t from,zbx_uint64_t seed)3947 static int	dc_function_calculate_nextcheck(const zbx_trigger_timer_t *timer, time_t from, zbx_uint64_t seed)
3948 {
3949 	if (ZBX_TRIGGER_TIMER_FUNCTION_TIME == timer->type || ZBX_TRIGGER_TIMER_TRIGGER == timer->type)
3950 	{
3951 		int	nextcheck;
3952 
3953 		nextcheck = ZBX_TIMER_DELAY * (int)(from / (time_t)ZBX_TIMER_DELAY) +
3954 				(int)(seed % (zbx_uint64_t)ZBX_TIMER_DELAY);
3955 
3956 		while (nextcheck <= from)
3957 			nextcheck += ZBX_TIMER_DELAY;
3958 
3959 		return nextcheck;
3960 	}
3961 	else if (ZBX_TRIGGER_TIMER_FUNCTION_TREND == timer->type)
3962 	{
3963 		struct tm	tm;
3964 		time_t		nextcheck;
3965 		int		offsets[ZBX_TIME_UNIT_COUNT] = {0, 0, 0, SEC_PER_MIN * 10,
3966 				SEC_PER_HOUR + SEC_PER_MIN * 10, SEC_PER_HOUR + SEC_PER_MIN * 10,
3967 				SEC_PER_HOUR + SEC_PER_MIN * 10, SEC_PER_HOUR + SEC_PER_MIN * 10};
3968 		int		periods[ZBX_TIME_UNIT_COUNT] = {0, 0, 0, SEC_PER_MIN * 10, SEC_PER_HOUR,
3969 				SEC_PER_HOUR * 11, SEC_PER_DAY - SEC_PER_HOUR, SEC_PER_DAY - SEC_PER_HOUR};
3970 
3971 		if (ZBX_TIME_UNIT_HOUR == timer->trend_base)
3972 		{
3973 			localtime_r(&from, &tm);
3974 			zbx_tm_round_up(&tm, timer->trend_base);
3975 
3976 			if (-1 == (nextcheck = mktime(&tm)))
3977 			{
3978 				zabbix_log(LOG_LEVEL_WARNING, "cannot calculate trend function \"" ZBX_FS_UI64
3979 						"\" schedule: %s", timer->objectid, zbx_strerror(errno));
3980 				THIS_SHOULD_NEVER_HAPPEN;
3981 
3982 				return 0;
3983 			}
3984 		}
3985 		else
3986 		{
3987 			int	ret = FAIL;
3988 			char	*error = NULL, *period_shift;
3989 
3990 			if (NULL != (period_shift = strchr(timer->parameter, ':')))
3991 			{
3992 				period_shift++;
3993 				ret = dc_function_calculate_trends_nextcheck(from, period_shift, timer->trend_base,
3994 						&nextcheck, &error);
3995 			}
3996 			else
3997 				error = zbx_dsprintf(NULL, "invalid first parameter");
3998 
3999 			if (FAIL == ret)
4000 			{
4001 				zabbix_log(LOG_LEVEL_WARNING, "cannot calculate trend function \"" ZBX_FS_UI64
4002 						"\" schedule: %s", timer->objectid, error);
4003 				zbx_free(error);
4004 
4005 				return 0;
4006 			}
4007 		}
4008 
4009 		return nextcheck + offsets[timer->trend_base] + seed % periods[timer->trend_base];
4010 	}
4011 
4012 	THIS_SHOULD_NEVER_HAPPEN;
4013 
4014 	return 0;
4015 }
4016 
4017 /******************************************************************************
4018  *                                                                            *
4019  * Function: dc_trigger_function_timer_create                                 *
4020  *                                                                            *
4021  * Purpose: create trigger timer based on the trend function                  *
4022  *                                                                            *
4023  * Return value:  Created timer or NULL in the case of error.                 *
4024  *                                                                            *
4025  ******************************************************************************/
dc_trigger_function_timer_create(ZBX_DC_FUNCTION * function)4026 static zbx_trigger_timer_t	*dc_trigger_function_timer_create(ZBX_DC_FUNCTION *function)
4027 {
4028 	zbx_trigger_timer_t	*timer;
4029 	zbx_time_unit_t		trend_base;
4030 	zbx_uint32_t		type;
4031 
4032 	if (ZBX_FUNCTION_TYPE_TRENDS == function->type)
4033 	{
4034 		char	*error = NULL;
4035 
4036 		if (FAIL == zbx_trends_parse_base(function->parameter, &trend_base, &error))
4037 		{
4038 			zabbix_log(LOG_LEVEL_WARNING, "cannot parse function " ZBX_FS_UI64 " period base: %s",
4039 					function->functionid, error);
4040 			zbx_free(error);
4041 			return NULL;
4042 		}
4043 		type = ZBX_TRIGGER_TIMER_FUNCTION_TREND;
4044 	}
4045 	else
4046 	{
4047 		trend_base = ZBX_TIME_UNIT_UNKNOWN;
4048 		type = ZBX_TRIGGER_TIMER_FUNCTION_TIME;
4049 	}
4050 
4051 	timer = (zbx_trigger_timer_t *)__config_mem_malloc_func(NULL, sizeof(zbx_trigger_timer_t));
4052 
4053 	timer->objectid = function->functionid;
4054 	timer->triggerid = function->triggerid;
4055 	timer->revision = function->revision;
4056 	timer->trend_base = trend_base;
4057 	timer->lock = 0;
4058 	timer->type = type;
4059 
4060 	function->timer_revision = function->revision;
4061 
4062 	if (ZBX_FUNCTION_TYPE_TRENDS == function->type)
4063 		DCstrpool_replace(0, &timer->parameter, function->parameter);
4064 	else
4065 		timer->parameter = NULL;
4066 
4067 	return timer;
4068 }
4069 
4070 /******************************************************************************
4071  *                                                                            *
4072  * Function: dc_trigger_timer_create                                          *
4073  *                                                                            *
4074  * Purpose: create trigger timer based on the specified trigger               *
4075  *                                                                            *
4076  * Return value:  Created timer or NULL in the case of error.                 *
4077  *                                                                            *
4078  ******************************************************************************/
dc_trigger_timer_create(ZBX_DC_TRIGGER * trigger)4079 static zbx_trigger_timer_t	*dc_trigger_timer_create(ZBX_DC_TRIGGER *trigger)
4080 {
4081 	zbx_trigger_timer_t	*timer;
4082 
4083 	timer = (zbx_trigger_timer_t *)__config_mem_malloc_func(NULL, sizeof(zbx_trigger_timer_t));
4084 	timer->type = ZBX_TRIGGER_TIMER_TRIGGER;
4085 	timer->objectid = trigger->triggerid;
4086 	timer->triggerid = trigger->triggerid;
4087 	timer->revision = trigger->revision;
4088 	timer->trend_base = ZBX_TIME_UNIT_UNKNOWN;
4089 	timer->lock = 0;
4090 	timer->parameter = NULL;
4091 
4092 	trigger->timer_revision = trigger->revision;
4093 
4094 	return timer;
4095 }
4096 
4097 /******************************************************************************
4098  *                                                                            *
4099  * Function: dc_trigger_timer_free                                            *
4100  *                                                                            *
4101  * Purpose: free trigger timer                                                *
4102  *                                                                            *
4103  ******************************************************************************/
dc_trigger_timer_free(zbx_trigger_timer_t * timer)4104 static void	dc_trigger_timer_free(zbx_trigger_timer_t *timer)
4105 {
4106 	if (NULL != timer->parameter)
4107 		zbx_strpool_release(timer->parameter);
4108 
4109 	__config_mem_free_func(timer);
4110 }
4111 
4112 /******************************************************************************
4113  *                                                                            *
4114  * Function: dc_schedule_trigger_timer                                        *
4115  *                                                                            *
4116  * Purpose: schedule trigger timer to be executed at the specified time       *
4117  *                                                                            *
4118  * Parameter: timer   - [IN] the timer to schedule                            *
4119  *            eval_ts - [IN] the history snapshot time, by default (NULL)     *
4120  *                           execution time will be used.                     *
4121  *            exec_ts - [IN] the tiemer execution time                        *
4122  *                                                                            *
4123  ******************************************************************************/
dc_schedule_trigger_timer(zbx_trigger_timer_t * timer,const zbx_timespec_t * eval_ts,const zbx_timespec_t * exec_ts)4124 static void	dc_schedule_trigger_timer(zbx_trigger_timer_t *timer, const zbx_timespec_t *eval_ts,
4125 		const zbx_timespec_t *exec_ts)
4126 {
4127 	zbx_binary_heap_elem_t	elem;
4128 
4129 	if (NULL == eval_ts)
4130 		timer->eval_ts = *exec_ts;
4131 	else
4132 		timer->eval_ts = *eval_ts;
4133 
4134 	timer->exec_ts = *exec_ts;
4135 
4136 	elem.key = 0;
4137 	elem.data = (void *)timer;
4138 	zbx_binary_heap_insert(&config->trigger_queue, &elem);
4139 }
4140 
4141 /******************************************************************************
4142  *                                                                            *
4143  * Function: dc_schedule_new_trigger_timers                                   *
4144  *                                                                            *
4145  * Purpose: set timer schedule and evaluation times based on functions and    *
4146  *          old trend function queue                                          *
4147  *                                                                            *
4148  ******************************************************************************/
dc_schedule_trigger_timers(zbx_hashset_t * trend_queue,int now)4149 static void	dc_schedule_trigger_timers(zbx_hashset_t *trend_queue, int now)
4150 {
4151 	ZBX_DC_FUNCTION		*function;
4152 	ZBX_DC_TRIGGER		*trigger;
4153 	zbx_trigger_timer_t	*timer, *old;
4154 	zbx_timespec_t		ts;
4155 	zbx_hashset_iter_t	iter;
4156 
4157 	ts.ns = 0;
4158 
4159 	zbx_hashset_iter_reset(&config->functions, &iter);
4160 	while (NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_iter_next(&iter)))
4161 	{
4162 		if (ZBX_FUNCTION_TYPE_TIMER != function->type && ZBX_FUNCTION_TYPE_TRENDS != function->type)
4163 			continue;
4164 
4165 		if (function->timer_revision == function->revision)
4166 			continue;
4167 
4168 		if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &function->triggerid)))
4169 			continue;
4170 
4171 		if (TRIGGER_STATUS_ENABLED != trigger->status || TRIGGER_FUNCTIONAL_TRUE != trigger->functional)
4172 			continue;
4173 
4174 		if (NULL == (timer = dc_trigger_function_timer_create(function)))
4175 			continue;
4176 
4177 		if (NULL != trend_queue && NULL != (old = (zbx_trigger_timer_t *)zbx_hashset_search(trend_queue,
4178 				&timer->objectid)) && old->eval_ts.sec < now + 10 * SEC_PER_MIN)
4179 		{
4180 			/* if the trigger was scheduled during next 10 minutes         */
4181 			/* schedule its evaluation later to reduce server startup load */
4182 			if (old->eval_ts.sec < now + 10 * SEC_PER_MIN)
4183 				ts.sec = now + 10 * SEC_PER_MIN + timer->triggerid % (10 * SEC_PER_MIN);
4184 			else
4185 				ts.sec = old->eval_ts.sec;
4186 
4187 			dc_schedule_trigger_timer(timer, &old->eval_ts, &ts);
4188 		}
4189 		else
4190 		{
4191 			if (0 == (ts.sec = dc_function_calculate_nextcheck(timer, now, timer->triggerid)))
4192 			{
4193 				dc_trigger_timer_free(timer);
4194 				function->timer_revision = 0;
4195 			}
4196 			else
4197 				dc_schedule_trigger_timer(timer, NULL, &ts);
4198 		}
4199 	}
4200 
4201 	zbx_hashset_iter_reset(&config->triggers, &iter);
4202 	while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
4203 	{
4204 		if (ZBX_TRIGGER_TIMER_DEFAULT == trigger->timer)
4205 			continue;
4206 
4207 		if (trigger->timer_revision == trigger->revision)
4208 			continue;
4209 
4210 		if (NULL == (timer = dc_trigger_timer_create(trigger)))
4211 			continue;
4212 
4213 		if (0 == (ts.sec = dc_function_calculate_nextcheck(timer, now, timer->triggerid)))
4214 		{
4215 			dc_trigger_timer_free(timer);
4216 			trigger->timer_revision = 0;
4217 		}
4218 		else
4219 			dc_schedule_trigger_timer(timer, NULL, &ts);
4220 
4221 	}
4222 }
4223 
DCsync_functions(zbx_dbsync_t * sync)4224 static void	DCsync_functions(zbx_dbsync_t *sync)
4225 {
4226 	char		**row;
4227 	zbx_uint64_t	rowid;
4228 	unsigned char	tag;
4229 
4230 	ZBX_DC_ITEM	*item;
4231 	ZBX_DC_FUNCTION	*function;
4232 
4233 	int		found, ret;
4234 	zbx_uint64_t	itemid, functionid, triggerid;
4235 
4236 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4237 
4238 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4239 	{
4240 		/* removed rows will be always added at the end */
4241 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4242 			break;
4243 
4244 		ZBX_STR2UINT64(itemid, row[0]);
4245 		ZBX_STR2UINT64(functionid, row[1]);
4246 		ZBX_STR2UINT64(triggerid, row[4]);
4247 
4248 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
4249 		{
4250 			/* Item could have been created after we have selected them in the             */
4251 			/* previous queries. However, we shall avoid the check for functions being the */
4252 			/* same as in the trigger expression, because that is somewhat expensive, not  */
4253 			/* 100% (think functions keeping their functionid, but changing their function */
4254 			/* or parameters), and even if there is an inconsistency, we can live with it. */
4255 
4256 			continue;
4257 		}
4258 
4259 		/* process function information */
4260 
4261 		function = (ZBX_DC_FUNCTION *)DCfind_id(&config->functions, functionid, sizeof(ZBX_DC_FUNCTION), &found);
4262 
4263 		if (1 == found)
4264 		{
4265 			if (function->itemid != itemid)
4266 			{
4267 				ZBX_DC_ITEM	*item_last;
4268 
4269 				if (NULL != (item_last = zbx_hashset_search(&config->items, &function->itemid)))
4270 				{
4271 					item_last->update_triggers = 1;
4272 					if (NULL != item_last->triggers)
4273 					{
4274 						config->items.mem_free_func(item_last->triggers);
4275 						item_last->triggers = NULL;
4276 					}
4277 				}
4278 			}
4279 		}
4280 		else
4281 			function->timer_revision = 0;
4282 
4283 		function->triggerid = triggerid;
4284 		function->itemid = itemid;
4285 		DCstrpool_replace(found, &function->function, row[2]);
4286 		DCstrpool_replace(found, &function->parameter, row[3]);
4287 
4288 		function->type = zbx_get_function_type(function->function);
4289 		function->revision = config->sync_start_ts;
4290 
4291 		item->update_triggers = 1;
4292 		if (NULL != item->triggers)
4293 			item->triggers[0] = NULL;
4294 	}
4295 
4296 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4297 	{
4298 		if (NULL == (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &rowid)))
4299 			continue;
4300 
4301 		if (NULL != (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
4302 		{
4303 			item->update_triggers = 1;
4304 			if (NULL != item->triggers)
4305 			{
4306 				config->items.mem_free_func(item->triggers);
4307 				item->triggers = NULL;
4308 			}
4309 		}
4310 
4311 		zbx_strpool_release(function->function);
4312 		zbx_strpool_release(function->parameter);
4313 
4314 		zbx_hashset_remove_direct(&config->functions, function);
4315 	}
4316 
4317 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4318 }
4319 
4320 /******************************************************************************
4321  *                                                                            *
4322  * Function: dc_regexp_remove_expression                                      *
4323  *                                                                            *
4324  * Purpose: removes expression from regexp                                    *
4325  *                                                                            *
4326  ******************************************************************************/
dc_regexp_remove_expression(const char * regexp_name,zbx_uint64_t expressionid)4327 static ZBX_DC_REGEXP	*dc_regexp_remove_expression(const char *regexp_name, zbx_uint64_t expressionid)
4328 {
4329 	ZBX_DC_REGEXP	*regexp, regexp_local;
4330 	int		index;
4331 
4332 	regexp_local.name = regexp_name;
4333 
4334 	if (NULL == (regexp = (ZBX_DC_REGEXP *)zbx_hashset_search(&config->regexps, &regexp_local)))
4335 		return NULL;
4336 
4337 	if (FAIL == (index = zbx_vector_uint64_search(&regexp->expressionids, expressionid,
4338 			ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
4339 	{
4340 		return NULL;
4341 	}
4342 
4343 	zbx_vector_uint64_remove_noorder(&regexp->expressionids, index);
4344 
4345 	return regexp;
4346 }
4347 
4348 /******************************************************************************
4349  *                                                                            *
4350  * Function: DCsync_expressions                                               *
4351  *                                                                            *
4352  * Purpose: Updates expressions configuration cache                           *
4353  *                                                                            *
4354  * Parameters: result - [IN] the result of expressions database select        *
4355  *                                                                            *
4356  ******************************************************************************/
DCsync_expressions(zbx_dbsync_t * sync)4357 static void	DCsync_expressions(zbx_dbsync_t *sync)
4358 {
4359 	char			**row;
4360 	zbx_uint64_t		rowid;
4361 	unsigned char		tag;
4362 	zbx_hashset_iter_t	iter;
4363 	ZBX_DC_EXPRESSION	*expression;
4364 	ZBX_DC_REGEXP		*regexp, regexp_local;
4365 	zbx_uint64_t		expressionid;
4366 	int			found, ret;
4367 
4368 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4369 
4370 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4371 	{
4372 		/* removed rows will be always added at the end */
4373 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4374 			break;
4375 
4376 		ZBX_STR2UINT64(expressionid, row[1]);
4377 		expression = (ZBX_DC_EXPRESSION *)DCfind_id(&config->expressions, expressionid, sizeof(ZBX_DC_EXPRESSION), &found);
4378 
4379 		if (0 != found)
4380 			dc_regexp_remove_expression(expression->regexp, expressionid);
4381 
4382 		DCstrpool_replace(found, &expression->regexp, row[0]);
4383 		DCstrpool_replace(found, &expression->expression, row[2]);
4384 		ZBX_STR2UCHAR(expression->type, row[3]);
4385 		ZBX_STR2UCHAR(expression->case_sensitive, row[5]);
4386 		expression->delimiter = *row[4];
4387 
4388 		regexp_local.name = row[0];
4389 
4390 		if (NULL == (regexp = (ZBX_DC_REGEXP *)zbx_hashset_search(&config->regexps, &regexp_local)))
4391 		{
4392 			DCstrpool_replace(0, &regexp_local.name, row[0]);
4393 			zbx_vector_uint64_create_ext(&regexp_local.expressionids,
4394 					__config_mem_malloc_func,
4395 					__config_mem_realloc_func,
4396 					__config_mem_free_func);
4397 
4398 			regexp = (ZBX_DC_REGEXP *)zbx_hashset_insert(&config->regexps, &regexp_local, sizeof(ZBX_DC_REGEXP));
4399 		}
4400 
4401 		zbx_vector_uint64_append(&regexp->expressionids, expressionid);
4402 	}
4403 
4404 	/* remove regexps with no expressions related to it */
4405 	zbx_hashset_iter_reset(&config->regexps, &iter);
4406 
4407 	while (NULL != (regexp = (ZBX_DC_REGEXP *)zbx_hashset_iter_next(&iter)))
4408 	{
4409 		if (0 < regexp->expressionids.values_num)
4410 			continue;
4411 
4412 		zbx_strpool_release(regexp->name);
4413 		zbx_vector_uint64_destroy(&regexp->expressionids);
4414 		zbx_hashset_iter_remove(&iter);
4415 	}
4416 
4417 	/* remove unused expressions */
4418 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4419 	{
4420 		if (NULL == (expression = (ZBX_DC_EXPRESSION *)zbx_hashset_search(&config->expressions, &rowid)))
4421 			continue;
4422 
4423 		if (NULL != (regexp = dc_regexp_remove_expression(expression->regexp, expression->expressionid)))
4424 		{
4425 			if (0 == regexp->expressionids.values_num)
4426 			{
4427 				zbx_strpool_release(regexp->name);
4428 				zbx_vector_uint64_destroy(&regexp->expressionids);
4429 				zbx_hashset_remove_direct(&config->regexps, regexp);
4430 			}
4431 		}
4432 
4433 		zbx_strpool_release(expression->expression);
4434 		zbx_strpool_release(expression->regexp);
4435 		zbx_hashset_remove_direct(&config->expressions, expression);
4436 	}
4437 
4438 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4439 }
4440 
4441 /******************************************************************************
4442  *                                                                            *
4443  * Function: DCsync_actions                                                   *
4444  *                                                                            *
4445  * Purpose: Updates actions configuration cache                               *
4446  *                                                                            *
4447  * Parameters: sync - [IN] the db synchronization data                        *
4448  *                                                                            *
4449  * Comments: The result contains the following fields:                        *
4450  *           0 - actionid                                                     *
4451  *           1 - eventsource                                                  *
4452  *           2 - evaltype                                                     *
4453  *           3 - formula                                                      *
4454  *                                                                            *
4455  ******************************************************************************/
DCsync_actions(zbx_dbsync_t * sync)4456 static void	DCsync_actions(zbx_dbsync_t *sync)
4457 {
4458 	char		**row;
4459 	zbx_uint64_t	rowid;
4460 	unsigned char	tag;
4461 	zbx_uint64_t	actionid;
4462 	zbx_dc_action_t	*action;
4463 	int		found, ret;
4464 
4465 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4466 
4467 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4468 	{
4469 		/* removed rows will be always added at the end */
4470 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4471 			break;
4472 
4473 		ZBX_STR2UINT64(actionid, row[0]);
4474 		action = (zbx_dc_action_t *)DCfind_id(&config->actions, actionid, sizeof(zbx_dc_action_t), &found);
4475 
4476 		ZBX_STR2UCHAR(action->eventsource, row[1]);
4477 		ZBX_STR2UCHAR(action->evaltype, row[2]);
4478 
4479 		DCstrpool_replace(found, &action->formula, row[3]);
4480 
4481 		if (0 == found)
4482 		{
4483 			if (EVENT_SOURCE_INTERNAL == action->eventsource)
4484 				config->internal_actions++;
4485 
4486 			zbx_vector_ptr_create_ext(&action->conditions, __config_mem_malloc_func,
4487 					__config_mem_realloc_func, __config_mem_free_func);
4488 
4489 			zbx_vector_ptr_reserve(&action->conditions, 1);
4490 
4491 			action->opflags = ZBX_ACTION_OPCLASS_NONE;
4492 		}
4493 	}
4494 
4495 	/* remove deleted actions */
4496 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4497 	{
4498 		if (NULL == (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &rowid)))
4499 			continue;
4500 
4501 		if (EVENT_SOURCE_INTERNAL == action->eventsource)
4502 			config->internal_actions--;
4503 
4504 		zbx_strpool_release(action->formula);
4505 		zbx_vector_ptr_destroy(&action->conditions);
4506 
4507 		zbx_hashset_remove_direct(&config->actions, action);
4508 	}
4509 
4510 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4511 }
4512 
4513 /******************************************************************************
4514  *                                                                            *
4515  * Function: DCsync_action_ops                                                *
4516  *                                                                            *
4517  * Purpose: Updates action operation class flags in configuration cache       *
4518  *                                                                            *
4519  * Parameters: sync - [IN] the db synchronization data                        *
4520  *                                                                            *
4521  * Comments: The result contains the following fields:                        *
4522  *           0 - actionid                                                     *
4523  *           1 - action operation class flags                                 *
4524  *                                                                            *
4525  ******************************************************************************/
DCsync_action_ops(zbx_dbsync_t * sync)4526 static void	DCsync_action_ops(zbx_dbsync_t *sync)
4527 {
4528 	char		**row;
4529 	zbx_uint64_t	rowid;
4530 	unsigned char	tag;
4531 	zbx_uint64_t	actionid;
4532 	zbx_dc_action_t	*action;
4533 
4534 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4535 
4536 	while (SUCCEED == zbx_dbsync_next(sync, &rowid, &row, &tag))
4537 	{
4538 		ZBX_STR2UINT64(actionid, row[0]);
4539 
4540 		if (NULL == (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &actionid)))
4541 			continue;
4542 
4543 		action->opflags = atoi(row[1]);
4544 	}
4545 
4546 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4547 }
4548 
4549 /******************************************************************************
4550  *                                                                            *
4551  * Function: dc_compare_action_conditions_by_type                             *
4552  *                                                                            *
4553  * Purpose: compare two action conditions by their type                       *
4554  *                                                                            *
4555  * Comments: This function is used to sort action conditions by type.         *
4556  *                                                                            *
4557  ******************************************************************************/
dc_compare_action_conditions_by_type(const void * d1,const void * d2)4558 static int	dc_compare_action_conditions_by_type(const void *d1, const void *d2)
4559 {
4560 	zbx_dc_action_condition_t	*c1 = *(zbx_dc_action_condition_t **)d1;
4561 	zbx_dc_action_condition_t	*c2 = *(zbx_dc_action_condition_t **)d2;
4562 
4563 	ZBX_RETURN_IF_NOT_EQUAL(c1->conditiontype, c2->conditiontype);
4564 
4565 	return 0;
4566 }
4567 
4568 /******************************************************************************
4569  *                                                                            *
4570  * Function: DCsync_action_conditions                                         *
4571  *                                                                            *
4572  * Purpose: Updates action conditions configuration cache                     *
4573  *                                                                            *
4574  * Parameters: sync - [IN] the db synchronization data                        *
4575  *                                                                            *
4576  * Comments: The result contains the following fields:                        *
4577  *           0 - conditionid                                                  *
4578  *           1 - actionid                                                     *
4579  *           2 - conditiontype                                                *
4580  *           3 - operator                                                     *
4581  *           4 - value                                                        *
4582  *                                                                            *
4583  ******************************************************************************/
DCsync_action_conditions(zbx_dbsync_t * sync)4584 static void	DCsync_action_conditions(zbx_dbsync_t *sync)
4585 {
4586 	char				**row;
4587 	zbx_uint64_t			rowid;
4588 	unsigned char			tag;
4589 	zbx_uint64_t			actionid, conditionid;
4590 	zbx_dc_action_t			*action;
4591 	zbx_dc_action_condition_t	*condition;
4592 	int				found, i, index, ret;
4593 	zbx_vector_ptr_t		actions;
4594 
4595 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4596 
4597 	zbx_vector_ptr_create(&actions);
4598 
4599 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4600 	{
4601 		/* removed rows will be always added at the end */
4602 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4603 			break;
4604 
4605 		ZBX_STR2UINT64(actionid, row[1]);
4606 
4607 		if (NULL == (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &actionid)))
4608 			continue;
4609 
4610 		ZBX_STR2UINT64(conditionid, row[0]);
4611 
4612 		condition = (zbx_dc_action_condition_t *)DCfind_id(&config->action_conditions, conditionid, sizeof(zbx_dc_action_condition_t),
4613 				&found);
4614 
4615 		ZBX_STR2UCHAR(condition->conditiontype, row[2]);
4616 		ZBX_STR2UCHAR(condition->op, row[3]);
4617 
4618 		DCstrpool_replace(found, &condition->value, row[4]);
4619 		DCstrpool_replace(found, &condition->value2, row[5]);
4620 
4621 		if (0 == found)
4622 		{
4623 			condition->actionid = actionid;
4624 			zbx_vector_ptr_append(&action->conditions, condition);
4625 		}
4626 
4627 		if (CONDITION_EVAL_TYPE_AND_OR == action->evaltype)
4628 			zbx_vector_ptr_append(&actions, action);
4629 	}
4630 
4631 	/* remove deleted conditions */
4632 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4633 	{
4634 		if (NULL == (condition = (zbx_dc_action_condition_t *)zbx_hashset_search(&config->action_conditions, &rowid)))
4635 			continue;
4636 
4637 		if (NULL != (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &condition->actionid)))
4638 		{
4639 			if (FAIL != (index = zbx_vector_ptr_search(&action->conditions, condition,
4640 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4641 			{
4642 				zbx_vector_ptr_remove_noorder(&action->conditions, index);
4643 
4644 				if (CONDITION_EVAL_TYPE_AND_OR == action->evaltype)
4645 					zbx_vector_ptr_append(&actions, action);
4646 			}
4647 		}
4648 
4649 		zbx_strpool_release(condition->value);
4650 		zbx_strpool_release(condition->value2);
4651 
4652 		zbx_hashset_remove_direct(&config->action_conditions, condition);
4653 	}
4654 
4655 	/* sort conditions by type */
4656 
4657 	zbx_vector_ptr_sort(&actions, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4658 	zbx_vector_ptr_uniq(&actions, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4659 
4660 	for (i = 0; i < actions.values_num; i++)
4661 	{
4662 		action = (zbx_dc_action_t *)actions.values[i];
4663 
4664 		if (CONDITION_EVAL_TYPE_AND_OR == action->evaltype)
4665 			zbx_vector_ptr_sort(&action->conditions, dc_compare_action_conditions_by_type);
4666 	}
4667 
4668 	zbx_vector_ptr_destroy(&actions);
4669 
4670 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4671 }
4672 
4673 /******************************************************************************
4674  *                                                                            *
4675  * Function: DCsync_correlations                                              *
4676  *                                                                            *
4677  * Purpose: Updates correlations configuration cache                          *
4678  *                                                                            *
4679  * Parameters: sync - [IN] the db synchronization data                        *
4680  *                                                                            *
4681  * Comments: The result contains the following fields:                        *
4682  *           0 - correlationid                                                *
4683  *           1 - name                                                         *
4684  *           2 - evaltype                                                     *
4685  *           3 - formula                                                      *
4686  *                                                                            *
4687  ******************************************************************************/
DCsync_correlations(zbx_dbsync_t * sync)4688 static void	DCsync_correlations(zbx_dbsync_t *sync)
4689 {
4690 	char			**row;
4691 	zbx_uint64_t		rowid;
4692 	unsigned char		tag;
4693 	zbx_uint64_t		correlationid;
4694 	zbx_dc_correlation_t	*correlation;
4695 	int			found, ret;
4696 
4697 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4698 
4699 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4700 	{
4701 		/* removed rows will be always added at the end */
4702 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4703 			break;
4704 
4705 		ZBX_STR2UINT64(correlationid, row[0]);
4706 
4707 		correlation = (zbx_dc_correlation_t *)DCfind_id(&config->correlations, correlationid, sizeof(zbx_dc_correlation_t), &found);
4708 
4709 		if (0 == found)
4710 		{
4711 			zbx_vector_ptr_create_ext(&correlation->conditions, __config_mem_malloc_func,
4712 					__config_mem_realloc_func, __config_mem_free_func);
4713 
4714 			zbx_vector_ptr_create_ext(&correlation->operations, __config_mem_malloc_func,
4715 					__config_mem_realloc_func, __config_mem_free_func);
4716 		}
4717 
4718 		DCstrpool_replace(found, &correlation->name, row[1]);
4719 		DCstrpool_replace(found, &correlation->formula, row[3]);
4720 
4721 		ZBX_STR2UCHAR(correlation->evaltype, row[2]);
4722 	}
4723 
4724 	/* remove deleted correlations */
4725 
4726 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4727 	{
4728 		if (NULL == (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &rowid)))
4729 			continue;
4730 
4731 		zbx_strpool_release(correlation->name);
4732 		zbx_strpool_release(correlation->formula);
4733 
4734 		zbx_vector_ptr_destroy(&correlation->conditions);
4735 		zbx_vector_ptr_destroy(&correlation->operations);
4736 
4737 		zbx_hashset_remove_direct(&config->correlations, correlation);
4738 	}
4739 
4740 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4741 }
4742 
4743 /******************************************************************************
4744  *                                                                            *
4745  * Function: dc_corr_condition_get_size                                       *
4746  *                                                                            *
4747  * Purpose: get the actual size of correlation condition data depending on    *
4748  *          its type                                                          *
4749  *                                                                            *
4750  * Parameters: type - [IN] the condition type                                 *
4751  *                                                                            *
4752  * Return value: the size                                                     *
4753  *                                                                            *
4754  ******************************************************************************/
dc_corr_condition_get_size(unsigned char type)4755 static size_t	dc_corr_condition_get_size(unsigned char type)
4756 {
4757 	switch (type)
4758 	{
4759 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
4760 			/* break; is not missing here */
4761 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
4762 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_tag_t);
4763 		case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP:
4764 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_group_t);
4765 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
4766 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_tag_pair_t);
4767 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
4768 			/* break; is not missing here */
4769 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
4770 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_tag_value_t);
4771 	}
4772 
4773 	THIS_SHOULD_NEVER_HAPPEN;
4774 	return 0;
4775 }
4776 
4777 /******************************************************************************
4778  *                                                                            *
4779  * Function: dc_corr_condition_init_data                                      *
4780  *                                                                            *
4781  * Purpose: initializes correlation condition data from database row          *
4782  *                                                                            *
4783  * Parameters: condition - [IN] the condition to initialize                   *
4784  *             found     - [IN] 0 - new condition, 1 - cached condition       *
4785  *             row       - [IN] the database row containing condition data    *
4786  *                                                                            *
4787  ******************************************************************************/
dc_corr_condition_init_data(zbx_dc_corr_condition_t * condition,int found,DB_ROW row)4788 static void	dc_corr_condition_init_data(zbx_dc_corr_condition_t *condition, int found,  DB_ROW row)
4789 {
4790 	if (ZBX_CORR_CONDITION_OLD_EVENT_TAG == condition->type || ZBX_CORR_CONDITION_NEW_EVENT_TAG == condition->type)
4791 	{
4792 		DCstrpool_replace(found, &condition->data.tag.tag, row[0]);
4793 		return;
4794 	}
4795 
4796 	row++;
4797 
4798 	if (ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE == condition->type ||
4799 			ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE == condition->type)
4800 	{
4801 		DCstrpool_replace(found, &condition->data.tag_value.tag, row[0]);
4802 		DCstrpool_replace(found, &condition->data.tag_value.value, row[1]);
4803 		ZBX_STR2UCHAR(condition->data.tag_value.op, row[2]);
4804 		return;
4805 	}
4806 
4807 	row += 3;
4808 
4809 	if (ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP == condition->type)
4810 	{
4811 		ZBX_STR2UINT64(condition->data.group.groupid, row[0]);
4812 		ZBX_STR2UCHAR(condition->data.group.op, row[1]);
4813 		return;
4814 	}
4815 
4816 	row += 2;
4817 
4818 	if (ZBX_CORR_CONDITION_EVENT_TAG_PAIR == condition->type)
4819 	{
4820 		DCstrpool_replace(found, &condition->data.tag_pair.oldtag, row[0]);
4821 		DCstrpool_replace(found, &condition->data.tag_pair.newtag, row[1]);
4822 		return;
4823 	}
4824 }
4825 
4826 /******************************************************************************
4827  *                                                                            *
4828  * Function: corr_condition_free_data                                         *
4829  *                                                                            *
4830  * Purpose: frees correlation condition data                                  *
4831  *                                                                            *
4832  * Parameters: condition - [IN] the condition                                 *
4833  *                                                                            *
4834  ******************************************************************************/
corr_condition_free_data(zbx_dc_corr_condition_t * condition)4835 static void	corr_condition_free_data(zbx_dc_corr_condition_t *condition)
4836 {
4837 	switch (condition->type)
4838 	{
4839 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
4840 			/* break; is not missing here */
4841 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
4842 			zbx_strpool_release(condition->data.tag.tag);
4843 			break;
4844 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
4845 			zbx_strpool_release(condition->data.tag_pair.oldtag);
4846 			zbx_strpool_release(condition->data.tag_pair.newtag);
4847 			break;
4848 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
4849 			/* break; is not missing here */
4850 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
4851 			zbx_strpool_release(condition->data.tag_value.tag);
4852 			zbx_strpool_release(condition->data.tag_value.value);
4853 			break;
4854 	}
4855 }
4856 
4857 /******************************************************************************
4858  *                                                                            *
4859  * Function: dc_compare_corr_conditions_by_type                               *
4860  *                                                                            *
4861  * Purpose: compare two correlation conditions by their type                  *
4862  *                                                                            *
4863  * Comments: This function is used to sort correlation conditions by type.    *
4864  *                                                                            *
4865  ******************************************************************************/
dc_compare_corr_conditions_by_type(const void * d1,const void * d2)4866 static int	dc_compare_corr_conditions_by_type(const void *d1, const void *d2)
4867 {
4868 	zbx_dc_corr_condition_t	*c1 = *(zbx_dc_corr_condition_t **)d1;
4869 	zbx_dc_corr_condition_t	*c2 = *(zbx_dc_corr_condition_t **)d2;
4870 
4871 	ZBX_RETURN_IF_NOT_EQUAL(c1->type, c2->type);
4872 
4873 	return 0;
4874 }
4875 
4876 /******************************************************************************
4877  *                                                                            *
4878  * Function: DCsync_corr_conditions                                           *
4879  *                                                                            *
4880  * Purpose: Updates correlation conditions configuration cache                *
4881  *                                                                            *
4882  * Parameters: sync - [IN] the db synchronization data                        *
4883  *                                                                            *
4884  * Comments: The result contains the following fields:                        *
4885  *           0 - corr_conditionid                                             *
4886  *           1 - correlationid                                                *
4887  *           2 - type                                                         *
4888  *           3 - corr_condition_tag.tag                                       *
4889  *           4 - corr_condition_tagvalue.tag                                  *
4890  *           5 - corr_condition_tagvalue.value                                *
4891  *           6 - corr_condition_tagvalue.operator                             *
4892  *           7 - corr_condition_group.groupid                                 *
4893  *           8 - corr_condition_group.operator                                *
4894  *           9 - corr_condition_tagpair.oldtag                                *
4895  *          10 - corr_condition_tagpair.newtag                                *
4896  *                                                                            *
4897  ******************************************************************************/
DCsync_corr_conditions(zbx_dbsync_t * sync)4898 static void	DCsync_corr_conditions(zbx_dbsync_t *sync)
4899 {
4900 	char			**row;
4901 	zbx_uint64_t		rowid;
4902 	unsigned char		tag;
4903 	zbx_uint64_t		conditionid, correlationid;
4904 	zbx_dc_corr_condition_t	*condition;
4905 	zbx_dc_correlation_t	*correlation;
4906 	int			found, ret, i, index;
4907 	unsigned char		type;
4908 	size_t			condition_size;
4909 	zbx_vector_ptr_t	correlations;
4910 
4911 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4912 
4913 	zbx_vector_ptr_create(&correlations);
4914 
4915 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4916 	{
4917 		/* removed rows will be always added at the end */
4918 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4919 			break;
4920 
4921 		ZBX_STR2UINT64(correlationid, row[1]);
4922 
4923 		if (NULL == (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &correlationid)))
4924 			continue;
4925 
4926 		ZBX_STR2UINT64(conditionid, row[0]);
4927 		ZBX_STR2UCHAR(type, row[2]);
4928 
4929 		condition_size = dc_corr_condition_get_size(type);
4930 		condition = (zbx_dc_corr_condition_t *)DCfind_id(&config->corr_conditions, conditionid, condition_size, &found);
4931 
4932 		condition->correlationid = correlationid;
4933 		condition->type = type;
4934 		dc_corr_condition_init_data(condition, found, row + 3);
4935 
4936 		if (0 == found)
4937 			zbx_vector_ptr_append(&correlation->conditions, condition);
4938 
4939 		/* sort the conditions later */
4940 		if (CONDITION_EVAL_TYPE_AND_OR == correlation->evaltype)
4941 			zbx_vector_ptr_append(&correlations, correlation);
4942 	}
4943 
4944 	/* remove deleted correlation conditions */
4945 
4946 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4947 	{
4948 		if (NULL == (condition = (zbx_dc_corr_condition_t *)zbx_hashset_search(&config->corr_conditions, &rowid)))
4949 			continue;
4950 
4951 		/* remove condition from correlation->conditions vector */
4952 		if (NULL != (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &condition->correlationid)))
4953 		{
4954 			if (FAIL != (index = zbx_vector_ptr_search(&correlation->conditions, condition,
4955 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4956 			{
4957 				/* sort the conditions later */
4958 				if (CONDITION_EVAL_TYPE_AND_OR == correlation->evaltype)
4959 					zbx_vector_ptr_append(&correlations, correlation);
4960 
4961 				zbx_vector_ptr_remove_noorder(&correlation->conditions, index);
4962 			}
4963 		}
4964 
4965 		corr_condition_free_data(condition);
4966 		zbx_hashset_remove_direct(&config->corr_conditions, condition);
4967 	}
4968 
4969 	/* sort conditions by type */
4970 
4971 	zbx_vector_ptr_sort(&correlations, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4972 	zbx_vector_ptr_uniq(&correlations, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4973 
4974 	for (i = 0; i < correlations.values_num; i++)
4975 	{
4976 		correlation = (zbx_dc_correlation_t *)correlations.values[i];
4977 		zbx_vector_ptr_sort(&correlation->conditions, dc_compare_corr_conditions_by_type);
4978 	}
4979 
4980 	zbx_vector_ptr_destroy(&correlations);
4981 
4982 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4983 }
4984 
4985 /******************************************************************************
4986  *                                                                            *
4987  * Function: DCsync_corr_operations                                           *
4988  *                                                                            *
4989  * Purpose: Updates correlation operations configuration cache                *
4990  *                                                                            *
4991  * Parameters: result - [IN] the result of correlation operations database    *
4992  *                           select                                           *
4993  *                                                                            *
4994  * Comments: The result contains the following fields:                        *
4995  *           0 - corr_operationid                                             *
4996  *           1 - correlationid                                                *
4997  *           2 - type                                                         *
4998  *                                                                            *
4999  ******************************************************************************/
DCsync_corr_operations(zbx_dbsync_t * sync)5000 static void	DCsync_corr_operations(zbx_dbsync_t *sync)
5001 {
5002 	char			**row;
5003 	zbx_uint64_t		rowid;
5004 	unsigned char		tag;
5005 	zbx_uint64_t		operationid, correlationid;
5006 	zbx_dc_corr_operation_t	*operation;
5007 	zbx_dc_correlation_t	*correlation;
5008 	int			found, ret, index;
5009 	unsigned char		type;
5010 
5011 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5012 
5013 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5014 	{
5015 		/* removed rows will be always added at the end */
5016 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5017 			break;
5018 
5019 		ZBX_STR2UINT64(correlationid, row[1]);
5020 
5021 		if (NULL == (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &correlationid)))
5022 			continue;
5023 
5024 		ZBX_STR2UINT64(operationid, row[0]);
5025 		ZBX_STR2UCHAR(type, row[2]);
5026 
5027 		operation = (zbx_dc_corr_operation_t *)DCfind_id(&config->corr_operations, operationid, sizeof(zbx_dc_corr_operation_t), &found);
5028 
5029 		operation->type = type;
5030 
5031 		if (0 == found)
5032 		{
5033 			operation->correlationid = correlationid;
5034 			zbx_vector_ptr_append(&correlation->operations, operation);
5035 		}
5036 	}
5037 
5038 	/* remove deleted correlation operations */
5039 
5040 	/* remove deleted actions */
5041 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5042 	{
5043 		if (NULL == (operation = (zbx_dc_corr_operation_t *)zbx_hashset_search(&config->corr_operations, &rowid)))
5044 			continue;
5045 
5046 		/* remove operation from correlation->conditions vector */
5047 		if (NULL != (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &operation->correlationid)))
5048 		{
5049 			if (FAIL != (index = zbx_vector_ptr_search(&correlation->operations, operation,
5050 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5051 			{
5052 				zbx_vector_ptr_remove_noorder(&correlation->operations, index);
5053 			}
5054 		}
5055 		zbx_hashset_remove_direct(&config->corr_operations, operation);
5056 	}
5057 
5058 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5059 }
5060 
dc_compare_hgroups(const void * d1,const void * d2)5061 static int	dc_compare_hgroups(const void *d1, const void *d2)
5062 {
5063 	const zbx_dc_hostgroup_t	*g1 = *((const zbx_dc_hostgroup_t **)d1);
5064 	const zbx_dc_hostgroup_t	*g2 = *((const zbx_dc_hostgroup_t **)d2);
5065 
5066 	return strcmp(g1->name, g2->name);
5067 }
5068 
5069 /******************************************************************************
5070  *                                                                            *
5071  * Function: DCsync_hostgroups                                                *
5072  *                                                                            *
5073  * Purpose: Updates host groups configuration cache                           *
5074  *                                                                            *
5075  * Parameters: sync - [IN] the db synchronization data                        *
5076  *                                                                            *
5077  * Comments: The result contains the following fields:                        *
5078  *           0 - groupid                                                      *
5079  *           1 - name                                                         *
5080  *                                                                            *
5081  ******************************************************************************/
DCsync_hostgroups(zbx_dbsync_t * sync)5082 static void	DCsync_hostgroups(zbx_dbsync_t *sync)
5083 {
5084 	char			**row;
5085 	zbx_uint64_t		rowid;
5086 	unsigned char		tag;
5087 	zbx_uint64_t		groupid;
5088 	zbx_dc_hostgroup_t	*group;
5089 	int			found, ret, index;
5090 
5091 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5092 
5093 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5094 	{
5095 		/* removed rows will be always added at the end */
5096 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5097 			break;
5098 
5099 		ZBX_STR2UINT64(groupid, row[0]);
5100 
5101 		group = (zbx_dc_hostgroup_t *)DCfind_id(&config->hostgroups, groupid, sizeof(zbx_dc_hostgroup_t), &found);
5102 
5103 		if (0 == found)
5104 		{
5105 			group->flags = ZBX_DC_HOSTGROUP_FLAGS_NONE;
5106 			zbx_vector_ptr_append(&config->hostgroups_name, group);
5107 
5108 			zbx_hashset_create_ext(&group->hostids, 0, ZBX_DEFAULT_UINT64_HASH_FUNC,
5109 					ZBX_DEFAULT_UINT64_COMPARE_FUNC, NULL, __config_mem_malloc_func,
5110 					__config_mem_realloc_func, __config_mem_free_func);
5111 		}
5112 
5113 		DCstrpool_replace(found, &group->name, row[1]);
5114 	}
5115 
5116 	/* remove deleted host groups */
5117 
5118 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5119 	{
5120 		if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &rowid)))
5121 			continue;
5122 
5123 		if (FAIL != (index = zbx_vector_ptr_search(&config->hostgroups_name, group, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5124 			zbx_vector_ptr_remove_noorder(&config->hostgroups_name, index);
5125 
5126 		if (ZBX_DC_HOSTGROUP_FLAGS_NONE != group->flags)
5127 			zbx_vector_uint64_destroy(&group->nested_groupids);
5128 
5129 		zbx_strpool_release(group->name);
5130 		zbx_hashset_destroy(&group->hostids);
5131 		zbx_hashset_remove_direct(&config->hostgroups, group);
5132 	}
5133 
5134 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5135 }
5136 
5137 /******************************************************************************
5138  *                                                                            *
5139  * Function: DCsync_trigger_tags                                              *
5140  *                                                                            *
5141  * Purpose: Updates trigger tags in configuration cache                       *
5142  *                                                                            *
5143  * Parameters: sync - [IN] the db synchronization data                        *
5144  *                                                                            *
5145  * Comments: The result contains the following fields:                        *
5146  *           0 - triggertagid                                                 *
5147  *           1 - triggerid                                                    *
5148  *           2 - tag                                                          *
5149  *           3 - value                                                        *
5150  *                                                                            *
5151  ******************************************************************************/
DCsync_trigger_tags(zbx_dbsync_t * sync)5152 static void	DCsync_trigger_tags(zbx_dbsync_t *sync)
5153 {
5154 	char			**row;
5155 	zbx_uint64_t		rowid;
5156 	unsigned char		tag;
5157 	int			found, ret, index;
5158 	zbx_uint64_t		triggerid, triggertagid;
5159 	ZBX_DC_TRIGGER		*trigger;
5160 	zbx_dc_trigger_tag_t	*trigger_tag;
5161 
5162 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5163 
5164 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5165 	{
5166 		/* removed rows will be always added at the end */
5167 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5168 			break;
5169 
5170 		ZBX_STR2UINT64(triggerid, row[1]);
5171 
5172 		if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerid)))
5173 			continue;
5174 
5175 		ZBX_STR2UINT64(triggertagid, row[0]);
5176 
5177 		trigger_tag = (zbx_dc_trigger_tag_t *)DCfind_id(&config->trigger_tags, triggertagid,
5178 				sizeof(zbx_dc_trigger_tag_t), &found);
5179 		DCstrpool_replace(found, &trigger_tag->tag, row[2]);
5180 		DCstrpool_replace(found, &trigger_tag->value, row[3]);
5181 
5182 		if (0 == found)
5183 		{
5184 			trigger_tag->triggerid = triggerid;
5185 			zbx_vector_ptr_append(&trigger->tags, trigger_tag);
5186 		}
5187 	}
5188 
5189 	/* remove unused trigger tags */
5190 
5191 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5192 	{
5193 		if (NULL == (trigger_tag = (zbx_dc_trigger_tag_t *)zbx_hashset_search(&config->trigger_tags, &rowid)))
5194 			continue;
5195 
5196 		if (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &trigger_tag->triggerid)))
5197 		{
5198 			if (FAIL != (index = zbx_vector_ptr_search(&trigger->tags, trigger_tag,
5199 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5200 			{
5201 				zbx_vector_ptr_remove_noorder(&trigger->tags, index);
5202 
5203 				/* recreate empty tags vector to release used memory */
5204 				if (0 == trigger->tags.values_num)
5205 				{
5206 					zbx_vector_ptr_destroy(&trigger->tags);
5207 					zbx_vector_ptr_create_ext(&trigger->tags, __config_mem_malloc_func,
5208 							__config_mem_realloc_func, __config_mem_free_func);
5209 				}
5210 			}
5211 		}
5212 
5213 		zbx_strpool_release(trigger_tag->tag);
5214 		zbx_strpool_release(trigger_tag->value);
5215 
5216 		zbx_hashset_remove_direct(&config->trigger_tags, trigger_tag);
5217 	}
5218 
5219 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5220 }
5221 
5222 /******************************************************************************
5223  *                                                                            *
5224  * Function: DCsync_item_tags                                                 *
5225  *                                                                            *
5226  * Purpose: Updates item tags in configuration cache                          *
5227  *                                                                            *
5228  * Parameters: sync - [IN] the db synchronization data                        *
5229  *                                                                            *
5230  * Comments: The result contains the following fields:                        *
5231  *           0 - itemtagid                                                    *
5232  *           1 - itemid                                                       *
5233  *           2 - tag                                                          *
5234  *           3 - value                                                        *
5235  *                                                                            *
5236  ******************************************************************************/
DCsync_item_tags(zbx_dbsync_t * sync)5237 static void	DCsync_item_tags(zbx_dbsync_t *sync)
5238 {
5239 	char			**row;
5240 	zbx_uint64_t		rowid;
5241 	unsigned char		tag;
5242 	int			found, ret, index;
5243 	zbx_uint64_t		itemid, itemtagid;
5244 	ZBX_DC_ITEM		*item;
5245 	zbx_dc_item_tag_t	*item_tag;
5246 
5247 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5248 
5249 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5250 	{
5251 		/* removed rows will be always added at the end */
5252 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5253 			break;
5254 
5255 		ZBX_STR2UINT64(itemid, row[1]);
5256 
5257 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
5258 			continue;
5259 
5260 		ZBX_STR2UINT64(itemtagid, row[0]);
5261 
5262 		item_tag = (zbx_dc_item_tag_t *)DCfind_id(&config->item_tags, itemtagid, sizeof(zbx_dc_item_tag_t),
5263 				&found);
5264 		DCstrpool_replace(found, &item_tag->tag, row[2]);
5265 		DCstrpool_replace(found, &item_tag->value, row[3]);
5266 
5267 		if (0 == found)
5268 		{
5269 			item_tag->itemid = itemid;
5270 			zbx_vector_ptr_append(&item->tags, item_tag);
5271 		}
5272 	}
5273 
5274 	/* remove unused item tags */
5275 
5276 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5277 	{
5278 		if (NULL == (item_tag = (zbx_dc_item_tag_t *)zbx_hashset_search(&config->item_tags, &rowid)))
5279 			continue;
5280 
5281 		if (NULL != (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &item_tag->itemid)))
5282 		{
5283 			if (FAIL != (index = zbx_vector_ptr_search(&item->tags, item_tag,
5284 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5285 			{
5286 				zbx_vector_ptr_remove_noorder(&item->tags, index);
5287 
5288 				/* recreate empty tags vector to release used memory */
5289 				if (0 == item->tags.values_num)
5290 				{
5291 					zbx_vector_ptr_destroy(&item->tags);
5292 					zbx_vector_ptr_create_ext(&item->tags, __config_mem_malloc_func,
5293 							__config_mem_realloc_func, __config_mem_free_func);
5294 				}
5295 			}
5296 		}
5297 
5298 		zbx_strpool_release(item_tag->tag);
5299 		zbx_strpool_release(item_tag->value);
5300 
5301 		zbx_hashset_remove_direct(&config->item_tags, item_tag);
5302 	}
5303 
5304 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5305 }
5306 
5307 /******************************************************************************
5308  *                                                                            *
5309  * Function: DCsync_host_tags                                                 *
5310  *                                                                            *
5311  * Purpose: Updates host tags in configuration cache                          *
5312  *                                                                            *
5313  * Parameters: sync - [IN] the db synchronization data                        *
5314  *                                                                            *
5315  * Comments: The result contains the following fields:                        *
5316  *           0 - hosttagid                                                    *
5317  *           1 - hostid                                                       *
5318  *           2 - tag                                                          *
5319  *           3 - value                                                        *
5320  *                                                                            *
5321  ******************************************************************************/
DCsync_host_tags(zbx_dbsync_t * sync)5322 static void	DCsync_host_tags(zbx_dbsync_t *sync)
5323 {
5324 	char		**row;
5325 	zbx_uint64_t	rowid;
5326 	unsigned char	tag;
5327 
5328 	zbx_dc_host_tag_t		*host_tag;
5329 	zbx_dc_host_tag_index_t		*host_tag_index_entry;
5330 
5331 	int		found, index, ret;
5332 	zbx_uint64_t	hosttagid, hostid;
5333 
5334 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5335 
5336 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5337 	{
5338 		/* removed rows will be always added at the end */
5339 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5340 			break;
5341 
5342 		ZBX_STR2UINT64(hosttagid, row[0]);
5343 		ZBX_STR2UINT64(hostid, row[1]);
5344 
5345 		host_tag = (zbx_dc_host_tag_t *)DCfind_id(&config->host_tags, hosttagid,
5346 				sizeof(zbx_dc_host_tag_t), &found);
5347 
5348 		/* store new information in host_tag structure */
5349 		host_tag->hostid = hostid;
5350 		DCstrpool_replace(found, &host_tag->tag, row[2]);
5351 		DCstrpool_replace(found, &host_tag->value, row[3]);
5352 
5353 		/* update host_tags_index*/
5354 		if (tag == ZBX_DBSYNC_ROW_ADD)
5355 		{
5356 			host_tag_index_entry = (zbx_dc_host_tag_index_t *)DCfind_id(&config->host_tags_index, hostid,
5357 					sizeof(zbx_dc_host_tag_index_t), &found);
5358 
5359 			if (0 == found)
5360 			{
5361 				zbx_vector_ptr_create_ext(&host_tag_index_entry->tags, __config_mem_malloc_func,
5362 						__config_mem_realloc_func, __config_mem_free_func);
5363 			}
5364 
5365 			zbx_vector_ptr_append(&host_tag_index_entry->tags, host_tag);
5366 		}
5367 	}
5368 
5369 	/* remove deleted host tags from buffer */
5370 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5371 	{
5372 		if (NULL == (host_tag = (zbx_dc_host_tag_t *)zbx_hashset_search(&config->host_tags, &rowid)))
5373 			continue;
5374 
5375 		/* update host_tags_index*/
5376 		host_tag_index_entry = (zbx_dc_host_tag_index_t *)zbx_hashset_search(&config->host_tags_index,
5377 				&host_tag->hostid);
5378 
5379 		if (NULL != host_tag_index_entry)
5380 		{
5381 			if (FAIL != (index = zbx_vector_ptr_search(&host_tag_index_entry->tags, host_tag,
5382 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5383 			{
5384 				zbx_vector_ptr_remove(&host_tag_index_entry->tags, index);
5385 			}
5386 
5387 			/* remove index entry if it's empty */
5388 			if (0 == host_tag_index_entry->tags.values_num)
5389 			{
5390 				zbx_vector_ptr_destroy(&host_tag_index_entry->tags);
5391 				zbx_hashset_remove_direct(&config->host_tags_index, host_tag_index_entry);
5392 			}
5393 		}
5394 
5395 		/* clear host_tag structure */
5396 		zbx_strpool_release(host_tag->tag);
5397 		zbx_strpool_release(host_tag->value);
5398 
5399 		zbx_hashset_remove_direct(&config->host_tags, host_tag);
5400 	}
5401 
5402 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5403 }
5404 
5405 /******************************************************************************
5406  *                                                                            *
5407  * Function: dc_compare_itemscript_param                                      *
5408  *                                                                            *
5409  * Purpose: compare two item script parameters                                *
5410  *                                                                            *
5411  ******************************************************************************/
dc_compare_itemscript_param(const void * d1,const void * d2)5412 static int	dc_compare_itemscript_param(const void *d1, const void *d2)
5413 {
5414 	zbx_dc_scriptitem_param_t	*p1 = *(zbx_dc_scriptitem_param_t **)d1;
5415 	zbx_dc_scriptitem_param_t	*p2 = *(zbx_dc_scriptitem_param_t **)d2;
5416 
5417 	ZBX_RETURN_IF_NOT_EQUAL(p1->name, p2->name);
5418 	ZBX_RETURN_IF_NOT_EQUAL(p1->value, p2->value);
5419 
5420 	return 0;
5421 }
5422 
5423 /******************************************************************************
5424  *                                                                            *
5425  * Function: dc_compare_item_preproc_by_step                                  *
5426  *                                                                            *
5427  * Purpose: compare two item preprocessing operations by step                 *
5428  *                                                                            *
5429  * Comments: This function is used to sort correlation conditions by type.    *
5430  *                                                                            *
5431  ******************************************************************************/
dc_compare_preprocops_by_step(const void * d1,const void * d2)5432 static int	dc_compare_preprocops_by_step(const void *d1, const void *d2)
5433 {
5434 	zbx_dc_preproc_op_t	*p1 = *(zbx_dc_preproc_op_t **)d1;
5435 	zbx_dc_preproc_op_t	*p2 = *(zbx_dc_preproc_op_t **)d2;
5436 
5437 	if (ZBX_PREPROC_VALIDATE_NOT_SUPPORTED == p1->type)
5438 		return -1;
5439 
5440 	if (ZBX_PREPROC_VALIDATE_NOT_SUPPORTED == p2->type)
5441 		return 1;
5442 
5443 	ZBX_RETURN_IF_NOT_EQUAL(p1->step, p2->step);
5444 
5445 	return 0;
5446 }
5447 
5448 /******************************************************************************
5449  *                                                                            *
5450  * Function: DCsync_item_preproc                                              *
5451  *                                                                            *
5452  * Purpose: Updates item preprocessing steps in configuration cache           *
5453  *                                                                            *
5454  * Parameters: sync - [IN] the db synchronization data                        *
5455  *                                                                            *
5456  * Comments: The result contains the following fields:                        *
5457  *           0 - item_preprocid                                               *
5458  *           1 - itemid                                                       *
5459  *           2 - type                                                         *
5460  *           3 - params                                                       *
5461  *                                                                            *
5462  ******************************************************************************/
DCsync_item_preproc(zbx_dbsync_t * sync,int timestamp)5463 static void	DCsync_item_preproc(zbx_dbsync_t *sync, int timestamp)
5464 {
5465 	char			**row;
5466 	zbx_uint64_t		rowid;
5467 	unsigned char		tag;
5468 	zbx_uint64_t		item_preprocid, itemid;
5469 	int			found, ret, i, index;
5470 	ZBX_DC_PREPROCITEM	*preprocitem = NULL;
5471 	zbx_dc_preproc_op_t	*op;
5472 	zbx_vector_ptr_t	items;
5473 
5474 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5475 
5476 	zbx_vector_ptr_create(&items);
5477 
5478 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5479 	{
5480 		/* removed rows will be always added at the end */
5481 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5482 			break;
5483 
5484 		ZBX_STR2UINT64(itemid, row[1]);
5485 
5486 		if (NULL == preprocitem || itemid != preprocitem->itemid)
5487 		{
5488 			if (NULL == (preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_search(&config->preprocitems, &itemid)))
5489 			{
5490 				ZBX_DC_PREPROCITEM	preprocitem_local;
5491 
5492 				preprocitem_local.itemid = itemid;
5493 
5494 				preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_insert(&config->preprocitems, &preprocitem_local,
5495 						sizeof(preprocitem_local));
5496 
5497 				zbx_vector_ptr_create_ext(&preprocitem->preproc_ops, __config_mem_malloc_func,
5498 						__config_mem_realloc_func, __config_mem_free_func);
5499 			}
5500 
5501 			preprocitem->update_time = timestamp;
5502 		}
5503 
5504 		ZBX_STR2UINT64(item_preprocid, row[0]);
5505 
5506 		op = (zbx_dc_preproc_op_t *)DCfind_id(&config->preprocops, item_preprocid, sizeof(zbx_dc_preproc_op_t), &found);
5507 
5508 		ZBX_STR2UCHAR(op->type, row[2]);
5509 		DCstrpool_replace(found, &op->params, row[3]);
5510 		op->step = atoi(row[4]);
5511 		op->error_handler = atoi(row[6]);
5512 		DCstrpool_replace(found, &op->error_handler_params, row[7]);
5513 
5514 		if (0 == found)
5515 		{
5516 			op->itemid = itemid;
5517 			zbx_vector_ptr_append(&preprocitem->preproc_ops, op);
5518 		}
5519 
5520 		zbx_vector_ptr_append(&items, preprocitem);
5521 	}
5522 
5523 	/* remove deleted item preprocessing operations */
5524 
5525 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5526 	{
5527 		if (NULL == (op = (zbx_dc_preproc_op_t *)zbx_hashset_search(&config->preprocops, &rowid)))
5528 			continue;
5529 
5530 		if (NULL != (preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_search(&config->preprocitems, &op->itemid)))
5531 		{
5532 			if (FAIL != (index = zbx_vector_ptr_search(&preprocitem->preproc_ops, op,
5533 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5534 			{
5535 				zbx_vector_ptr_remove_noorder(&preprocitem->preproc_ops, index);
5536 				zbx_vector_ptr_append(&items, preprocitem);
5537 			}
5538 		}
5539 
5540 		zbx_strpool_release(op->params);
5541 		zbx_strpool_release(op->error_handler_params);
5542 		zbx_hashset_remove_direct(&config->preprocops, op);
5543 	}
5544 
5545 	/* sort item preprocessing operations by step */
5546 
5547 	zbx_vector_ptr_sort(&items, ZBX_DEFAULT_PTR_COMPARE_FUNC);
5548 	zbx_vector_ptr_uniq(&items, ZBX_DEFAULT_PTR_COMPARE_FUNC);
5549 
5550 	for (i = 0; i < items.values_num; i++)
5551 	{
5552 		preprocitem = (ZBX_DC_PREPROCITEM *)items.values[i];
5553 
5554 		if (0 == preprocitem->preproc_ops.values_num)
5555 		{
5556 			zbx_vector_ptr_destroy(&preprocitem->preproc_ops);
5557 			zbx_hashset_remove_direct(&config->preprocitems, preprocitem);
5558 		}
5559 		else
5560 			zbx_vector_ptr_sort(&preprocitem->preproc_ops, dc_compare_preprocops_by_step);
5561 	}
5562 
5563 	zbx_vector_ptr_destroy(&items);
5564 
5565 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5566 }
5567 
5568 /******************************************************************************
5569  *                                                                            *
5570  * Function: DCsync_itemscript_param                                          *
5571  *                                                                            *
5572  * Purpose: Updates item script parameters in configuration cache             *
5573  *                                                                            *
5574  * Parameters: sync - [IN] the db synchronization data                        *
5575  *                                                                            *
5576  * Comments: The result contains the following fields:                        *
5577  *           0 - item_script_paramid                                          *
5578  *           1 - itemid                                                       *
5579  *           2 - name                                                         *
5580  *           3 - value                                                        *
5581  *                                                                            *
5582  ******************************************************************************/
DCsync_itemscript_param(zbx_dbsync_t * sync)5583 static void	DCsync_itemscript_param(zbx_dbsync_t *sync)
5584 {
5585 	char				**row;
5586 	zbx_uint64_t			rowid;
5587 	unsigned char			tag;
5588 	zbx_uint64_t			item_script_paramid, itemid;
5589 	int				found, ret, i, index;
5590 	ZBX_DC_SCRIPTITEM		*scriptitem;
5591 	zbx_dc_scriptitem_param_t	*scriptitem_params;
5592 	zbx_vector_ptr_t		items;
5593 
5594 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5595 
5596 	zbx_vector_ptr_create(&items);
5597 
5598 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5599 	{
5600 		/* removed rows will be always added at the end */
5601 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5602 			break;
5603 
5604 		ZBX_STR2UINT64(itemid, row[1]);
5605 
5606 		if (NULL == (scriptitem = (ZBX_DC_SCRIPTITEM *) zbx_hashset_search(&config->scriptitems, &itemid)))
5607 		{
5608 			zabbix_log(LOG_LEVEL_DEBUG,
5609 					"cannot find parent item for item parameters (itemid=" ZBX_FS_UI64")", itemid);
5610 			continue;
5611 		}
5612 
5613 		ZBX_STR2UINT64(item_script_paramid, row[0]);
5614 		scriptitem_params = (zbx_dc_scriptitem_param_t *)DCfind_id(&config->itemscript_params,
5615 				item_script_paramid, sizeof(zbx_dc_scriptitem_param_t), &found);
5616 
5617 		DCstrpool_replace(found, &scriptitem_params->name, row[2]);
5618 		DCstrpool_replace(found, &scriptitem_params->value, row[3]);
5619 
5620 		if (0 == found)
5621 		{
5622 			scriptitem_params->itemid = itemid;
5623 			zbx_vector_ptr_append(&scriptitem->params, scriptitem_params);
5624 		}
5625 
5626 		zbx_vector_ptr_append(&items, scriptitem);
5627 	}
5628 
5629 	/* remove deleted item script parameters */
5630 
5631 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5632 	{
5633 		if (NULL == (scriptitem_params =
5634 				(zbx_dc_scriptitem_param_t *)zbx_hashset_search(&config->itemscript_params, &rowid)))
5635 		{
5636 			continue;
5637 		}
5638 
5639 		if (NULL != (scriptitem = (ZBX_DC_SCRIPTITEM *)zbx_hashset_search(&config->scriptitems,
5640 				&scriptitem_params->itemid)))
5641 		{
5642 			if (FAIL != (index = zbx_vector_ptr_search(&scriptitem->params, scriptitem_params,
5643 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5644 			{
5645 				zbx_vector_ptr_remove_noorder(&scriptitem->params, index);
5646 				zbx_vector_ptr_append(&items, scriptitem);
5647 			}
5648 		}
5649 
5650 		zbx_strpool_release(scriptitem_params->name);
5651 		zbx_strpool_release(scriptitem_params->value);
5652 		zbx_hashset_remove_direct(&config->itemscript_params, scriptitem_params);
5653 	}
5654 
5655 	/* sort item script parameters */
5656 
5657 	zbx_vector_ptr_sort(&items, ZBX_DEFAULT_PTR_COMPARE_FUNC);
5658 	zbx_vector_ptr_uniq(&items, ZBX_DEFAULT_PTR_COMPARE_FUNC);
5659 
5660 	for (i = 0; i < items.values_num; i++)
5661 	{
5662 		scriptitem = (ZBX_DC_SCRIPTITEM *)items.values[i];
5663 
5664 		if (0 == scriptitem->params.values_num)
5665 		{
5666 			zbx_vector_ptr_destroy(&scriptitem->params);
5667 			zbx_hashset_remove_direct(&config->scriptitems, scriptitem);
5668 		}
5669 		else
5670 			zbx_vector_ptr_sort(&scriptitem->params, dc_compare_itemscript_param);
5671 	}
5672 
5673 	zbx_vector_ptr_destroy(&items);
5674 
5675 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5676 }
5677 
5678 /******************************************************************************
5679  *                                                                            *
5680  * Function: DCsync_hostgroup_hosts                                           *
5681  *                                                                            *
5682  * Purpose: Updates group hosts in configuration cache                        *
5683  *                                                                            *
5684  * Parameters: sync - [IN] the db synchronization data                        *
5685  *                                                                            *
5686  * Comments: The result contains the following fields:                        *
5687  *           0 - groupid                                                      *
5688  *           1 - hostid                                                       *
5689  *                                                                            *
5690  ******************************************************************************/
DCsync_hostgroup_hosts(zbx_dbsync_t * sync)5691 static void	DCsync_hostgroup_hosts(zbx_dbsync_t *sync)
5692 {
5693 	char			**row;
5694 	zbx_uint64_t		rowid;
5695 	unsigned char		tag;
5696 
5697 	zbx_dc_hostgroup_t	*group = NULL;
5698 
5699 	int			ret;
5700 	zbx_uint64_t		last_groupid = 0, groupid, hostid;
5701 
5702 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5703 
5704 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
5705 	{
5706 		config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
5707 
5708 		/* removed rows will be always added at the end */
5709 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
5710 			break;
5711 
5712 		ZBX_STR2UINT64(groupid, row[0]);
5713 
5714 		if (last_groupid != groupid)
5715 		{
5716 			group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &groupid);
5717 			last_groupid = groupid;
5718 		}
5719 
5720 		if (NULL == group)
5721 			continue;
5722 
5723 		ZBX_STR2UINT64(hostid, row[1]);
5724 		zbx_hashset_insert(&group->hostids, &hostid, sizeof(hostid));
5725 	}
5726 
5727 	/* remove deleted group hostids from cache */
5728 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
5729 	{
5730 		ZBX_STR2UINT64(groupid, row[0]);
5731 
5732 		if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &groupid)))
5733 			continue;
5734 
5735 		ZBX_STR2UINT64(hostid, row[1]);
5736 		zbx_hashset_remove(&group->hostids, &hostid);
5737 	}
5738 
5739 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5740 }
5741 
5742 /******************************************************************************
5743  *                                                                            *
5744  * Function: dc_trigger_update_topology                                       *
5745  *                                                                            *
5746  * Purpose: updates trigger topology after trigger dependency changes         *
5747  *                                                                            *
5748  ******************************************************************************/
dc_trigger_update_topology(void)5749 static void	dc_trigger_update_topology(void)
5750 {
5751 	zbx_hashset_iter_t	iter;
5752 	ZBX_DC_TRIGGER		*trigger;
5753 
5754 	zbx_hashset_iter_reset(&config->triggers, &iter);
5755 	while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
5756 		trigger->topoindex = 1;
5757 
5758 	DCconfig_sort_triggers_topologically();
5759 }
5760 
zbx_default_ptr_pair_ptr_compare_func(const void * d1,const void * d2)5761 static int	zbx_default_ptr_pair_ptr_compare_func(const void *d1, const void *d2)
5762 {
5763 	const zbx_ptr_pair_t	*p1 = (const zbx_ptr_pair_t *)d1;
5764 	const zbx_ptr_pair_t	*p2 = (const zbx_ptr_pair_t *)d2;
5765 
5766 	ZBX_RETURN_IF_NOT_EQUAL(p1->first, p2->first);
5767 	ZBX_RETURN_IF_NOT_EQUAL(p1->second, p2->second);
5768 
5769 	return 0;
5770 }
5771 
5772 /******************************************************************************
5773  *                                                                            *
5774  * Function: dc_trigger_update_cache                                          *
5775  *                                                                            *
5776  * Purpose: updates trigger related cache data;                               *
5777  *              1) time triggers assigned to timer processes                  *
5778  *              2) trigger functionality (if it uses contain disabled         *
5779  *                 items/hosts)                                               *
5780  *              3) list of triggers each item is used by                      *
5781  *                                                                            *
5782  ******************************************************************************/
dc_trigger_update_cache(void)5783 static void	dc_trigger_update_cache(void)
5784 {
5785 	zbx_hashset_iter_t	iter;
5786 	ZBX_DC_TRIGGER		*trigger;
5787 	ZBX_DC_FUNCTION		*function;
5788 	ZBX_DC_ITEM		*item;
5789 	int			i, j, k;
5790 	zbx_ptr_pair_t		itemtrig;
5791 	zbx_vector_ptr_pair_t	itemtrigs;
5792 	ZBX_DC_HOST		*host;
5793 
5794 	zbx_hashset_iter_reset(&config->triggers, &iter);
5795 	while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
5796 		trigger->functional = TRIGGER_FUNCTIONAL_TRUE;
5797 
5798 	zbx_vector_ptr_pair_create(&itemtrigs);
5799 	zbx_hashset_iter_reset(&config->functions, &iter);
5800 	while (NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_iter_next(&iter)))
5801 	{
5802 
5803 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)) ||
5804 				NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &function->triggerid)))
5805 		{
5806 			continue;
5807 		}
5808 
5809 		/* cache item - trigger link */
5810 		if (0 != item->update_triggers)
5811 		{
5812 			itemtrig.first = item;
5813 			itemtrig.second = trigger;
5814 			zbx_vector_ptr_pair_append(&itemtrigs, itemtrig);
5815 		}
5816 
5817 		/* disable functionality for triggers with expression containing */
5818 		/* disabled or not monitored items                               */
5819 
5820 		if (TRIGGER_FUNCTIONAL_FALSE == trigger->functional)
5821 			continue;
5822 
5823 		if (ITEM_STATUS_DISABLED == item->status ||
5824 				(NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->hostid)) ||
5825 						HOST_STATUS_NOT_MONITORED == host->status))
5826 		{
5827 			trigger->functional = TRIGGER_FUNCTIONAL_FALSE;
5828 		}
5829 	}
5830 
5831 	zbx_vector_ptr_pair_sort(&itemtrigs, zbx_default_ptr_pair_ptr_compare_func);
5832 	zbx_vector_ptr_pair_uniq(&itemtrigs, zbx_default_ptr_pair_ptr_compare_func);
5833 
5834 	/* update links from items to triggers */
5835 	for (i = 0; i < itemtrigs.values_num; i++)
5836 	{
5837 		for (j = i + 1; j < itemtrigs.values_num; j++)
5838 		{
5839 			if (itemtrigs.values[i].first != itemtrigs.values[j].first)
5840 				break;
5841 		}
5842 
5843 		item = (ZBX_DC_ITEM *)itemtrigs.values[i].first;
5844 		item->update_triggers = 0;
5845 		item->triggers = (ZBX_DC_TRIGGER **)config->items.mem_realloc_func(item->triggers, (j - i + 1) * sizeof(ZBX_DC_TRIGGER *));
5846 
5847 		for (k = i; k < j; k++)
5848 			item->triggers[k - i] = (ZBX_DC_TRIGGER *)itemtrigs.values[k].second;
5849 
5850 		item->triggers[j - i] = NULL;
5851 
5852 		i = j - 1;
5853 	}
5854 
5855 	zbx_vector_ptr_pair_destroy(&itemtrigs);
5856 }
5857 
5858 /******************************************************************************
5859  *                                                                            *
5860  * Function: dc_hostgroups_update_cache                                       *
5861  *                                                                            *
5862  * Purpose: updates hostgroup name index and resets nested group lists        *
5863  *                                                                            *
5864  ******************************************************************************/
dc_hostgroups_update_cache(void)5865 static void	dc_hostgroups_update_cache(void)
5866 {
5867 	zbx_hashset_iter_t	iter;
5868 	zbx_dc_hostgroup_t	*group;
5869 
5870 	zbx_vector_ptr_sort(&config->hostgroups_name, dc_compare_hgroups);
5871 
5872 	zbx_hashset_iter_reset(&config->hostgroups, &iter);
5873 	while (NULL != (group = (zbx_dc_hostgroup_t *)zbx_hashset_iter_next(&iter)))
5874 	{
5875 		if (ZBX_DC_HOSTGROUP_FLAGS_NONE != group->flags)
5876 		{
5877 			group->flags = ZBX_DC_HOSTGROUP_FLAGS_NONE;
5878 			zbx_vector_uint64_destroy(&group->nested_groupids);
5879 		}
5880 	}
5881 }
5882 
5883 /******************************************************************************
5884  *                                                                            *
5885  * Function: dc_load_trigger_queue                                            *
5886  *                                                                            *
5887  * Purpose: load trigger queue from database                                  *
5888  *                                                                            *
5889  * Comments: This function is called when syncing configuration cache for the *
5890  *           first time after server start. After loading trigger queue it    *
5891  *           will clear the corresponding data in database.                   *
5892  *                                                                            *
5893  ******************************************************************************/
dc_load_trigger_queue(zbx_hashset_t * trend_functions)5894 static void	dc_load_trigger_queue(zbx_hashset_t *trend_functions)
5895 {
5896 	DB_RESULT	result;
5897 	DB_ROW		row;
5898 
5899 	result = DBselect("select objectid,type,clock,ns from trigger_queue");
5900 
5901 	while (NULL != (row = DBfetch(result)))
5902 	{
5903 		zbx_trigger_timer_t	timer_local, *timer;
5904 
5905 		if (ZBX_TRIGGER_TIMER_FUNCTION_TREND != atoi(row[1]))
5906 		{
5907 			THIS_SHOULD_NEVER_HAPPEN;
5908 			continue;
5909 		}
5910 
5911 		ZBX_STR2UINT64(timer_local.objectid, row[0]);
5912 
5913 		timer_local.eval_ts.sec = atoi(row[2]);
5914 		timer_local.eval_ts.ns =  atoi(row[3]);
5915 		timer = zbx_hashset_insert(trend_functions, &timer_local, sizeof(timer_local));
5916 
5917 		/* in the case function was scheduled multiple times use the latest data */
5918 		if (0 > zbx_timespec_compare(&timer->eval_ts, &timer_local.eval_ts))
5919 			timer->eval_ts = timer_local.eval_ts;
5920 
5921 	}
5922 	DBfree_result(result);
5923 }
5924 
5925 /******************************************************************************
5926  *                                                                            *
5927  * Function: DCsync_configuration                                             *
5928  *                                                                            *
5929  * Purpose: Synchronize configuration data from database                      *
5930  *                                                                            *
5931  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
5932  *                                                                            *
5933  ******************************************************************************/
DCsync_configuration(unsigned char mode,const struct zbx_json_parse * jp_kvs_paths)5934 void	DCsync_configuration(unsigned char mode, const struct zbx_json_parse *jp_kvs_paths)
5935 {
5936 	int		i, flags;
5937 	double		sec, csec, hsec, hisec, htsec, gmsec, hmsec, ifsec, isec, tsec, dsec, fsec, expr_sec, csec2,
5938 			hsec2, hisec2, htsec2, gmsec2, hmsec2, ifsec2, isec2, tsec2, dsec2, fsec2, expr_sec2,
5939 			action_sec, action_sec2, action_op_sec, action_op_sec2, action_condition_sec,
5940 			action_condition_sec2, trigger_tag_sec, trigger_tag_sec2, host_tag_sec, host_tag_sec2,
5941 			correlation_sec, correlation_sec2, corr_condition_sec, corr_condition_sec2, corr_operation_sec,
5942 			corr_operation_sec2, hgroups_sec, hgroups_sec2, itempp_sec, itempp_sec2, itemscrp_sec,
5943 			itemscrp_sec2, total, total2, update_sec, maintenance_sec, maintenance_sec2, item_tag_sec,
5944 			item_tag_sec2;
5945 
5946 	zbx_dbsync_t	config_sync, hosts_sync, hi_sync, htmpl_sync, gmacro_sync, hmacro_sync, if_sync, items_sync,
5947 			template_items_sync, prototype_items_sync, triggers_sync, tdep_sync, func_sync, expr_sync,
5948 			action_sync, action_op_sync, action_condition_sync, trigger_tag_sync, item_tag_sync,
5949 			host_tag_sync, correlation_sync, corr_condition_sync, corr_operation_sync, hgroups_sync,
5950 			itempp_sync, itemscrp_sync, maintenance_sync, maintenance_period_sync, maintenance_tag_sync,
5951 			maintenance_group_sync, maintenance_host_sync, hgroup_host_sync;
5952 
5953 	double		autoreg_csec, autoreg_csec2;
5954 	zbx_dbsync_t	autoreg_config_sync;
5955 	zbx_uint64_t	update_flags = 0;
5956 
5957 	zbx_hashset_t		trend_queue;
5958 
5959 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5960 
5961 	config->sync_start_ts = time(NULL);
5962 
5963 	if (ZBX_SYNC_SECRETS == mode)
5964 	{
5965 		DCsync_kvs_paths(NULL);
5966 		goto skip;
5967 	}
5968 
5969 	zbx_dbsync_init_env(config);
5970 
5971 	if (ZBX_DBSYNC_INIT == mode)
5972 	{
5973 		zbx_hashset_create(&trend_queue, 1000, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
5974 		dc_load_trigger_queue(&trend_queue);
5975 	}
5976 
5977 	/* global configuration must be synchronized directly with database */
5978 	zbx_dbsync_init(&config_sync, ZBX_DBSYNC_INIT);
5979 	zbx_dbsync_init(&autoreg_config_sync, mode);
5980 	zbx_dbsync_init(&hosts_sync, mode);
5981 	zbx_dbsync_init(&hi_sync, mode);
5982 	zbx_dbsync_init(&htmpl_sync, mode);
5983 	zbx_dbsync_init(&gmacro_sync, mode);
5984 	zbx_dbsync_init(&hmacro_sync, mode);
5985 	zbx_dbsync_init(&if_sync, mode);
5986 	zbx_dbsync_init(&items_sync, mode);
5987 	zbx_dbsync_init(&template_items_sync, mode);
5988 	zbx_dbsync_init(&prototype_items_sync, mode);
5989 	zbx_dbsync_init(&triggers_sync, mode);
5990 	zbx_dbsync_init(&tdep_sync, mode);
5991 	zbx_dbsync_init(&func_sync, mode);
5992 	zbx_dbsync_init(&expr_sync, mode);
5993 	zbx_dbsync_init(&action_sync, mode);
5994 
5995 	/* Action operation sync produces virtual rows with two columns - actionid, opflags. */
5996 	/* Because of this it cannot return the original database select and must always be  */
5997 	/* initialized in update mode.                                                       */
5998 	zbx_dbsync_init(&action_op_sync, ZBX_DBSYNC_UPDATE);
5999 
6000 	zbx_dbsync_init(&action_condition_sync, mode);
6001 	zbx_dbsync_init(&trigger_tag_sync, mode);
6002 	zbx_dbsync_init(&item_tag_sync, mode);
6003 	zbx_dbsync_init(&host_tag_sync, mode);
6004 	zbx_dbsync_init(&correlation_sync, mode);
6005 	zbx_dbsync_init(&corr_condition_sync, mode);
6006 	zbx_dbsync_init(&corr_operation_sync, mode);
6007 	zbx_dbsync_init(&hgroups_sync, mode);
6008 	zbx_dbsync_init(&hgroup_host_sync, mode);
6009 	zbx_dbsync_init(&itempp_sync, mode);
6010 	zbx_dbsync_init(&itemscrp_sync, mode);
6011 
6012 	zbx_dbsync_init(&maintenance_sync, mode);
6013 	zbx_dbsync_init(&maintenance_period_sync, mode);
6014 	zbx_dbsync_init(&maintenance_tag_sync, mode);
6015 	zbx_dbsync_init(&maintenance_group_sync, mode);
6016 	zbx_dbsync_init(&maintenance_host_sync, mode);
6017 
6018 	sec = zbx_time();
6019 	if (FAIL == zbx_dbsync_compare_config(&config_sync))
6020 		goto out;
6021 	csec = zbx_time() - sec;
6022 
6023 	sec = zbx_time();
6024 	if (FAIL == zbx_dbsync_compare_autoreg_psk(&autoreg_config_sync))
6025 		goto out;
6026 	autoreg_csec = zbx_time() - sec;
6027 
6028 	/* sync global configuration settings */
6029 	START_SYNC;
6030 	sec = zbx_time();
6031 	DCsync_config(&config_sync, &flags);
6032 	csec2 = zbx_time() - sec;
6033 
6034 	sec = zbx_time();
6035 	DCsync_autoreg_config(&autoreg_config_sync);	/* must be done in the same cache locking with config sync */
6036 	autoreg_csec2 = zbx_time() - sec;
6037 	FINISH_SYNC;
6038 
6039 	/* sync macro related data, to support macro resolving during configuration sync */
6040 
6041 	sec = zbx_time();
6042 	if (FAIL == zbx_dbsync_compare_host_templates(&htmpl_sync))
6043 		goto out;
6044 	htsec = zbx_time() - sec;
6045 
6046 	sec = zbx_time();
6047 	if (FAIL == zbx_dbsync_compare_global_macros(&gmacro_sync))
6048 		goto out;
6049 	gmsec = zbx_time() - sec;
6050 
6051 	sec = zbx_time();
6052 	if (FAIL == zbx_dbsync_compare_host_macros(&hmacro_sync))
6053 		goto out;
6054 	hmsec = zbx_time() - sec;
6055 
6056 	sec = zbx_time();
6057 	if (FAIL == zbx_dbsync_compare_host_tags(&host_tag_sync))
6058 		goto out;
6059 	host_tag_sec = zbx_time() - sec;
6060 
6061 	START_SYNC;
6062 	sec = zbx_time();
6063 	DCsync_htmpls(&htmpl_sync);
6064 	htsec2 = zbx_time() - sec;
6065 
6066 	sec = zbx_time();
6067 	DCsync_gmacros(&gmacro_sync);
6068 	gmsec2 = zbx_time() - sec;
6069 
6070 	sec = zbx_time();
6071 	DCsync_hmacros(&hmacro_sync);
6072 	hmsec2 = zbx_time() - sec;
6073 
6074 	sec = zbx_time();
6075 	DCsync_host_tags(&host_tag_sync);
6076 	host_tag_sec2 = zbx_time() - sec;
6077 	FINISH_SYNC;
6078 
6079 	if (FAIL == DCsync_kvs_paths(jp_kvs_paths))
6080 	{
6081 		START_SYNC;
6082 		goto out;
6083 	}
6084 
6085 	/* sync host data to support host lookups when resolving macros during configuration sync */
6086 
6087 	sec = zbx_time();
6088 	if (FAIL == zbx_dbsync_compare_hosts(&hosts_sync))
6089 		goto out;
6090 	hsec = zbx_time() - sec;
6091 
6092 	sec = zbx_time();
6093 	if (FAIL == zbx_dbsync_compare_host_inventory(&hi_sync))
6094 		goto out;
6095 	hisec = zbx_time() - sec;
6096 
6097 	sec = zbx_time();
6098 	if (FAIL == zbx_dbsync_compare_host_groups(&hgroups_sync))
6099 		goto out;
6100 	if (FAIL == zbx_dbsync_compare_host_group_hosts(&hgroup_host_sync))
6101 		goto out;
6102 	hgroups_sec = zbx_time() - sec;
6103 
6104 	sec = zbx_time();
6105 	if (FAIL == zbx_dbsync_compare_maintenances(&maintenance_sync))
6106 		goto out;
6107 	if (FAIL == zbx_dbsync_compare_maintenance_tags(&maintenance_tag_sync))
6108 		goto out;
6109 	if (FAIL == zbx_dbsync_compare_maintenance_periods(&maintenance_period_sync))
6110 		goto out;
6111 	if (FAIL == zbx_dbsync_compare_maintenance_groups(&maintenance_group_sync))
6112 		goto out;
6113 	if (FAIL == zbx_dbsync_compare_maintenance_hosts(&maintenance_host_sync))
6114 		goto out;
6115 	maintenance_sec = zbx_time() - sec;
6116 
6117 	START_SYNC;
6118 	sec = zbx_time();
6119 	DCsync_hosts(&hosts_sync);
6120 	hsec2 = zbx_time() - sec;
6121 
6122 	sec = zbx_time();
6123 	DCsync_host_inventory(&hi_sync);
6124 	hisec2 = zbx_time() - sec;
6125 
6126 	sec = zbx_time();
6127 	DCsync_hostgroups(&hgroups_sync);
6128 	DCsync_hostgroup_hosts(&hgroup_host_sync);
6129 	hgroups_sec2 = zbx_time() - sec;
6130 
6131 	sec = zbx_time();
6132 	DCsync_maintenances(&maintenance_sync);
6133 	DCsync_maintenance_tags(&maintenance_tag_sync);
6134 	DCsync_maintenance_groups(&maintenance_group_sync);
6135 	DCsync_maintenance_hosts(&maintenance_host_sync);
6136 	DCsync_maintenance_periods(&maintenance_period_sync);
6137 	maintenance_sec2 = zbx_time() - sec;
6138 
6139 	if (0 != hgroups_sync.add_num + hgroups_sync.update_num + hgroups_sync.remove_num)
6140 		update_flags |= ZBX_DBSYNC_UPDATE_HOST_GROUPS;
6141 
6142 	if (0 != maintenance_group_sync.add_num + maintenance_group_sync.update_num + maintenance_group_sync.remove_num)
6143 		update_flags |= ZBX_DBSYNC_UPDATE_MAINTENANCE_GROUPS;
6144 
6145 	if (0 != (update_flags & ZBX_DBSYNC_UPDATE_HOST_GROUPS))
6146 		dc_hostgroups_update_cache();
6147 
6148 	/* pre-cache nested groups used in maintenances to allow read lock */
6149 	/* during host maintenance update calculations                     */
6150 	if (0 != (update_flags & (ZBX_DBSYNC_UPDATE_HOST_GROUPS | ZBX_DBSYNC_UPDATE_MAINTENANCE_GROUPS)))
6151 		dc_maintenance_precache_nested_groups();
6152 
6153 	FINISH_SYNC;
6154 
6155 	/* sync item data to support item lookups when resolving macros during configuration sync */
6156 
6157 	sec = zbx_time();
6158 	if (FAIL == zbx_dbsync_compare_interfaces(&if_sync))
6159 		goto out;
6160 	ifsec = zbx_time() - sec;
6161 
6162 	sec = zbx_time();
6163 	if (FAIL == zbx_dbsync_compare_items(&items_sync))
6164 		goto out;
6165 
6166 	if (FAIL == zbx_dbsync_compare_template_items(&template_items_sync))
6167 		goto out;
6168 
6169 	if (FAIL == zbx_dbsync_compare_prototype_items(&prototype_items_sync))
6170 		goto out;
6171 	isec = zbx_time() - sec;
6172 
6173 	sec = zbx_time();
6174 	if (FAIL == zbx_dbsync_compare_item_preprocs(&itempp_sync))
6175 		goto out;
6176 	itempp_sec = zbx_time() - sec;
6177 
6178 	sec = zbx_time();
6179 	if (FAIL == zbx_dbsync_compare_item_script_param(&itemscrp_sync))
6180 		goto out;
6181 	itemscrp_sec = zbx_time() - sec;
6182 
6183 	START_SYNC;
6184 
6185 	/* resolves macros for interface_snmpaddrs, must be after DCsync_hmacros() */
6186 	sec = zbx_time();
6187 	DCsync_interfaces(&if_sync);
6188 	ifsec2 = zbx_time() - sec;
6189 
6190 	/* relies on hosts, proxies and interfaces, must be after DCsync_{hosts,interfaces}() */
6191 	sec = zbx_time();
6192 	DCsync_items(&items_sync, flags);
6193 	DCsync_template_items(&template_items_sync);
6194 	DCsync_prototype_items(&prototype_items_sync);
6195 	isec2 = zbx_time() - sec;
6196 
6197 	/* relies on items, must be after DCsync_items() */
6198 	sec = zbx_time();
6199 	DCsync_item_preproc(&itempp_sync, sec);
6200 	itempp_sec2 = zbx_time() - sec;
6201 
6202 	/* relies on items, must be after DCsync_items() */
6203 	sec = zbx_time();
6204 	DCsync_itemscript_param(&itemscrp_sync);
6205 	itemscrp_sec2 = zbx_time() - sec;
6206 
6207 	config->item_sync_ts = time(NULL);
6208 	FINISH_SYNC;
6209 
6210 	dc_flush_history();	/* misconfigured items generate pseudo-historic values to become notsupported */
6211 
6212 	/* sync function data to support function lookups when resolving macros during configuration sync */
6213 
6214 	/* relies on items, must be after DCsync_items() */
6215 	sec = zbx_time();
6216 	if (FAIL == zbx_dbsync_compare_item_tags(&item_tag_sync))
6217 		goto out;
6218 	item_tag_sec = zbx_time() - sec;
6219 
6220 	sec = zbx_time();
6221 	if (FAIL == zbx_dbsync_compare_functions(&func_sync))
6222 		goto out;
6223 	fsec = zbx_time() - sec;
6224 
6225 	START_SYNC;
6226 	sec = zbx_time();
6227 	DCsync_functions(&func_sync);
6228 	fsec2 = zbx_time() - sec;
6229 	FINISH_SYNC;
6230 
6231 	/* sync rest of the data */
6232 
6233 	sec = zbx_time();
6234 	if (FAIL == zbx_dbsync_compare_triggers(&triggers_sync))
6235 		goto out;
6236 	tsec = zbx_time() - sec;
6237 
6238 	sec = zbx_time();
6239 	if (FAIL == zbx_dbsync_compare_trigger_dependency(&tdep_sync))
6240 		goto out;
6241 	dsec = zbx_time() - sec;
6242 
6243 	sec = zbx_time();
6244 	if (FAIL == zbx_dbsync_compare_expressions(&expr_sync))
6245 		goto out;
6246 	expr_sec = zbx_time() - sec;
6247 
6248 	sec = zbx_time();
6249 	if (FAIL == zbx_dbsync_compare_actions(&action_sync))
6250 		goto out;
6251 	action_sec = zbx_time() - sec;
6252 
6253 	sec = zbx_time();
6254 	if (FAIL == zbx_dbsync_compare_action_ops(&action_op_sync))
6255 		goto out;
6256 	action_op_sec = zbx_time() - sec;
6257 
6258 	sec = zbx_time();
6259 	if (FAIL == zbx_dbsync_compare_action_conditions(&action_condition_sync))
6260 		goto out;
6261 	action_condition_sec = zbx_time() - sec;
6262 
6263 	sec = zbx_time();
6264 	if (FAIL == zbx_dbsync_compare_trigger_tags(&trigger_tag_sync))
6265 		goto out;
6266 	trigger_tag_sec = zbx_time() - sec;
6267 
6268 	sec = zbx_time();
6269 	if (FAIL == zbx_dbsync_compare_correlations(&correlation_sync))
6270 		goto out;
6271 	correlation_sec = zbx_time() - sec;
6272 
6273 	sec = zbx_time();
6274 	if (FAIL == zbx_dbsync_compare_corr_conditions(&corr_condition_sync))
6275 		goto out;
6276 	corr_condition_sec = zbx_time() - sec;
6277 
6278 	sec = zbx_time();
6279 	if (FAIL == zbx_dbsync_compare_corr_operations(&corr_operation_sync))
6280 		goto out;
6281 	corr_operation_sec = zbx_time() - sec;
6282 
6283 	START_SYNC;
6284 
6285 	sec = zbx_time();
6286 	DCsync_triggers(&triggers_sync);
6287 	tsec2 = zbx_time() - sec;
6288 
6289 	sec = zbx_time();
6290 	DCsync_trigdeps(&tdep_sync);
6291 	dsec2 = zbx_time() - sec;
6292 
6293 	sec = zbx_time();
6294 	DCsync_expressions(&expr_sync);
6295 	expr_sec2 = zbx_time() - sec;
6296 
6297 	sec = zbx_time();
6298 	DCsync_actions(&action_sync);
6299 	action_sec2 = zbx_time() - sec;
6300 
6301 	sec = zbx_time();
6302 	DCsync_action_ops(&action_op_sync);
6303 	action_op_sec2 = zbx_time() - sec;
6304 
6305 	sec = zbx_time();
6306 	DCsync_action_conditions(&action_condition_sync);
6307 	action_condition_sec2 = zbx_time() - sec;
6308 
6309 	sec = zbx_time();
6310 	/* relies on triggers, must be after DCsync_triggers() */
6311 	DCsync_trigger_tags(&trigger_tag_sync);
6312 	trigger_tag_sec2 = zbx_time() - sec;
6313 
6314 	sec = zbx_time();
6315 	DCsync_item_tags(&item_tag_sync);
6316 	item_tag_sec2 = zbx_time() - sec;
6317 
6318 	sec = zbx_time();
6319 	DCsync_correlations(&correlation_sync);
6320 	correlation_sec2 = zbx_time() - sec;
6321 
6322 	sec = zbx_time();
6323 	/* relies on correlation rules, must be after DCsync_correlations() */
6324 	DCsync_corr_conditions(&corr_condition_sync);
6325 	corr_condition_sec2 = zbx_time() - sec;
6326 
6327 	sec = zbx_time();
6328 	/* relies on correlation rules, must be after DCsync_correlations() */
6329 	DCsync_corr_operations(&corr_operation_sync);
6330 	corr_operation_sec2 = zbx_time() - sec;
6331 
6332 	sec = zbx_time();
6333 
6334 	if (0 != hosts_sync.add_num + hosts_sync.update_num + hosts_sync.remove_num)
6335 		update_flags |= ZBX_DBSYNC_UPDATE_HOSTS;
6336 
6337 	if (0 != items_sync.add_num + items_sync.update_num + items_sync.remove_num)
6338 		update_flags |= ZBX_DBSYNC_UPDATE_ITEMS;
6339 
6340 	if (0 != func_sync.add_num + func_sync.update_num + func_sync.remove_num)
6341 		update_flags |= ZBX_DBSYNC_UPDATE_FUNCTIONS;
6342 
6343 	if (0 != triggers_sync.add_num + triggers_sync.update_num + triggers_sync.remove_num)
6344 		update_flags |= ZBX_DBSYNC_UPDATE_TRIGGERS;
6345 
6346 	if (0 != tdep_sync.add_num + tdep_sync.update_num + tdep_sync.remove_num)
6347 		update_flags |= ZBX_DBSYNC_UPDATE_TRIGGER_DEPENDENCY;
6348 
6349 	/* update trigger topology if trigger dependency was changed */
6350 	if (0 != (update_flags & ZBX_DBSYNC_UPDATE_TRIGGER_DEPENDENCY))
6351 		dc_trigger_update_topology();
6352 
6353 	/* update various trigger related links in cache */
6354 	if (0 != (update_flags & (ZBX_DBSYNC_UPDATE_HOSTS | ZBX_DBSYNC_UPDATE_ITEMS | ZBX_DBSYNC_UPDATE_FUNCTIONS |
6355 			ZBX_DBSYNC_UPDATE_TRIGGERS)))
6356 	{
6357 		dc_trigger_update_cache();
6358 		dc_schedule_trigger_timers((ZBX_DBSYNC_INIT == mode ? &trend_queue : NULL), time(NULL));
6359 	}
6360 
6361 	update_sec = zbx_time() - sec;
6362 
6363 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
6364 	{
6365 		total = csec + hsec + hisec + htsec + gmsec + hmsec + ifsec + isec + tsec + dsec + fsec + expr_sec +
6366 				action_sec + action_op_sec + action_condition_sec + trigger_tag_sec + correlation_sec +
6367 				corr_condition_sec + corr_operation_sec + hgroups_sec + itempp_sec + maintenance_sec +
6368 				item_tag_sec;
6369 		total2 = csec2 + hsec2 + hisec2 + htsec2 + gmsec2 + hmsec2 + ifsec2 + isec2 + tsec2 + dsec2 + fsec2 +
6370 				expr_sec2 + action_op_sec2 + action_sec2 + action_condition_sec2 + trigger_tag_sec2 +
6371 				correlation_sec2 + corr_condition_sec2 + corr_operation_sec2 + hgroups_sec2 +
6372 				itempp_sec2 + maintenance_sec2 + item_tag_sec2 + update_sec;
6373 
6374 		zabbix_log(LOG_LEVEL_DEBUG, "%s() config     : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6375 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6376 				__func__, csec, csec2, config_sync.add_num, config_sync.update_num,
6377 				config_sync.remove_num);
6378 
6379 		total += autoreg_csec;
6380 		total2 += autoreg_csec2;
6381 		zabbix_log(LOG_LEVEL_DEBUG, "%s() autoreg    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6382 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6383 				__func__, autoreg_csec, autoreg_csec2, autoreg_config_sync.add_num,
6384 				autoreg_config_sync.update_num, autoreg_config_sync.remove_num);
6385 
6386 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6387 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6388 				__func__, hsec, hsec2, hosts_sync.add_num, hosts_sync.update_num,
6389 				hosts_sync.remove_num);
6390 		zabbix_log(LOG_LEVEL_DEBUG, "%s() host_invent: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6391 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6392 				__func__, hisec, hisec2, hi_sync.add_num, hi_sync.update_num,
6393 				hi_sync.remove_num);
6394 		zabbix_log(LOG_LEVEL_DEBUG, "%s() templates  : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6395 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6396 				__func__, htsec, htsec2, htmpl_sync.add_num, htmpl_sync.update_num,
6397 				htmpl_sync.remove_num);
6398 		zabbix_log(LOG_LEVEL_DEBUG, "%s() globmacros : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6399 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6400 				__func__, gmsec, gmsec2, gmacro_sync.add_num, gmacro_sync.update_num,
6401 				gmacro_sync.remove_num);
6402 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hostmacros : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6403 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6404 				__func__, hmsec, hmsec2, hmacro_sync.add_num, hmacro_sync.update_num,
6405 				hmacro_sync.remove_num);
6406 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfaces : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6407 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6408 				__func__, ifsec, ifsec2, if_sync.add_num, if_sync.update_num,
6409 				if_sync.remove_num);
6410 		zabbix_log(LOG_LEVEL_DEBUG, "%s() items      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6411 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6412 				__func__, isec, isec2, items_sync.add_num, items_sync.update_num,
6413 				items_sync.remove_num);
6414 		zabbix_log(LOG_LEVEL_DEBUG, "%s() template_items      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6415 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6416 				__func__, isec, isec2, template_items_sync.add_num,
6417 				template_items_sync.update_num, template_items_sync.remove_num);
6418 		zabbix_log(LOG_LEVEL_DEBUG, "%s() prototype_items      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6419 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6420 				__func__, isec, isec2, prototype_items_sync.add_num,
6421 				prototype_items_sync.update_num, prototype_items_sync.remove_num);
6422 		zabbix_log(LOG_LEVEL_DEBUG, "%s() triggers   : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6423 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6424 				__func__, tsec, tsec2, triggers_sync.add_num, triggers_sync.update_num,
6425 				triggers_sync.remove_num);
6426 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trigdeps   : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6427 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6428 				__func__, dsec, dsec2, tdep_sync.add_num, tdep_sync.update_num,
6429 				tdep_sync.remove_num);
6430 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trig. tags : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6431 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6432 				__func__, trigger_tag_sec, trigger_tag_sec2, trigger_tag_sync.add_num,
6433 				trigger_tag_sync.update_num, trigger_tag_sync.remove_num);
6434 		zabbix_log(LOG_LEVEL_DEBUG, "%s() host tags : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6435 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6436 				__func__, host_tag_sec, host_tag_sec2, host_tag_sync.add_num,
6437 				host_tag_sync.update_num, host_tag_sync.remove_num);
6438 		zabbix_log(LOG_LEVEL_DEBUG, "%s() item tags : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6439 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6440 				__func__, item_tag_sec, item_tag_sec2, item_tag_sync.add_num,
6441 				item_tag_sync.update_num, item_tag_sync.remove_num);
6442 		zabbix_log(LOG_LEVEL_DEBUG, "%s() functions  : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6443 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6444 				__func__, fsec, fsec2, func_sync.add_num, func_sync.update_num,
6445 				func_sync.remove_num);
6446 		zabbix_log(LOG_LEVEL_DEBUG, "%s() expressions: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6447 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6448 				__func__, expr_sec, expr_sec2, expr_sync.add_num, expr_sync.update_num,
6449 				expr_sync.remove_num);
6450 		zabbix_log(LOG_LEVEL_DEBUG, "%s() actions    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6451 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6452 				__func__, action_sec, action_sec2, action_sync.add_num, action_sync.update_num,
6453 				action_sync.remove_num);
6454 		zabbix_log(LOG_LEVEL_DEBUG, "%s() operations : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6455 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6456 				__func__, action_op_sec, action_op_sec2, action_op_sync.add_num,
6457 				action_op_sync.update_num, action_op_sync.remove_num);
6458 		zabbix_log(LOG_LEVEL_DEBUG, "%s() conditions : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6459 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6460 				__func__, action_condition_sec, action_condition_sec2,
6461 				action_condition_sync.add_num, action_condition_sync.update_num,
6462 				action_condition_sync.remove_num);
6463 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr       : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6464 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6465 				__func__, correlation_sec, correlation_sec2, correlation_sync.add_num,
6466 				correlation_sync.update_num, correlation_sync.remove_num);
6467 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr_cond  : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6468 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6469 				__func__, corr_condition_sec, corr_condition_sec2, corr_condition_sync.add_num,
6470 				corr_condition_sync.update_num, corr_condition_sync.remove_num);
6471 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr_op    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6472 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6473 				__func__, corr_operation_sec, corr_operation_sec2, corr_operation_sync.add_num,
6474 				corr_operation_sync.update_num, corr_operation_sync.remove_num);
6475 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hgroups    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6476 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6477 				__func__, hgroups_sec, hgroups_sec2, hgroups_sync.add_num,
6478 				hgroups_sync.update_num, hgroups_sync.remove_num);
6479 		zabbix_log(LOG_LEVEL_DEBUG, "%s() item pproc : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6480 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6481 				__func__, itempp_sec, itempp_sec2, itempp_sync.add_num, itempp_sync.update_num,
6482 				itempp_sync.remove_num);
6483 		zabbix_log(LOG_LEVEL_DEBUG, "%s() item script param: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6484 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6485 				__func__, itemscrp_sec, itemscrp_sec2, itemscrp_sync.add_num,
6486 				itemscrp_sync.update_num, itemscrp_sync.remove_num);
6487 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maintenance: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
6488 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
6489 				__func__, maintenance_sec, maintenance_sec2, maintenance_sync.add_num,
6490 				maintenance_sync.update_num, maintenance_sync.remove_num);
6491 
6492 		zabbix_log(LOG_LEVEL_DEBUG, "%s() reindex    : " ZBX_FS_DBL " sec.", __func__, update_sec);
6493 
6494 		zabbix_log(LOG_LEVEL_DEBUG, "%s() total sql  : " ZBX_FS_DBL " sec.", __func__, total);
6495 		zabbix_log(LOG_LEVEL_DEBUG, "%s() total sync : " ZBX_FS_DBL " sec.", __func__, total2);
6496 
6497 		zabbix_log(LOG_LEVEL_DEBUG, "%s() proxies    : %d (%d slots)", __func__,
6498 				config->proxies.num_data, config->proxies.num_slots);
6499 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts      : %d (%d slots)", __func__,
6500 				config->hosts.num_data, config->hosts.num_slots);
6501 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts_h    : %d (%d slots)", __func__,
6502 				config->hosts_h.num_data, config->hosts_h.num_slots);
6503 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts_p    : %d (%d slots)", __func__,
6504 				config->hosts_p.num_data, config->hosts_p.num_slots);
6505 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
6506 		zabbix_log(LOG_LEVEL_DEBUG, "%s() psks       : %d (%d slots)", __func__,
6507 				config->psks.num_data, config->psks.num_slots);
6508 #endif
6509 		zabbix_log(LOG_LEVEL_DEBUG, "%s() ipmihosts  : %d (%d slots)", __func__,
6510 				config->ipmihosts.num_data, config->ipmihosts.num_slots);
6511 		zabbix_log(LOG_LEVEL_DEBUG, "%s() host_invent: %d (%d slots)", __func__,
6512 				config->host_inventories.num_data, config->host_inventories.num_slots);
6513 		zabbix_log(LOG_LEVEL_DEBUG, "%s() htmpls     : %d (%d slots)", __func__,
6514 				config->htmpls.num_data, config->htmpls.num_slots);
6515 		zabbix_log(LOG_LEVEL_DEBUG, "%s() gmacros    : %d (%d slots)", __func__,
6516 				config->gmacros.num_data, config->gmacros.num_slots);
6517 		zabbix_log(LOG_LEVEL_DEBUG, "%s() gmacros_m  : %d (%d slots)", __func__,
6518 				config->gmacros_m.num_data, config->gmacros_m.num_slots);
6519 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hmacros    : %d (%d slots)", __func__,
6520 				config->hmacros.num_data, config->hmacros.num_slots);
6521 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hmacros_hm : %d (%d slots)", __func__,
6522 				config->hmacros_hm.num_data, config->hmacros_hm.num_slots);
6523 		zabbix_log(LOG_LEVEL_DEBUG, "%s() kvs_paths : %d", __func__, config->kvs_paths.values_num);
6524 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfaces : %d (%d slots)", __func__,
6525 				config->interfaces.num_data, config->interfaces.num_slots);
6526 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfaces_snmp : %d (%d slots)", __func__,
6527 				config->interfaces_snmp.num_data, config->interfaces_snmp.num_slots);
6528 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfac_ht: %d (%d slots)", __func__,
6529 				config->interfaces_ht.num_data, config->interfaces_ht.num_slots);
6530 		zabbix_log(LOG_LEVEL_DEBUG, "%s() if_snmpitms: %d (%d slots)", __func__,
6531 				config->interface_snmpitems.num_data, config->interface_snmpitems.num_slots);
6532 		zabbix_log(LOG_LEVEL_DEBUG, "%s() if_snmpaddr: %d (%d slots)", __func__,
6533 				config->interface_snmpaddrs.num_data, config->interface_snmpaddrs.num_slots);
6534 		zabbix_log(LOG_LEVEL_DEBUG, "%s() items      : %d (%d slots)", __func__,
6535 				config->items.num_data, config->items.num_slots);
6536 		zabbix_log(LOG_LEVEL_DEBUG, "%s() items_hk   : %d (%d slots)", __func__,
6537 				config->items_hk.num_data, config->items_hk.num_slots);
6538 		zabbix_log(LOG_LEVEL_DEBUG, "%s() numitems   : %d (%d slots)", __func__,
6539 				config->numitems.num_data, config->numitems.num_slots);
6540 		zabbix_log(LOG_LEVEL_DEBUG, "%s() preprocitems: %d (%d slots)", __func__,
6541 				config->preprocitems.num_data, config->preprocitems.num_slots);
6542 		zabbix_log(LOG_LEVEL_DEBUG, "%s() preprocops : %d (%d slots)", __func__,
6543 				config->preprocops.num_data, config->preprocops.num_slots);
6544 		zabbix_log(LOG_LEVEL_DEBUG, "%s() snmpitems  : %d (%d slots)", __func__,
6545 				config->snmpitems.num_data, config->snmpitems.num_slots);
6546 		zabbix_log(LOG_LEVEL_DEBUG, "%s() ipmiitems  : %d (%d slots)", __func__,
6547 				config->ipmiitems.num_data, config->ipmiitems.num_slots);
6548 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trapitems  : %d (%d slots)", __func__,
6549 				config->trapitems.num_data, config->trapitems.num_slots);
6550 		zabbix_log(LOG_LEVEL_DEBUG, "%s() dependentitems  : %d (%d slots)", __func__,
6551 				config->dependentitems.num_data, config->dependentitems.num_slots);
6552 		zabbix_log(LOG_LEVEL_DEBUG, "%s() logitems   : %d (%d slots)", __func__,
6553 				config->logitems.num_data, config->logitems.num_slots);
6554 		zabbix_log(LOG_LEVEL_DEBUG, "%s() dbitems    : %d (%d slots)", __func__,
6555 				config->dbitems.num_data, config->dbitems.num_slots);
6556 		zabbix_log(LOG_LEVEL_DEBUG, "%s() sshitems   : %d (%d slots)", __func__,
6557 				config->sshitems.num_data, config->sshitems.num_slots);
6558 		zabbix_log(LOG_LEVEL_DEBUG, "%s() telnetitems: %d (%d slots)", __func__,
6559 				config->telnetitems.num_data, config->telnetitems.num_slots);
6560 		zabbix_log(LOG_LEVEL_DEBUG, "%s() simpleitems: %d (%d slots)", __func__,
6561 				config->simpleitems.num_data, config->simpleitems.num_slots);
6562 		zabbix_log(LOG_LEVEL_DEBUG, "%s() jmxitems   : %d (%d slots)", __func__,
6563 				config->jmxitems.num_data, config->jmxitems.num_slots);
6564 		zabbix_log(LOG_LEVEL_DEBUG, "%s() calcitems  : %d (%d slots)", __func__,
6565 				config->calcitems.num_data, config->calcitems.num_slots);
6566 		zabbix_log(LOG_LEVEL_DEBUG, "%s() httpitems  : %d (%d slots)", __func__,
6567 				config->httpitems.num_data, config->httpitems.num_slots);
6568 		zabbix_log(LOG_LEVEL_DEBUG, "%s() scriptitems  : %d (%d slots)", __func__,
6569 				config->scriptitems.num_data, config->scriptitems.num_slots);
6570 		zabbix_log(LOG_LEVEL_DEBUG, "%s() functions  : %d (%d slots)", __func__,
6571 				config->functions.num_data, config->functions.num_slots);
6572 		zabbix_log(LOG_LEVEL_DEBUG, "%s() triggers   : %d (%d slots)", __func__,
6573 				config->triggers.num_data, config->triggers.num_slots);
6574 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trigdeps   : %d (%d slots)", __func__,
6575 				config->trigdeps.num_data, config->trigdeps.num_slots);
6576 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trig. tags : %d (%d slots)", __func__,
6577 				config->trigger_tags.num_data, config->trigger_tags.num_slots);
6578 		zabbix_log(LOG_LEVEL_DEBUG, "%s() expressions: %d (%d slots)", __func__,
6579 				config->expressions.num_data, config->expressions.num_slots);
6580 
6581 		zabbix_log(LOG_LEVEL_DEBUG, "%s() actions    : %d (%d slots)", __func__,
6582 				config->actions.num_data, config->actions.num_slots);
6583 		zabbix_log(LOG_LEVEL_DEBUG, "%s() conditions : %d (%d slots)", __func__,
6584 				config->action_conditions.num_data, config->action_conditions.num_slots);
6585 
6586 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr.      : %d (%d slots)", __func__,
6587 				config->correlations.num_data, config->correlations.num_slots);
6588 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr. conds: %d (%d slots)", __func__,
6589 				config->corr_conditions.num_data, config->corr_conditions.num_slots);
6590 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr. ops  : %d (%d slots)", __func__,
6591 				config->corr_operations.num_data, config->corr_operations.num_slots);
6592 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hgroups    : %d (%d slots)", __func__,
6593 				config->hostgroups.num_data, config->hostgroups.num_slots);
6594 		zabbix_log(LOG_LEVEL_DEBUG, "%s() item procs : %d (%d slots)", __func__,
6595 				config->preprocops.num_data, config->preprocops.num_slots);
6596 
6597 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maintenance: %d (%d slots)", __func__,
6598 				config->maintenances.num_data, config->maintenances.num_slots);
6599 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maint tags : %d (%d slots)", __func__,
6600 				config->maintenance_tags.num_data, config->maintenance_tags.num_slots);
6601 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maint time : %d (%d slots)", __func__,
6602 				config->maintenance_periods.num_data, config->maintenance_periods.num_slots);
6603 
6604 		for (i = 0; ZBX_POLLER_TYPE_COUNT > i; i++)
6605 		{
6606 			zabbix_log(LOG_LEVEL_DEBUG, "%s() queue[%d]   : %d (%d allocated)", __func__,
6607 					i, config->queues[i].elems_num, config->queues[i].elems_alloc);
6608 		}
6609 
6610 		zabbix_log(LOG_LEVEL_DEBUG, "%s() pqueue     : %d (%d allocated)", __func__,
6611 				config->pqueue.elems_num, config->pqueue.elems_alloc);
6612 
6613 		zabbix_log(LOG_LEVEL_DEBUG, "%s() timer queue: %d (%d allocated)", __func__,
6614 				config->trigger_queue.elems_num, config->trigger_queue.elems_alloc);
6615 
6616 		zabbix_log(LOG_LEVEL_DEBUG, "%s() configfree : " ZBX_FS_DBL "%%", __func__,
6617 				100 * ((double)config_mem->free_size / config_mem->orig_size));
6618 
6619 		zabbix_log(LOG_LEVEL_DEBUG, "%s() strings    : %d (%d slots)", __func__,
6620 				config->strpool.num_data, config->strpool.num_slots);
6621 
6622 		zbx_mem_dump_stats(LOG_LEVEL_DEBUG, config_mem);
6623 	}
6624 out:
6625 	if (0 == sync_in_progress)
6626 	{
6627 		/* non recoverable database error is encountered */
6628 		THIS_SHOULD_NEVER_HAPPEN;
6629 		START_SYNC;
6630 	}
6631 
6632 	config->status->last_update = 0;
6633 	config->sync_ts = time(NULL);
6634 
6635 	FINISH_SYNC;
6636 
6637 	zbx_dbsync_clear(&config_sync);
6638 	zbx_dbsync_clear(&autoreg_config_sync);
6639 	zbx_dbsync_clear(&hosts_sync);
6640 	zbx_dbsync_clear(&hi_sync);
6641 	zbx_dbsync_clear(&htmpl_sync);
6642 	zbx_dbsync_clear(&gmacro_sync);
6643 	zbx_dbsync_clear(&hmacro_sync);
6644 	zbx_dbsync_clear(&host_tag_sync);
6645 	zbx_dbsync_clear(&if_sync);
6646 	zbx_dbsync_clear(&items_sync);
6647 	zbx_dbsync_clear(&template_items_sync);
6648 	zbx_dbsync_clear(&prototype_items_sync);
6649 	zbx_dbsync_clear(&triggers_sync);
6650 	zbx_dbsync_clear(&tdep_sync);
6651 	zbx_dbsync_clear(&func_sync);
6652 	zbx_dbsync_clear(&expr_sync);
6653 	zbx_dbsync_clear(&action_sync);
6654 	zbx_dbsync_clear(&action_op_sync);
6655 	zbx_dbsync_clear(&action_condition_sync);
6656 	zbx_dbsync_clear(&trigger_tag_sync);
6657 	zbx_dbsync_clear(&correlation_sync);
6658 	zbx_dbsync_clear(&corr_condition_sync);
6659 	zbx_dbsync_clear(&corr_operation_sync);
6660 	zbx_dbsync_clear(&hgroups_sync);
6661 	zbx_dbsync_clear(&itempp_sync);
6662 	zbx_dbsync_clear(&itemscrp_sync);
6663 	zbx_dbsync_clear(&item_tag_sync);
6664 	zbx_dbsync_clear(&maintenance_sync);
6665 	zbx_dbsync_clear(&maintenance_period_sync);
6666 	zbx_dbsync_clear(&maintenance_tag_sync);
6667 	zbx_dbsync_clear(&maintenance_group_sync);
6668 	zbx_dbsync_clear(&maintenance_host_sync);
6669 	zbx_dbsync_clear(&hgroup_host_sync);
6670 
6671 	if (ZBX_DBSYNC_INIT == mode)
6672 		zbx_hashset_destroy(&trend_queue);
6673 
6674 	zbx_dbsync_free_env();
6675 skip:
6676 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_TRACE))
6677 		DCdump_configuration();
6678 
6679 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
6680 }
6681 
6682 /******************************************************************************
6683  *                                                                            *
6684  * Helper functions for configuration cache data structure element comparison *
6685  * and hash value calculation.                                                *
6686  *                                                                            *
6687  * The __config_mem_XXX_func(), __config_XXX_hash and __config_XXX_compare    *
6688  * functions are used only inside init_configuration_cache() function to      *
6689  * initialize internal data structures.                                       *
6690  *                                                                            *
6691  ******************************************************************************/
6692 
__config_item_hk_hash(const void * data)6693 static zbx_hash_t	__config_item_hk_hash(const void *data)
6694 {
6695 	const ZBX_DC_ITEM_HK	*item_hk = (const ZBX_DC_ITEM_HK *)data;
6696 
6697 	zbx_hash_t		hash;
6698 
6699 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&item_hk->hostid);
6700 	hash = ZBX_DEFAULT_STRING_HASH_ALGO(item_hk->key, strlen(item_hk->key), hash);
6701 
6702 	return hash;
6703 }
6704 
__config_item_hk_compare(const void * d1,const void * d2)6705 static int	__config_item_hk_compare(const void *d1, const void *d2)
6706 {
6707 	const ZBX_DC_ITEM_HK	*item_hk_1 = (const ZBX_DC_ITEM_HK *)d1;
6708 	const ZBX_DC_ITEM_HK	*item_hk_2 = (const ZBX_DC_ITEM_HK *)d2;
6709 
6710 	ZBX_RETURN_IF_NOT_EQUAL(item_hk_1->hostid, item_hk_2->hostid);
6711 
6712 	return item_hk_1->key == item_hk_2->key ? 0 : strcmp(item_hk_1->key, item_hk_2->key);
6713 }
6714 
__config_host_h_hash(const void * data)6715 static zbx_hash_t	__config_host_h_hash(const void *data)
6716 {
6717 	const ZBX_DC_HOST_H	*host_h = (const ZBX_DC_HOST_H *)data;
6718 
6719 	return ZBX_DEFAULT_STRING_HASH_ALGO(host_h->host, strlen(host_h->host), ZBX_DEFAULT_HASH_SEED);
6720 }
6721 
__config_host_h_compare(const void * d1,const void * d2)6722 static int	__config_host_h_compare(const void *d1, const void *d2)
6723 {
6724 	const ZBX_DC_HOST_H	*host_h_1 = (const ZBX_DC_HOST_H *)d1;
6725 	const ZBX_DC_HOST_H	*host_h_2 = (const ZBX_DC_HOST_H *)d2;
6726 
6727 	return host_h_1->host == host_h_2->host ? 0 : strcmp(host_h_1->host, host_h_2->host);
6728 }
6729 
__config_gmacro_m_hash(const void * data)6730 static zbx_hash_t	__config_gmacro_m_hash(const void *data)
6731 {
6732 	const ZBX_DC_GMACRO_M	*gmacro_m = (const ZBX_DC_GMACRO_M *)data;
6733 
6734 	zbx_hash_t		hash;
6735 
6736 	hash = ZBX_DEFAULT_STRING_HASH_FUNC(gmacro_m->macro);
6737 
6738 	return hash;
6739 }
6740 
__config_gmacro_m_compare(const void * d1,const void * d2)6741 static int	__config_gmacro_m_compare(const void *d1, const void *d2)
6742 {
6743 	const ZBX_DC_GMACRO_M	*gmacro_m_1 = (const ZBX_DC_GMACRO_M *)d1;
6744 	const ZBX_DC_GMACRO_M	*gmacro_m_2 = (const ZBX_DC_GMACRO_M *)d2;
6745 
6746 	return gmacro_m_1->macro == gmacro_m_2->macro ? 0 : strcmp(gmacro_m_1->macro, gmacro_m_2->macro);
6747 }
6748 
__config_hmacro_hm_hash(const void * data)6749 static zbx_hash_t	__config_hmacro_hm_hash(const void *data)
6750 {
6751 	const ZBX_DC_HMACRO_HM	*hmacro_hm = (const ZBX_DC_HMACRO_HM *)data;
6752 
6753 	zbx_hash_t		hash;
6754 
6755 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&hmacro_hm->hostid);
6756 	hash = ZBX_DEFAULT_STRING_HASH_ALGO(hmacro_hm->macro, strlen(hmacro_hm->macro), hash);
6757 
6758 	return hash;
6759 }
6760 
__config_hmacro_hm_compare(const void * d1,const void * d2)6761 static int	__config_hmacro_hm_compare(const void *d1, const void *d2)
6762 {
6763 	const ZBX_DC_HMACRO_HM	*hmacro_hm_1 = (const ZBX_DC_HMACRO_HM *)d1;
6764 	const ZBX_DC_HMACRO_HM	*hmacro_hm_2 = (const ZBX_DC_HMACRO_HM *)d2;
6765 
6766 	ZBX_RETURN_IF_NOT_EQUAL(hmacro_hm_1->hostid, hmacro_hm_2->hostid);
6767 
6768 	return hmacro_hm_1->macro == hmacro_hm_2->macro ? 0 : strcmp(hmacro_hm_1->macro, hmacro_hm_2->macro);
6769 }
6770 
__config_interface_ht_hash(const void * data)6771 static zbx_hash_t	__config_interface_ht_hash(const void *data)
6772 {
6773 	const ZBX_DC_INTERFACE_HT	*interface_ht = (const ZBX_DC_INTERFACE_HT *)data;
6774 
6775 	zbx_hash_t			hash;
6776 
6777 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&interface_ht->hostid);
6778 	hash = ZBX_DEFAULT_STRING_HASH_ALGO((char *)&interface_ht->type, 1, hash);
6779 
6780 	return hash;
6781 }
6782 
__config_interface_ht_compare(const void * d1,const void * d2)6783 static int	__config_interface_ht_compare(const void *d1, const void *d2)
6784 {
6785 	const ZBX_DC_INTERFACE_HT	*interface_ht_1 = (const ZBX_DC_INTERFACE_HT *)d1;
6786 	const ZBX_DC_INTERFACE_HT	*interface_ht_2 = (const ZBX_DC_INTERFACE_HT *)d2;
6787 
6788 	ZBX_RETURN_IF_NOT_EQUAL(interface_ht_1->hostid, interface_ht_2->hostid);
6789 	ZBX_RETURN_IF_NOT_EQUAL(interface_ht_1->type, interface_ht_2->type);
6790 
6791 	return 0;
6792 }
6793 
__config_interface_addr_hash(const void * data)6794 static zbx_hash_t	__config_interface_addr_hash(const void *data)
6795 {
6796 	const ZBX_DC_INTERFACE_ADDR	*interface_addr = (const ZBX_DC_INTERFACE_ADDR *)data;
6797 
6798 	return ZBX_DEFAULT_STRING_HASH_ALGO(interface_addr->addr, strlen(interface_addr->addr), ZBX_DEFAULT_HASH_SEED);
6799 }
6800 
__config_interface_addr_compare(const void * d1,const void * d2)6801 static int	__config_interface_addr_compare(const void *d1, const void *d2)
6802 {
6803 	const ZBX_DC_INTERFACE_ADDR	*interface_addr_1 = (const ZBX_DC_INTERFACE_ADDR *)d1;
6804 	const ZBX_DC_INTERFACE_ADDR	*interface_addr_2 = (const ZBX_DC_INTERFACE_ADDR *)d2;
6805 
6806 	return (interface_addr_1->addr == interface_addr_2->addr ? 0 : strcmp(interface_addr_1->addr, interface_addr_2->addr));
6807 }
6808 
__config_snmp_item_compare(const ZBX_DC_ITEM * i1,const ZBX_DC_ITEM * i2)6809 static int	__config_snmp_item_compare(const ZBX_DC_ITEM *i1, const ZBX_DC_ITEM *i2)
6810 {
6811 	const ZBX_DC_SNMPITEM	*s1;
6812 	const ZBX_DC_SNMPITEM	*s2;
6813 
6814 	unsigned char		f1;
6815 	unsigned char		f2;
6816 
6817 	ZBX_RETURN_IF_NOT_EQUAL(i1->interfaceid, i2->interfaceid);
6818 	ZBX_RETURN_IF_NOT_EQUAL(i1->type, i2->type);
6819 
6820 	f1 = ZBX_FLAG_DISCOVERY_RULE & i1->flags;
6821 	f2 = ZBX_FLAG_DISCOVERY_RULE & i2->flags;
6822 
6823 	ZBX_RETURN_IF_NOT_EQUAL(f1, f2);
6824 
6825 	s1 = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &i1->itemid);
6826 	s2 = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &i2->itemid);
6827 
6828 	ZBX_RETURN_IF_NOT_EQUAL(s1->snmp_oid_type, s2->snmp_oid_type);
6829 
6830 	return 0;
6831 }
6832 
__config_heap_elem_compare(const void * d1,const void * d2)6833 static int	__config_heap_elem_compare(const void *d1, const void *d2)
6834 {
6835 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
6836 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6837 
6838 	const ZBX_DC_ITEM		*i1 = (const ZBX_DC_ITEM *)e1->data;
6839 	const ZBX_DC_ITEM		*i2 = (const ZBX_DC_ITEM *)e2->data;
6840 
6841 	ZBX_RETURN_IF_NOT_EQUAL(i1->nextcheck, i2->nextcheck);
6842 	ZBX_RETURN_IF_NOT_EQUAL(i1->queue_priority, i2->queue_priority);
6843 
6844 	if (ITEM_TYPE_SNMP != i1->type)
6845 	{
6846 		if (ITEM_TYPE_SNMP != i2->type)
6847 			return 0;
6848 
6849 		return -1;
6850 	}
6851 	else
6852 	{
6853 		if (ITEM_TYPE_SNMP != i2->type)
6854 			return +1;
6855 
6856 		return __config_snmp_item_compare(i1, i2);
6857 	}
6858 }
6859 
__config_pinger_elem_compare(const void * d1,const void * d2)6860 static int	__config_pinger_elem_compare(const void *d1, const void *d2)
6861 {
6862 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
6863 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6864 
6865 	const ZBX_DC_ITEM		*i1 = (const ZBX_DC_ITEM *)e1->data;
6866 	const ZBX_DC_ITEM		*i2 = (const ZBX_DC_ITEM *)e2->data;
6867 
6868 	ZBX_RETURN_IF_NOT_EQUAL(i1->nextcheck, i2->nextcheck);
6869 	ZBX_RETURN_IF_NOT_EQUAL(i1->queue_priority, i2->queue_priority);
6870 	ZBX_RETURN_IF_NOT_EQUAL(i1->interfaceid, i2->interfaceid);
6871 
6872 	return 0;
6873 }
6874 
__config_java_item_compare(const ZBX_DC_ITEM * i1,const ZBX_DC_ITEM * i2)6875 static int	__config_java_item_compare(const ZBX_DC_ITEM *i1, const ZBX_DC_ITEM *i2)
6876 {
6877 	const ZBX_DC_JMXITEM	*j1;
6878 	const ZBX_DC_JMXITEM	*j2;
6879 
6880 	ZBX_RETURN_IF_NOT_EQUAL(i1->interfaceid, i2->interfaceid);
6881 
6882 	j1 = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &i1->itemid);
6883 	j2 = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &i2->itemid);
6884 
6885 	ZBX_RETURN_IF_NOT_EQUAL(j1->username, j2->username);
6886 	ZBX_RETURN_IF_NOT_EQUAL(j1->password, j2->password);
6887 	ZBX_RETURN_IF_NOT_EQUAL(j1->jmx_endpoint, j2->jmx_endpoint);
6888 
6889 	return 0;
6890 }
6891 
__config_java_elem_compare(const void * d1,const void * d2)6892 static int	__config_java_elem_compare(const void *d1, const void *d2)
6893 {
6894 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
6895 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6896 
6897 	const ZBX_DC_ITEM		*i1 = (const ZBX_DC_ITEM *)e1->data;
6898 	const ZBX_DC_ITEM		*i2 = (const ZBX_DC_ITEM *)e2->data;
6899 
6900 	ZBX_RETURN_IF_NOT_EQUAL(i1->nextcheck, i2->nextcheck);
6901 	ZBX_RETURN_IF_NOT_EQUAL(i1->queue_priority, i2->queue_priority);
6902 
6903 	return __config_java_item_compare(i1, i2);
6904 }
6905 
__config_proxy_compare(const void * d1,const void * d2)6906 static int	__config_proxy_compare(const void *d1, const void *d2)
6907 {
6908 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
6909 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6910 
6911 	const ZBX_DC_PROXY		*p1 = (const ZBX_DC_PROXY *)e1->data;
6912 	const ZBX_DC_PROXY		*p2 = (const ZBX_DC_PROXY *)e2->data;
6913 
6914 	ZBX_RETURN_IF_NOT_EQUAL(p1->nextcheck, p2->nextcheck);
6915 
6916 	return 0;
6917 }
6918 
6919 /* hash and compare functions for expressions hashset */
6920 
__config_regexp_hash(const void * data)6921 static zbx_hash_t	__config_regexp_hash(const void *data)
6922 {
6923 	const ZBX_DC_REGEXP	*regexp = (const ZBX_DC_REGEXP *)data;
6924 
6925 	return ZBX_DEFAULT_STRING_HASH_FUNC(regexp->name);
6926 }
6927 
__config_regexp_compare(const void * d1,const void * d2)6928 static int	__config_regexp_compare(const void *d1, const void *d2)
6929 {
6930 	const ZBX_DC_REGEXP	*r1 = (const ZBX_DC_REGEXP *)d1;
6931 	const ZBX_DC_REGEXP	*r2 = (const ZBX_DC_REGEXP *)d2;
6932 
6933 	return r1->name == r2->name ? 0 : strcmp(r1->name, r2->name);
6934 }
6935 
6936 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
__config_psk_hash(const void * data)6937 static zbx_hash_t	__config_psk_hash(const void *data)
6938 {
6939 	const ZBX_DC_PSK	*psk_i = (const ZBX_DC_PSK *)data;
6940 
6941 	return ZBX_DEFAULT_STRING_HASH_ALGO(psk_i->tls_psk_identity, strlen(psk_i->tls_psk_identity),
6942 			ZBX_DEFAULT_HASH_SEED);
6943 }
6944 
__config_psk_compare(const void * d1,const void * d2)6945 static int	__config_psk_compare(const void *d1, const void *d2)
6946 {
6947 	const ZBX_DC_PSK	*psk_1 = (const ZBX_DC_PSK *)d1;
6948 	const ZBX_DC_PSK	*psk_2 = (const ZBX_DC_PSK *)d2;
6949 
6950 	return psk_1->tls_psk_identity == psk_2->tls_psk_identity ? 0 : strcmp(psk_1->tls_psk_identity,
6951 			psk_2->tls_psk_identity);
6952 }
6953 #endif
6954 
__config_timer_compare(const void * d1,const void * d2)6955 static int	__config_timer_compare(const void *d1, const void *d2)
6956 {
6957 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
6958 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6959 
6960 	const zbx_trigger_timer_t	*t1 = (const zbx_trigger_timer_t *)e1->data;
6961 	const zbx_trigger_timer_t	*t2 = (const zbx_trigger_timer_t *)e2->data;
6962 
6963 	int	ret;
6964 
6965 	if (0 != (ret = zbx_timespec_compare(&t1->exec_ts, &t2->exec_ts)))
6966 		return ret;
6967 
6968 	ZBX_RETURN_IF_NOT_EQUAL(t1->triggerid, t2->triggerid);
6969 
6970 	if (0 != (ret = zbx_timespec_compare(&t1->eval_ts, &t2->eval_ts)))
6971 		return ret;
6972 
6973 	return 0;
6974 }
6975 
__config_data_session_hash(const void * data)6976 static zbx_hash_t	__config_data_session_hash(const void *data)
6977 {
6978 	const zbx_data_session_t	*session = (const zbx_data_session_t *)data;
6979 	zbx_hash_t			hash;
6980 
6981 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&session->hostid);
6982 	return ZBX_DEFAULT_STRING_HASH_ALGO(session->token, strlen(session->token), hash);
6983 }
6984 
__config_data_session_compare(const void * d1,const void * d2)6985 static int	__config_data_session_compare(const void *d1, const void *d2)
6986 {
6987 	const zbx_data_session_t	*s1 = (const zbx_data_session_t *)d1;
6988 	const zbx_data_session_t	*s2 = (const zbx_data_session_t *)d2;
6989 
6990 	ZBX_RETURN_IF_NOT_EQUAL(s1->hostid, s2->hostid);
6991 	return strcmp(s1->token, s2->token);
6992 }
6993 
6994 /******************************************************************************
6995  *                                                                            *
6996  * Function: init_configuration_cache                                         *
6997  *                                                                            *
6998  * Purpose: Allocate shared memory for configuration cache                    *
6999  *                                                                            *
7000  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
7001  *                                                                            *
7002  ******************************************************************************/
init_configuration_cache(char ** error)7003 int	init_configuration_cache(char **error)
7004 {
7005 	int	i, ret;
7006 
7007 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() size:" ZBX_FS_UI64, __func__, CONFIG_CONF_CACHE_SIZE);
7008 
7009 	if (SUCCEED != (ret = zbx_rwlock_create(&config_lock, ZBX_RWLOCK_CONFIG, error)))
7010 		goto out;
7011 
7012 	if (SUCCEED != (ret = zbx_mem_create(&config_mem, CONFIG_CONF_CACHE_SIZE, "configuration cache",
7013 			"CacheSize", 0, error)))
7014 	{
7015 		goto out;
7016 	}
7017 
7018 	config = (ZBX_DC_CONFIG *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_CONFIG) +
7019 			CONFIG_TIMER_FORKS * sizeof(zbx_vector_ptr_t));
7020 
7021 #define CREATE_HASHSET(hashset, hashset_size)									\
7022 														\
7023 	CREATE_HASHSET_EXT(hashset, hashset_size, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC)
7024 
7025 #define CREATE_HASHSET_EXT(hashset, hashset_size, hash_func, compare_func)					\
7026 														\
7027 	zbx_hashset_create_ext(&hashset, hashset_size, hash_func, compare_func, NULL,				\
7028 			__config_mem_malloc_func, __config_mem_realloc_func, __config_mem_free_func)
7029 
7030 	CREATE_HASHSET(config->items, 100);
7031 	CREATE_HASHSET(config->numitems, 0);
7032 	CREATE_HASHSET(config->snmpitems, 0);
7033 	CREATE_HASHSET(config->ipmiitems, 0);
7034 	CREATE_HASHSET(config->trapitems, 0);
7035 	CREATE_HASHSET(config->dependentitems, 0);
7036 	CREATE_HASHSET(config->logitems, 0);
7037 	CREATE_HASHSET(config->dbitems, 0);
7038 	CREATE_HASHSET(config->sshitems, 0);
7039 	CREATE_HASHSET(config->telnetitems, 0);
7040 	CREATE_HASHSET(config->simpleitems, 0);
7041 	CREATE_HASHSET(config->jmxitems, 0);
7042 	CREATE_HASHSET(config->calcitems, 0);
7043 	CREATE_HASHSET(config->masteritems, 0);
7044 	CREATE_HASHSET(config->preprocitems, 0);
7045 	CREATE_HASHSET(config->httpitems, 0);
7046 	CREATE_HASHSET(config->scriptitems, 0);
7047 	CREATE_HASHSET(config->itemscript_params, 0);
7048 	CREATE_HASHSET(config->template_items, 0);
7049 	CREATE_HASHSET(config->prototype_items, 0);
7050 	CREATE_HASHSET(config->functions, 100);
7051 	CREATE_HASHSET(config->triggers, 100);
7052 	CREATE_HASHSET(config->trigdeps, 0);
7053 	CREATE_HASHSET(config->hosts, 10);
7054 	CREATE_HASHSET(config->proxies, 0);
7055 	CREATE_HASHSET(config->host_inventories, 0);
7056 	CREATE_HASHSET(config->host_inventories_auto, 0);
7057 	CREATE_HASHSET(config->ipmihosts, 0);
7058 	CREATE_HASHSET(config->htmpls, 0);
7059 	CREATE_HASHSET(config->gmacros, 0);
7060 	CREATE_HASHSET(config->hmacros, 0);
7061 	CREATE_HASHSET(config->interfaces, 10);
7062 	CREATE_HASHSET(config->interfaces_snmp, 0);
7063 	CREATE_HASHSET(config->interface_snmpitems, 0);
7064 	CREATE_HASHSET(config->expressions, 0);
7065 	CREATE_HASHSET(config->actions, 0);
7066 	CREATE_HASHSET(config->action_conditions, 0);
7067 	CREATE_HASHSET(config->trigger_tags, 0);
7068 	CREATE_HASHSET(config->item_tags, 0);
7069 	CREATE_HASHSET(config->host_tags, 0);
7070 	CREATE_HASHSET(config->host_tags_index, 0);
7071 	CREATE_HASHSET(config->correlations, 0);
7072 	CREATE_HASHSET(config->corr_conditions, 0);
7073 	CREATE_HASHSET(config->corr_operations, 0);
7074 	CREATE_HASHSET(config->hostgroups, 0);
7075 	zbx_vector_ptr_create_ext(&config->hostgroups_name, __config_mem_malloc_func, __config_mem_realloc_func,
7076 			__config_mem_free_func);
7077 	zbx_vector_ptr_create_ext(&config->kvs_paths, __config_mem_malloc_func, __config_mem_realloc_func,
7078 			__config_mem_free_func);
7079 
7080 	CREATE_HASHSET(config->preprocops, 0);
7081 
7082 	CREATE_HASHSET(config->maintenances, 0);
7083 	CREATE_HASHSET(config->maintenance_periods, 0);
7084 	CREATE_HASHSET(config->maintenance_tags, 0);
7085 
7086 	CREATE_HASHSET_EXT(config->items_hk, 100, __config_item_hk_hash, __config_item_hk_compare);
7087 	CREATE_HASHSET_EXT(config->hosts_h, 10, __config_host_h_hash, __config_host_h_compare);
7088 	CREATE_HASHSET_EXT(config->hosts_p, 0, __config_host_h_hash, __config_host_h_compare);
7089 	CREATE_HASHSET_EXT(config->gmacros_m, 0, __config_gmacro_m_hash, __config_gmacro_m_compare);
7090 	CREATE_HASHSET_EXT(config->hmacros_hm, 0, __config_hmacro_hm_hash, __config_hmacro_hm_compare);
7091 	CREATE_HASHSET_EXT(config->interfaces_ht, 10, __config_interface_ht_hash, __config_interface_ht_compare);
7092 	CREATE_HASHSET_EXT(config->interface_snmpaddrs, 0, __config_interface_addr_hash, __config_interface_addr_compare);
7093 	CREATE_HASHSET_EXT(config->regexps, 0, __config_regexp_hash, __config_regexp_compare);
7094 
7095 	CREATE_HASHSET_EXT(config->strpool, 100, __config_strpool_hash, __config_strpool_compare);
7096 
7097 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
7098 	CREATE_HASHSET_EXT(config->psks, 0, __config_psk_hash, __config_psk_compare);
7099 #endif
7100 
7101 	for (i = 0; i < ZBX_POLLER_TYPE_COUNT; i++)
7102 	{
7103 		switch (i)
7104 		{
7105 			case ZBX_POLLER_TYPE_JAVA:
7106 				zbx_binary_heap_create_ext(&config->queues[i],
7107 						__config_java_elem_compare,
7108 						ZBX_BINARY_HEAP_OPTION_DIRECT,
7109 						__config_mem_malloc_func,
7110 						__config_mem_realloc_func,
7111 						__config_mem_free_func);
7112 				break;
7113 			case ZBX_POLLER_TYPE_PINGER:
7114 				zbx_binary_heap_create_ext(&config->queues[i],
7115 						__config_pinger_elem_compare,
7116 						ZBX_BINARY_HEAP_OPTION_DIRECT,
7117 						__config_mem_malloc_func,
7118 						__config_mem_realloc_func,
7119 						__config_mem_free_func);
7120 				break;
7121 			default:
7122 				zbx_binary_heap_create_ext(&config->queues[i],
7123 						__config_heap_elem_compare,
7124 						ZBX_BINARY_HEAP_OPTION_DIRECT,
7125 						__config_mem_malloc_func,
7126 						__config_mem_realloc_func,
7127 						__config_mem_free_func);
7128 				break;
7129 		}
7130 	}
7131 
7132 	zbx_binary_heap_create_ext(&config->pqueue,
7133 					__config_proxy_compare,
7134 					ZBX_BINARY_HEAP_OPTION_DIRECT,
7135 					__config_mem_malloc_func,
7136 					__config_mem_realloc_func,
7137 					__config_mem_free_func);
7138 
7139 	zbx_binary_heap_create_ext(&config->trigger_queue,
7140 					__config_timer_compare,
7141 					ZBX_BINARY_HEAP_OPTION_EMPTY,
7142 					__config_mem_malloc_func,
7143 					__config_mem_realloc_func,
7144 					__config_mem_free_func);
7145 
7146 	CREATE_HASHSET_EXT(config->data_sessions, 0, __config_data_session_hash, __config_data_session_compare);
7147 
7148 	config->config = NULL;
7149 
7150 	config->status = (ZBX_DC_STATUS *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_STATUS));
7151 	config->status->last_update = 0;
7152 
7153 	config->availability_diff_ts = 0;
7154 	config->sync_ts = 0;
7155 	config->item_sync_ts = 0;
7156 	config->sync_start_ts = 0;
7157 
7158 	config->internal_actions = 0;
7159 
7160 	/* maintenance data are used only when timers are defined (server) */
7161 	if (0 != CONFIG_TIMER_FORKS)
7162 	{
7163 		config->maintenance_update = ZBX_MAINTENANCE_UPDATE_FALSE;
7164 		config->maintenance_update_flags = (zbx_uint64_t *)__config_mem_malloc_func(NULL, sizeof(zbx_uint64_t) *
7165 				ZBX_MAINTENANCE_UPDATE_FLAGS_NUM());
7166 		memset(config->maintenance_update_flags, 0, sizeof(zbx_uint64_t) * ZBX_MAINTENANCE_UPDATE_FLAGS_NUM());
7167 	}
7168 
7169 	config->proxy_lastaccess_ts = time(NULL);
7170 
7171 	/* create data session token for proxies */
7172 	if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
7173 	{
7174 		char	*token;
7175 
7176 		token = zbx_create_token(0);
7177 		config->session_token = dc_strdup(token);
7178 		zbx_free(token);
7179 	}
7180 	else
7181 		config->session_token = NULL;
7182 
7183 #undef CREATE_HASHSET
7184 #undef CREATE_HASHSET_EXT
7185 out:
7186 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
7187 
7188 	return ret;
7189 }
7190 
7191 /******************************************************************************
7192  *                                                                            *
7193  * Function: free_configuration_cache                                         *
7194  *                                                                            *
7195  * Purpose: Free memory allocated for configuration cache                     *
7196  *                                                                            *
7197  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
7198  *                                                                            *
7199  ******************************************************************************/
free_configuration_cache(void)7200 void	free_configuration_cache(void)
7201 {
7202 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
7203 
7204 	WRLOCK_CACHE;
7205 
7206 	config = NULL;
7207 
7208 	UNLOCK_CACHE;
7209 
7210 	zbx_rwlock_destroy(&config_lock);
7211 
7212 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
7213 }
7214 
7215 /******************************************************************************
7216  *                                                                            *
7217  * Function: in_maintenance_without_data_collection                           *
7218  *                                                                            *
7219  * Parameters: maintenance_status - [IN] maintenance status                   *
7220  *                                       HOST_MAINTENANCE_STATUS_* flag       *
7221  *             maintenance_type   - [IN] maintenance type                     *
7222  *                                       MAINTENANCE_TYPE_* flag              *
7223  *             type               - [IN] item type                            *
7224  *                                       ITEM_TYPE_* flag                     *
7225  *                                                                            *
7226  * Return value: SUCCEED if host in maintenance without data collection       *
7227  *               FAIL otherwise                                               *
7228  *                                                                            *
7229  ******************************************************************************/
in_maintenance_without_data_collection(unsigned char maintenance_status,unsigned char maintenance_type,unsigned char type)7230 int	in_maintenance_without_data_collection(unsigned char maintenance_status, unsigned char maintenance_type,
7231 		unsigned char type)
7232 {
7233 	if (HOST_MAINTENANCE_STATUS_ON != maintenance_status)
7234 		return FAIL;
7235 
7236 	if (MAINTENANCE_TYPE_NODATA != maintenance_type)
7237 		return FAIL;
7238 
7239 	if (ITEM_TYPE_INTERNAL == type)
7240 		return FAIL;
7241 
7242 	return SUCCEED;
7243 }
7244 
DCget_host(DC_HOST * dst_host,const ZBX_DC_HOST * src_host,unsigned int mode)7245 static void	DCget_host(DC_HOST *dst_host, const ZBX_DC_HOST *src_host, unsigned int mode)
7246 {
7247 	const ZBX_DC_IPMIHOST		*ipmihost;
7248 	const ZBX_DC_HOST_INVENTORY	*host_inventory;
7249 
7250 	dst_host->hostid = src_host->hostid;
7251 	dst_host->proxy_hostid = src_host->proxy_hostid;
7252 	dst_host->status = src_host->status;
7253 
7254 	strscpy(dst_host->host, src_host->host);
7255 
7256 	if (ZBX_ITEM_GET_HOSTNAME & mode)
7257 		zbx_strlcpy_utf8(dst_host->name, src_host->name, sizeof(dst_host->name));
7258 
7259 	if (ZBX_ITEM_GET_MAINTENANCE & mode)
7260 	{
7261 		dst_host->maintenance_status = src_host->maintenance_status;
7262 		dst_host->maintenance_type = src_host->maintenance_type;
7263 		dst_host->maintenance_from = src_host->maintenance_from;
7264 	}
7265 
7266 	if (ZBX_ITEM_GET_HOSTINFO & mode)
7267 	{
7268 		dst_host->tls_connect = src_host->tls_connect;
7269 		dst_host->tls_accept = src_host->tls_accept;
7270 	#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
7271 		strscpy(dst_host->tls_issuer, src_host->tls_issuer);
7272 		strscpy(dst_host->tls_subject, src_host->tls_subject);
7273 
7274 		if (NULL == src_host->tls_dc_psk)
7275 		{
7276 			*dst_host->tls_psk_identity = '\0';
7277 			*dst_host->tls_psk = '\0';
7278 		}
7279 		else
7280 		{
7281 			strscpy(dst_host->tls_psk_identity, src_host->tls_dc_psk->tls_psk_identity);
7282 			strscpy(dst_host->tls_psk, src_host->tls_dc_psk->tls_psk);
7283 		}
7284 	#endif
7285 		if (NULL != (ipmihost = (ZBX_DC_IPMIHOST *)zbx_hashset_search(&config->ipmihosts, &src_host->hostid)))
7286 		{
7287 			dst_host->ipmi_authtype = ipmihost->ipmi_authtype;
7288 			dst_host->ipmi_privilege = ipmihost->ipmi_privilege;
7289 			strscpy(dst_host->ipmi_username, ipmihost->ipmi_username);
7290 			strscpy(dst_host->ipmi_password, ipmihost->ipmi_password);
7291 		}
7292 		else
7293 		{
7294 			dst_host->ipmi_authtype = ZBX_IPMI_DEFAULT_AUTHTYPE;
7295 			dst_host->ipmi_privilege = ZBX_IPMI_DEFAULT_PRIVILEGE;
7296 			*dst_host->ipmi_username = '\0';
7297 			*dst_host->ipmi_password = '\0';
7298 		}
7299 	}
7300 
7301 	if (ZBX_ITEM_GET_INVENTORY & mode)
7302 	{
7303 		if (NULL != (host_inventory = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories, &src_host->hostid)))
7304 			dst_host->inventory_mode = (char)host_inventory->inventory_mode;
7305 		else
7306 			dst_host->inventory_mode = HOST_INVENTORY_DISABLED;
7307 	}
7308 }
7309 
7310 /******************************************************************************
7311  *                                                                            *
7312  * Function: DCget_host_by_hostid                                             *
7313  *                                                                            *
7314  * Purpose: Locate host in configuration cache                                *
7315  *                                                                            *
7316  * Parameters: host - [OUT] pointer to DC_HOST structure                      *
7317  *             hostid - [IN] host ID from database                            *
7318  *                                                                            *
7319  * Return value: SUCCEED if record located and FAIL otherwise                 *
7320  *                                                                            *
7321  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
7322  *                                                                            *
7323  ******************************************************************************/
DCget_host_by_hostid(DC_HOST * host,zbx_uint64_t hostid)7324 int	DCget_host_by_hostid(DC_HOST *host, zbx_uint64_t hostid)
7325 {
7326 	int			ret = FAIL;
7327 	const ZBX_DC_HOST	*dc_host;
7328 
7329 	RDLOCK_CACHE;
7330 
7331 	if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
7332 	{
7333 		DCget_host(host, dc_host, ZBX_ITEM_GET_ALL);
7334 		ret = SUCCEED;
7335 	}
7336 
7337 	UNLOCK_CACHE;
7338 
7339 	return ret;
7340 }
7341 
7342 /******************************************************************************
7343  *                                                                            *
7344  * Function: DCcheck_proxy_permissions                                        *
7345  *                                                                            *
7346  * Purpose:                                                                   *
7347  *     Check access rights for an active proxy and get the proxy ID           *
7348  *                                                                            *
7349  * Parameters:                                                                *
7350  *     host   - [IN] proxy name                                               *
7351  *     sock   - [IN] connection socket context                                *
7352  *     hostid - [OUT] proxy ID found in configuration cache                   *
7353  *     error  - [OUT] error message why access was denied                     *
7354  *                                                                            *
7355  * Return value:                                                              *
7356  *     SUCCEED - access is allowed, FAIL - access denied                      *
7357  *                                                                            *
7358  * Comments:                                                                  *
7359  *     Generating of error messages is done outside of configuration cache    *
7360  *     locking.                                                               *
7361  *                                                                            *
7362  ******************************************************************************/
DCcheck_proxy_permissions(const char * host,const zbx_socket_t * sock,zbx_uint64_t * hostid,char ** error)7363 int	DCcheck_proxy_permissions(const char *host, const zbx_socket_t *sock, zbx_uint64_t *hostid, char **error)
7364 {
7365 	const ZBX_DC_HOST	*dc_host;
7366 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
7367 	zbx_tls_conn_attr_t	attr;
7368 
7369 	if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type)
7370 	{
7371 		if (SUCCEED != zbx_tls_get_attr_cert(sock, &attr))
7372 		{
7373 			*error = zbx_strdup(*error, "internal error: cannot get connection attributes");
7374 			THIS_SHOULD_NEVER_HAPPEN;
7375 			return FAIL;
7376 		}
7377 	}
7378 #if defined(HAVE_GNUTLS) || (defined(HAVE_OPENSSL) && defined(HAVE_OPENSSL_WITH_PSK))
7379 	else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type)
7380 	{
7381 		if (SUCCEED != zbx_tls_get_attr_psk(sock, &attr))
7382 		{
7383 			*error = zbx_strdup(*error, "internal error: cannot get connection attributes");
7384 			THIS_SHOULD_NEVER_HAPPEN;
7385 			return FAIL;
7386 		}
7387 	}
7388 #endif
7389 	else if (ZBX_TCP_SEC_UNENCRYPTED != sock->connection_type)
7390 	{
7391 		*error = zbx_strdup(*error, "internal error: invalid connection type");
7392 		THIS_SHOULD_NEVER_HAPPEN;
7393 		return FAIL;
7394 	}
7395 #endif
7396 	RDLOCK_CACHE;
7397 
7398 	if (NULL == (dc_host = DCfind_proxy(host)))
7399 	{
7400 		UNLOCK_CACHE;
7401 		*error = zbx_dsprintf(*error, "proxy \"%s\" not found", host);
7402 		return FAIL;
7403 	}
7404 
7405 	if (HOST_STATUS_PROXY_ACTIVE != dc_host->status)
7406 	{
7407 		UNLOCK_CACHE;
7408 		*error = zbx_dsprintf(*error, "proxy \"%s\" is configured in passive mode", host);
7409 		return FAIL;
7410 	}
7411 
7412 	if (0 == ((unsigned int)dc_host->tls_accept & sock->connection_type))
7413 	{
7414 		UNLOCK_CACHE;
7415 		*error = zbx_dsprintf(NULL, "connection of type \"%s\" is not allowed for proxy \"%s\"",
7416 				zbx_tcp_connection_type_name(sock->connection_type), host);
7417 		return FAIL;
7418 	}
7419 
7420 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
7421 	if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type)
7422 	{
7423 		/* simplified match, not compliant with RFC 4517, 4518 */
7424 		if ('\0' != *dc_host->tls_issuer && 0 != strcmp(dc_host->tls_issuer, attr.issuer))
7425 		{
7426 			UNLOCK_CACHE;
7427 			*error = zbx_dsprintf(*error, "proxy \"%s\" certificate issuer does not match", host);
7428 			return FAIL;
7429 		}
7430 
7431 		/* simplified match, not compliant with RFC 4517, 4518 */
7432 		if ('\0' != *dc_host->tls_subject && 0 != strcmp(dc_host->tls_subject, attr.subject))
7433 		{
7434 			UNLOCK_CACHE;
7435 			*error = zbx_dsprintf(*error, "proxy \"%s\" certificate subject does not match", host);
7436 			return FAIL;
7437 		}
7438 	}
7439 #if defined(HAVE_GNUTLS) || (defined(HAVE_OPENSSL) && defined(HAVE_OPENSSL_WITH_PSK))
7440 	else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type)
7441 	{
7442 		if (NULL != dc_host->tls_dc_psk)
7443 		{
7444 			if (strlen(dc_host->tls_dc_psk->tls_psk_identity) != attr.psk_identity_len ||
7445 					0 != memcmp(dc_host->tls_dc_psk->tls_psk_identity, attr.psk_identity,
7446 					attr.psk_identity_len))
7447 			{
7448 				UNLOCK_CACHE;
7449 				*error = zbx_dsprintf(*error, "proxy \"%s\" is using false PSK identity", host);
7450 				return FAIL;
7451 			}
7452 		}
7453 		else
7454 		{
7455 			UNLOCK_CACHE;
7456 			*error = zbx_dsprintf(*error, "active proxy \"%s\" is connecting with PSK but there is no PSK"
7457 					" in the database for this proxy", host);
7458 			return FAIL;
7459 		}
7460 	}
7461 #endif
7462 #endif
7463 	*hostid = dc_host->hostid;
7464 
7465 	UNLOCK_CACHE;
7466 
7467 	return SUCCEED;
7468 }
7469 
7470 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
7471 /******************************************************************************
7472  *                                                                            *
7473  * Function: DCget_psk_by_identity                                            *
7474  *                                                                            *
7475  * Purpose:                                                                   *
7476  *     Find PSK with the specified identity in configuration cache            *
7477  *                                                                            *
7478  * Parameters:                                                                *
7479  *     psk_identity - [IN] PSK identity to search for ('\0' terminated)       *
7480  *     psk_buf      - [OUT] output buffer for PSK value with size             *
7481  *                    HOST_TLS_PSK_LEN_MAX                                    *
7482  *     psk_usage    - [OUT] 0 - PSK not found, 1 - found in host PSKs,        *
7483  *                          2 - found in autoregistration PSK, 3 - found in   *
7484  *                          both                                              *
7485  * Return value:                                                              *
7486  *     PSK length in bytes if PSK found. 0 - if PSK not found.                *
7487  *                                                                            *
7488  * Comments:                                                                  *
7489  *     ATTENTION! This function's address and arguments are described and     *
7490  *     used in file src/libs/zbxcrypto/tls.c for calling this function by     *
7491  *     pointer. If you ever change this DCget_psk_by_identity() function      *
7492  *     arguments or return value do not forget to synchronize changes with    *
7493  *     the src/libs/zbxcrypto/tls.c.                                          *
7494  *                                                                            *
7495  ******************************************************************************/
DCget_psk_by_identity(const unsigned char * psk_identity,unsigned char * psk_buf,unsigned int * psk_usage)7496 size_t	DCget_psk_by_identity(const unsigned char *psk_identity, unsigned char *psk_buf, unsigned int *psk_usage)
7497 {
7498 	const ZBX_DC_PSK	*psk_i;
7499 	ZBX_DC_PSK		psk_i_local;
7500 	size_t			psk_len = 0;
7501 	unsigned char		autoreg_psk_tmp[HOST_TLS_PSK_LEN_MAX];
7502 
7503 	*psk_usage = 0;
7504 
7505 	psk_i_local.tls_psk_identity = (const char *)psk_identity;
7506 
7507 	RDLOCK_CACHE;
7508 
7509 	/* Is it among host PSKs? */
7510 	if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)))
7511 	{
7512 		psk_len = zbx_strlcpy((char *)psk_buf, psk_i->tls_psk, HOST_TLS_PSK_LEN_MAX);
7513 		*psk_usage |= ZBX_PSK_FOR_HOST;
7514 	}
7515 
7516 	/* Does it match autoregistration PSK? */
7517 	if (0 != strcmp(config->autoreg_psk_identity, (const char *)psk_identity))
7518 	{
7519 		UNLOCK_CACHE;
7520 		return psk_len;
7521 	}
7522 
7523 	if (0 == *psk_usage)	/* only as autoregistration PSK */
7524 	{
7525 		psk_len = zbx_strlcpy((char *)psk_buf, config->autoreg_psk, HOST_TLS_PSK_LEN_MAX);
7526 		UNLOCK_CACHE;
7527 		*psk_usage |= ZBX_PSK_FOR_AUTOREG;
7528 
7529 		return psk_len;
7530 	}
7531 
7532 	/* the requested PSK is used as host PSK and as autoregistration PSK */
7533 	zbx_strlcpy((char *)autoreg_psk_tmp, config->autoreg_psk, sizeof(autoreg_psk_tmp));
7534 
7535 	UNLOCK_CACHE;
7536 
7537 	if (0 == strcmp((const char *)psk_buf, (const char *)autoreg_psk_tmp))
7538 	{
7539 		*psk_usage |= ZBX_PSK_FOR_AUTOREG;
7540 		return psk_len;
7541 	}
7542 
7543 	zabbix_log(LOG_LEVEL_WARNING, "host PSK and autoregistration PSK have the same identity \"%s\" but"
7544 			" different PSK values, autoregistration will not be allowed", psk_identity);
7545 	return psk_len;
7546 }
7547 #endif
7548 
7549 /******************************************************************************
7550  *                                                                            *
7551  * Function: DCget_autoregistration_psk                                       *
7552  *                                                                            *
7553  * Purpose:                                                                   *
7554  *     Copy autoregistration PSK identity and value from configuration cache  *
7555  *     into caller's buffers                                                  *
7556  *                                                                            *
7557  * Parameters:                                                                *
7558  *     psk_identity_buf     - [OUT] buffer for PSK identity                   *
7559  *     psk_identity_buf_len - [IN] buffer length for PSK identity             *
7560  *     psk_buf              - [OUT] buffer for PSK value                      *
7561  *     psk_buf_len          - [IN] buffer length for PSK value                *
7562  *                                                                            *
7563  * Comments: if autoregistration PSK is not configured then empty strings     *
7564  *           will be copied into buffers                                      *
7565  *                                                                            *
7566  ******************************************************************************/
DCget_autoregistration_psk(char * psk_identity_buf,size_t psk_identity_buf_len,unsigned char * psk_buf,size_t psk_buf_len)7567 void	DCget_autoregistration_psk(char *psk_identity_buf, size_t psk_identity_buf_len,
7568 		unsigned char *psk_buf, size_t psk_buf_len)
7569 {
7570 	RDLOCK_CACHE;
7571 
7572 	zbx_strlcpy((char *)psk_identity_buf, config->autoreg_psk_identity, psk_identity_buf_len);
7573 	zbx_strlcpy((char *)psk_buf, config->autoreg_psk, psk_buf_len);
7574 
7575 	UNLOCK_CACHE;
7576 }
7577 
DCget_interface(DC_INTERFACE * dst_interface,const ZBX_DC_INTERFACE * src_interface)7578 static void	DCget_interface(DC_INTERFACE *dst_interface, const ZBX_DC_INTERFACE *src_interface)
7579 {
7580 	if (NULL != src_interface)
7581 	{
7582 		dst_interface->interfaceid = src_interface->interfaceid;
7583 		strscpy(dst_interface->ip_orig, src_interface->ip);
7584 		strscpy(dst_interface->dns_orig, src_interface->dns);
7585 		strscpy(dst_interface->port_orig, src_interface->port);
7586 		dst_interface->useip = src_interface->useip;
7587 		dst_interface->type = src_interface->type;
7588 		dst_interface->main = src_interface->main;
7589 		dst_interface->available = src_interface->available;
7590 		dst_interface->disable_until = src_interface->disable_until;
7591 		dst_interface->errors_from = src_interface->errors_from;
7592 		strscpy(dst_interface->error, src_interface->error);
7593 	}
7594 	else
7595 	{
7596 		dst_interface->interfaceid = 0;
7597 		*dst_interface->ip_orig = '\0';
7598 		*dst_interface->dns_orig = '\0';
7599 		*dst_interface->port_orig = '\0';
7600 		dst_interface->useip = 1;
7601 		dst_interface->type = INTERFACE_TYPE_UNKNOWN;
7602 		dst_interface->main = 0;
7603 		dst_interface->available = INTERFACE_AVAILABLE_UNKNOWN;
7604 		dst_interface->disable_until = 0;
7605 		dst_interface->errors_from = 0;
7606 		*dst_interface->error = '\0';
7607 	}
7608 
7609 	dst_interface->addr = (1 == dst_interface->useip ? dst_interface->ip_orig : dst_interface->dns_orig);
7610 	dst_interface->port = 0;
7611 }
7612 
DCget_item(DC_ITEM * dst_item,const ZBX_DC_ITEM * src_item,unsigned int mode)7613 static void	DCget_item(DC_ITEM *dst_item, const ZBX_DC_ITEM *src_item, unsigned int mode)
7614 {
7615 	const ZBX_DC_NUMITEM		*numitem;
7616 	const ZBX_DC_LOGITEM		*logitem;
7617 	const ZBX_DC_SNMPITEM		*snmpitem;
7618 	const ZBX_DC_SNMPINTERFACE	*snmp;
7619 	const ZBX_DC_TRAPITEM		*trapitem;
7620 	const ZBX_DC_IPMIITEM		*ipmiitem;
7621 	const ZBX_DC_DBITEM		*dbitem;
7622 	const ZBX_DC_SSHITEM		*sshitem;
7623 	const ZBX_DC_TELNETITEM		*telnetitem;
7624 	const ZBX_DC_SIMPLEITEM		*simpleitem;
7625 	const ZBX_DC_JMXITEM		*jmxitem;
7626 	const ZBX_DC_CALCITEM		*calcitem;
7627 	const ZBX_DC_INTERFACE		*dc_interface;
7628 	const ZBX_DC_HTTPITEM		*httpitem;
7629 	const ZBX_DC_SCRIPTITEM		*scriptitem;
7630 
7631 	dst_item->type = src_item->type;
7632 	dst_item->value_type = src_item->value_type;
7633 
7634 	dst_item->state = src_item->state;
7635 	dst_item->lastlogsize = src_item->lastlogsize;
7636 	dst_item->mtime = src_item->mtime;
7637 
7638 	dst_item->history = src_item->history;
7639 
7640 	dst_item->inventory_link = src_item->inventory_link;
7641 	dst_item->valuemapid = src_item->valuemapid;
7642 	dst_item->status = src_item->status;
7643 
7644 	dst_item->history_sec = src_item->history_sec;
7645 	strscpy(dst_item->key_orig, src_item->key);
7646 
7647 	if (ZBX_ITEM_GET_MISC & mode)
7648 	{
7649 		dst_item->itemid = src_item->itemid;			/* set after lock */
7650 		dst_item->flags = src_item->flags;
7651 		dst_item->key = NULL;					/* set during initialization */
7652 	}
7653 
7654 	if (ZBX_ITEM_GET_DELAY & mode)
7655 		dst_item->delay = zbx_strdup(NULL, src_item->delay);	/* not used, should be initialized */
7656 
7657 	if ((ZBX_ITEM_GET_EMPTY_ERROR & mode) || '\0' != *src_item->error)		/* allocate after lock */
7658 		dst_item->error = zbx_strdup(NULL, src_item->error);
7659 
7660 	switch (src_item->value_type)
7661 	{
7662 		case ITEM_VALUE_TYPE_FLOAT:
7663 		case ITEM_VALUE_TYPE_UINT64:
7664 			if (0 != (ZBX_ITEM_GET_NUM & mode))
7665 			{
7666 				numitem = (ZBX_DC_NUMITEM *)zbx_hashset_search(&config->numitems, &src_item->itemid);
7667 
7668 				dst_item->trends = numitem->trends;
7669 				dst_item->trends_sec = numitem->trends_sec;
7670 
7671 				/* allocate after lock */
7672 				if (0 != (ZBX_ITEM_GET_EMPTY_UNITS & mode) || '\0' != *numitem->units)
7673 					dst_item->units = zbx_strdup(NULL, numitem->units);
7674 			}
7675 			break;
7676 		case ITEM_VALUE_TYPE_LOG:
7677 			if (ZBX_ITEM_GET_LOGTIMEFMT & mode)
7678 			{
7679 				if (NULL != (logitem = (ZBX_DC_LOGITEM *)zbx_hashset_search(&config->logitems,
7680 						&src_item->itemid)))
7681 				{
7682 					strscpy(dst_item->logtimefmt, logitem->logtimefmt);
7683 				}
7684 				else
7685 					*dst_item->logtimefmt = '\0';
7686 			}
7687 			break;
7688 	}
7689 
7690 	if (ZBX_ITEM_GET_INTERFACE & mode)	/* not used by history syncer */
7691 	{
7692 		dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &src_item->interfaceid);
7693 
7694 		DCget_interface(&dst_item->interface, dc_interface);
7695 	}
7696 
7697 	if (0 == (ZBX_ITEM_GET_POLLINFO & mode))	/* not used by history syncer */
7698 		return;
7699 
7700 	switch (src_item->type)
7701 	{
7702 		case ITEM_TYPE_SNMP:
7703 			snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &src_item->itemid);
7704 			snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &src_item->interfaceid);
7705 
7706 			if (NULL != snmpitem && NULL != snmp)
7707 			{
7708 				strscpy(dst_item->snmp_community_orig, snmp->community);
7709 				strscpy(dst_item->snmp_oid_orig, snmpitem->snmp_oid);
7710 				strscpy(dst_item->snmpv3_securityname_orig, snmp->securityname);
7711 				dst_item->snmpv3_securitylevel = snmp->securitylevel;
7712 				strscpy(dst_item->snmpv3_authpassphrase_orig, snmp->authpassphrase);
7713 				strscpy(dst_item->snmpv3_privpassphrase_orig, snmp->privpassphrase);
7714 				dst_item->snmpv3_authprotocol = snmp->authprotocol;
7715 				dst_item->snmpv3_privprotocol = snmp->privprotocol;
7716 				strscpy(dst_item->snmpv3_contextname_orig, snmp->contextname);
7717 				dst_item->snmp_version = snmp->version;
7718 			}
7719 			else
7720 			{
7721 				*dst_item->snmp_community_orig = '\0';
7722 				*dst_item->snmp_oid_orig = '\0';
7723 				*dst_item->snmpv3_securityname_orig = '\0';
7724 				dst_item->snmpv3_securitylevel = ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV;
7725 				*dst_item->snmpv3_authpassphrase_orig = '\0';
7726 				*dst_item->snmpv3_privpassphrase_orig = '\0';
7727 				dst_item->snmpv3_authprotocol = 0;
7728 				dst_item->snmpv3_privprotocol = 0;
7729 				*dst_item->snmpv3_contextname_orig = '\0';
7730 				dst_item->snmp_version = ZBX_IF_SNMP_VERSION_2;
7731 			}
7732 
7733 			dst_item->snmp_community = NULL;
7734 			dst_item->snmp_oid = NULL;
7735 			dst_item->snmpv3_securityname = NULL;
7736 			dst_item->snmpv3_authpassphrase = NULL;
7737 			dst_item->snmpv3_privpassphrase = NULL;
7738 			dst_item->snmpv3_contextname = NULL;
7739 			break;
7740 		case ITEM_TYPE_TRAPPER:
7741 			if (NULL != (trapitem = (ZBX_DC_TRAPITEM *)zbx_hashset_search(&config->trapitems, &src_item->itemid)))
7742 				strscpy(dst_item->trapper_hosts, trapitem->trapper_hosts);
7743 			else
7744 				*dst_item->trapper_hosts = '\0';
7745 			break;
7746 		case ITEM_TYPE_IPMI:
7747 			if (NULL != (ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &src_item->itemid)))
7748 				strscpy(dst_item->ipmi_sensor, ipmiitem->ipmi_sensor);
7749 			else
7750 				*dst_item->ipmi_sensor = '\0';
7751 			break;
7752 		case ITEM_TYPE_DB_MONITOR:
7753 			if (NULL != (dbitem = (ZBX_DC_DBITEM *)zbx_hashset_search(&config->dbitems, &src_item->itemid)))
7754 			{
7755 				dst_item->params = zbx_strdup(NULL, dbitem->params);
7756 				strscpy(dst_item->username_orig, dbitem->username);
7757 				strscpy(dst_item->password_orig, dbitem->password);
7758 			}
7759 			else
7760 			{
7761 				dst_item->params = zbx_strdup(NULL, "");
7762 				*dst_item->username_orig = '\0';
7763 				*dst_item->password_orig = '\0';
7764 			}
7765 			dst_item->username = NULL;
7766 			dst_item->password = NULL;
7767 
7768 			break;
7769 		case ITEM_TYPE_SSH:
7770 			if (NULL != (sshitem = (ZBX_DC_SSHITEM *)zbx_hashset_search(&config->sshitems, &src_item->itemid)))
7771 			{
7772 				dst_item->authtype = sshitem->authtype;
7773 				strscpy(dst_item->username_orig, sshitem->username);
7774 				strscpy(dst_item->publickey_orig, sshitem->publickey);
7775 				strscpy(dst_item->privatekey_orig, sshitem->privatekey);
7776 				strscpy(dst_item->password_orig, sshitem->password);
7777 				dst_item->params = zbx_strdup(NULL, sshitem->params);
7778 			}
7779 			else
7780 			{
7781 				dst_item->authtype = 0;
7782 				*dst_item->username_orig = '\0';
7783 				*dst_item->publickey_orig = '\0';
7784 				*dst_item->privatekey_orig = '\0';
7785 				*dst_item->password_orig = '\0';
7786 				dst_item->params = zbx_strdup(NULL, "");
7787 			}
7788 			dst_item->username = NULL;
7789 			dst_item->publickey = NULL;
7790 			dst_item->privatekey = NULL;
7791 			dst_item->password = NULL;
7792 			break;
7793 		case ITEM_TYPE_HTTPAGENT:
7794 			if (NULL != (httpitem = (ZBX_DC_HTTPITEM *)zbx_hashset_search(&config->httpitems, &src_item->itemid)))
7795 			{
7796 				strscpy(dst_item->timeout_orig, httpitem->timeout);
7797 				strscpy(dst_item->url_orig, httpitem->url);
7798 				strscpy(dst_item->query_fields_orig, httpitem->query_fields);
7799 				strscpy(dst_item->status_codes_orig, httpitem->status_codes);
7800 				dst_item->follow_redirects = httpitem->follow_redirects;
7801 				dst_item->post_type = httpitem->post_type;
7802 				strscpy(dst_item->http_proxy_orig, httpitem->http_proxy);
7803 				dst_item->headers = zbx_strdup(NULL, httpitem->headers);
7804 				dst_item->retrieve_mode = httpitem->retrieve_mode;
7805 				dst_item->request_method = httpitem->request_method;
7806 				dst_item->output_format = httpitem->output_format;
7807 				strscpy(dst_item->ssl_cert_file_orig, httpitem->ssl_cert_file);
7808 				strscpy(dst_item->ssl_key_file_orig, httpitem->ssl_key_file);
7809 				strscpy(dst_item->ssl_key_password_orig, httpitem->ssl_key_password);
7810 				dst_item->verify_peer = httpitem->verify_peer;
7811 				dst_item->verify_host = httpitem->verify_host;
7812 				dst_item->authtype = httpitem->authtype;
7813 				strscpy(dst_item->username_orig, httpitem->username);
7814 				strscpy(dst_item->password_orig, httpitem->password);
7815 				dst_item->posts = zbx_strdup(NULL, httpitem->posts);
7816 				dst_item->allow_traps = httpitem->allow_traps;
7817 				strscpy(dst_item->trapper_hosts, httpitem->trapper_hosts);
7818 			}
7819 			else
7820 			{
7821 				*dst_item->timeout_orig = '\0';
7822 				*dst_item->url_orig = '\0';
7823 				*dst_item->query_fields_orig = '\0';
7824 				*dst_item->status_codes_orig = '\0';
7825 				dst_item->follow_redirects = 0;
7826 				dst_item->post_type = 0;
7827 				*dst_item->http_proxy_orig = '\0';
7828 				dst_item->headers = zbx_strdup(NULL, "");
7829 				dst_item->retrieve_mode = 0;
7830 				dst_item->request_method = 0;
7831 				dst_item->output_format = 0;
7832 				*dst_item->ssl_cert_file_orig = '\0';
7833 				*dst_item->ssl_key_file_orig = '\0';
7834 				*dst_item->ssl_key_password_orig = '\0';
7835 				dst_item->verify_peer = 0;
7836 				dst_item->verify_host = 0;
7837 				dst_item->authtype = 0;
7838 				*dst_item->username_orig = '\0';
7839 				*dst_item->password_orig = '\0';
7840 				dst_item->posts = zbx_strdup(NULL, "");
7841 				dst_item->allow_traps = 0;
7842 				*dst_item->trapper_hosts = '\0';
7843 			}
7844 			dst_item->timeout = NULL;
7845 			dst_item->url = NULL;
7846 			dst_item->query_fields = NULL;
7847 			dst_item->status_codes = NULL;
7848 			dst_item->http_proxy = NULL;
7849 			dst_item->ssl_cert_file = NULL;
7850 			dst_item->ssl_key_file = NULL;
7851 			dst_item->ssl_key_password = NULL;
7852 			dst_item->username = NULL;
7853 			dst_item->password = NULL;
7854 			break;
7855 		case ITEM_TYPE_SCRIPT:
7856 			if (NULL != (scriptitem = (ZBX_DC_SCRIPTITEM *)zbx_hashset_search(&config->scriptitems,
7857 					&src_item->itemid)))
7858 			{
7859 				int		i;
7860 				struct zbx_json	json;
7861 
7862 				zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
7863 
7864 				strscpy(dst_item->timeout_orig, scriptitem->timeout);
7865 				dst_item->params = zbx_strdup(NULL, scriptitem->script);
7866 
7867 				for (i = 0; i < scriptitem->params.values_num; i++)
7868 				{
7869 					zbx_dc_scriptitem_param_t	*params =
7870 							(zbx_dc_scriptitem_param_t*)(scriptitem->params.values[i]);
7871 
7872 					zbx_json_addstring(&json, params->name, params->value, ZBX_JSON_TYPE_STRING);
7873 				}
7874 
7875 				dst_item->script_params = zbx_strdup(NULL, json.buffer);
7876 				zbx_json_free(&json);
7877 			}
7878 			else
7879 			{
7880 				*dst_item->timeout_orig = '\0';
7881 				dst_item->params = zbx_strdup(NULL, "");
7882 				dst_item->script_params = zbx_strdup(NULL, "");
7883 			}
7884 
7885 			dst_item->timeout = NULL;
7886 			break;
7887 		case ITEM_TYPE_TELNET:
7888 			if (NULL != (telnetitem = (ZBX_DC_TELNETITEM *)zbx_hashset_search(&config->telnetitems, &src_item->itemid)))
7889 			{
7890 				strscpy(dst_item->username_orig, telnetitem->username);
7891 				strscpy(dst_item->password_orig, telnetitem->password);
7892 				dst_item->params = zbx_strdup(NULL, telnetitem->params);
7893 			}
7894 			else
7895 			{
7896 				*dst_item->username_orig = '\0';
7897 				*dst_item->password_orig = '\0';
7898 				dst_item->params = zbx_strdup(NULL, "");
7899 			}
7900 			dst_item->username = NULL;
7901 			dst_item->password = NULL;
7902 			break;
7903 		case ITEM_TYPE_SIMPLE:
7904 			if (NULL != (simpleitem = (ZBX_DC_SIMPLEITEM *)zbx_hashset_search(&config->simpleitems, &src_item->itemid)))
7905 			{
7906 				strscpy(dst_item->username_orig, simpleitem->username);
7907 				strscpy(dst_item->password_orig, simpleitem->password);
7908 			}
7909 			else
7910 			{
7911 				*dst_item->username_orig = '\0';
7912 				*dst_item->password_orig = '\0';
7913 			}
7914 			dst_item->username = NULL;
7915 			dst_item->password = NULL;
7916 			break;
7917 		case ITEM_TYPE_JMX:
7918 			if (NULL != (jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &src_item->itemid)))
7919 			{
7920 				strscpy(dst_item->username_orig, jmxitem->username);
7921 				strscpy(dst_item->password_orig, jmxitem->password);
7922 				strscpy(dst_item->jmx_endpoint_orig, jmxitem->jmx_endpoint);
7923 			}
7924 			else
7925 			{
7926 				*dst_item->username_orig = '\0';
7927 				*dst_item->password_orig = '\0';
7928 				*dst_item->jmx_endpoint_orig = '\0';
7929 			}
7930 			dst_item->username = NULL;
7931 			dst_item->password = NULL;
7932 			dst_item->jmx_endpoint = NULL;
7933 			break;
7934 		case ITEM_TYPE_CALCULATED:
7935 			if (NULL != (calcitem = (ZBX_DC_CALCITEM *)zbx_hashset_search(&config->calcitems,
7936 					&src_item->itemid)))
7937 			{
7938 				dst_item->params = zbx_strdup(NULL, calcitem->params);
7939 				dst_item->formula_bin = dup_serialized_expression(calcitem->formula_bin);
7940 			}
7941 			else
7942 			{
7943 				dst_item->params = zbx_strdup(NULL, "");
7944 				dst_item->formula_bin = NULL;
7945 			}
7946 
7947 			break;
7948 		default:
7949 			/* nothing to do */;
7950 	}
7951 }
7952 
DCconfig_clean_items(DC_ITEM * items,int * errcodes,size_t num)7953 void	DCconfig_clean_items(DC_ITEM *items, int *errcodes, size_t num)
7954 {
7955 	size_t	i;
7956 
7957 	for (i = 0; i < num; i++)
7958 	{
7959 		if (NULL != errcodes && SUCCEED != errcodes[i])
7960 			continue;
7961 
7962 		if (ITEM_VALUE_TYPE_FLOAT == items[i].value_type || ITEM_VALUE_TYPE_UINT64 == items[i].value_type)
7963 		{
7964 			zbx_free(items[i].units);
7965 		}
7966 
7967 		switch (items[i].type)
7968 		{
7969 			case ITEM_TYPE_HTTPAGENT:
7970 				zbx_free(items[i].headers);
7971 				zbx_free(items[i].posts);
7972 				break;
7973 			case ITEM_TYPE_SCRIPT:
7974 				zbx_free(items[i].script_params);
7975 				ZBX_FALLTHROUGH;
7976 			case ITEM_TYPE_DB_MONITOR:
7977 			case ITEM_TYPE_SSH:
7978 			case ITEM_TYPE_TELNET:
7979 				zbx_free(items[i].params);
7980 				break;
7981 			case ITEM_TYPE_CALCULATED:
7982 				zbx_free(items[i].params);
7983 				zbx_free(items[i].formula_bin);
7984 				break;
7985 		}
7986 
7987 		zbx_free(items[i].delay);
7988 		zbx_free(items[i].error);
7989 	}
7990 }
7991 
DCget_function(DC_FUNCTION * dst_function,const ZBX_DC_FUNCTION * src_function)7992 static void	DCget_function(DC_FUNCTION *dst_function, const ZBX_DC_FUNCTION *src_function)
7993 {
7994 	size_t	sz_function, sz_parameter;
7995 
7996 	dst_function->functionid = src_function->functionid;
7997 	dst_function->triggerid = src_function->triggerid;
7998 	dst_function->itemid = src_function->itemid;
7999 
8000 	sz_function = strlen(src_function->function) + 1;
8001 	sz_parameter = strlen(src_function->parameter) + 1;
8002 	dst_function->function = (char *)zbx_malloc(NULL, sz_function + sz_parameter);
8003 	dst_function->parameter = dst_function->function + sz_function;
8004 	memcpy(dst_function->function, src_function->function, sz_function);
8005 	memcpy(dst_function->parameter, src_function->parameter, sz_parameter);
8006 }
8007 
DCget_trigger(DC_TRIGGER * dst_trigger,const ZBX_DC_TRIGGER * src_trigger)8008 static void	DCget_trigger(DC_TRIGGER *dst_trigger, const ZBX_DC_TRIGGER *src_trigger)
8009 {
8010 	int	i;
8011 
8012 	dst_trigger->triggerid = src_trigger->triggerid;
8013 	dst_trigger->description = zbx_strdup(NULL, src_trigger->description);
8014 	dst_trigger->error = zbx_strdup(NULL, src_trigger->error);
8015 	dst_trigger->timespec.sec = 0;
8016 	dst_trigger->timespec.ns = 0;
8017 	dst_trigger->priority = src_trigger->priority;
8018 	dst_trigger->type = src_trigger->type;
8019 	dst_trigger->value = src_trigger->value;
8020 	dst_trigger->state = src_trigger->state;
8021 	dst_trigger->new_value = TRIGGER_VALUE_UNKNOWN;
8022 	dst_trigger->lastchange = src_trigger->lastchange;
8023 	dst_trigger->topoindex = src_trigger->topoindex;
8024 	dst_trigger->status = src_trigger->status;
8025 	dst_trigger->recovery_mode = src_trigger->recovery_mode;
8026 	dst_trigger->correlation_mode = src_trigger->correlation_mode;
8027 	dst_trigger->correlation_tag = zbx_strdup(NULL, src_trigger->correlation_tag);
8028 	dst_trigger->opdata = zbx_strdup(NULL, src_trigger->opdata);
8029 	dst_trigger->event_name = ('\0' != *src_trigger->event_name ? zbx_strdup(NULL, src_trigger->event_name) : NULL);
8030 	dst_trigger->flags = 0;
8031 	dst_trigger->new_error = NULL;
8032 
8033 	dst_trigger->expression = zbx_strdup(NULL, src_trigger->expression);
8034 	dst_trigger->recovery_expression = zbx_strdup(NULL, src_trigger->recovery_expression);
8035 
8036 	dst_trigger->expression_bin = dup_serialized_expression(src_trigger->expression_bin);
8037 	dst_trigger->recovery_expression_bin = dup_serialized_expression(src_trigger->recovery_expression_bin);
8038 
8039 	dst_trigger->eval_ctx = NULL;
8040 	dst_trigger->eval_ctx_r = NULL;
8041 
8042 	zbx_vector_ptr_create(&dst_trigger->tags);
8043 
8044 	if (0 != src_trigger->tags.values_num)
8045 	{
8046 		zbx_vector_ptr_reserve(&dst_trigger->tags, src_trigger->tags.values_num);
8047 
8048 		for (i = 0; i < src_trigger->tags.values_num; i++)
8049 		{
8050 			const zbx_dc_trigger_tag_t	*dc_trigger_tag = (const zbx_dc_trigger_tag_t *)src_trigger->tags.values[i];
8051 			zbx_tag_t			*tag;
8052 
8053 			tag = (zbx_tag_t *)zbx_malloc(NULL, sizeof(zbx_tag_t));
8054 			tag->tag = zbx_strdup(NULL, dc_trigger_tag->tag);
8055 			tag->value = zbx_strdup(NULL, dc_trigger_tag->value);
8056 
8057 			zbx_vector_ptr_append(&dst_trigger->tags, tag);
8058 		}
8059 	}
8060 }
8061 
zbx_free_tag(zbx_tag_t * tag)8062 void	zbx_free_tag(zbx_tag_t *tag)
8063 {
8064 	zbx_free(tag->tag);
8065 	zbx_free(tag->value);
8066 	zbx_free(tag);
8067 }
8068 
zbx_free_item_tag(zbx_item_tag_t * item_tag)8069 void	zbx_free_item_tag(zbx_item_tag_t *item_tag)
8070 {
8071 	zbx_free(item_tag->tag.tag);
8072 	zbx_free(item_tag->tag.value);
8073 	zbx_free(item_tag);
8074 }
8075 
DCclean_trigger(DC_TRIGGER * trigger)8076 static void	DCclean_trigger(DC_TRIGGER *trigger)
8077 {
8078 	zbx_free(trigger->new_error);
8079 	zbx_free(trigger->error);
8080 	zbx_free(trigger->expression);
8081 	zbx_free(trigger->recovery_expression);
8082 	zbx_free(trigger->description);
8083 	zbx_free(trigger->correlation_tag);
8084 	zbx_free(trigger->opdata);
8085 	zbx_free(trigger->event_name);
8086 	zbx_free(trigger->expression_bin);
8087 	zbx_free(trigger->recovery_expression_bin);
8088 
8089 	zbx_vector_ptr_clear_ext(&trigger->tags, (zbx_clean_func_t)zbx_free_tag);
8090 	zbx_vector_ptr_destroy(&trigger->tags);
8091 
8092 	if (NULL != trigger->eval_ctx)
8093 	{
8094 		zbx_eval_clear(trigger->eval_ctx);
8095 		zbx_free(trigger->eval_ctx);
8096 	}
8097 
8098 	if (NULL != trigger->eval_ctx_r)
8099 	{
8100 		zbx_eval_clear(trigger->eval_ctx_r);
8101 		zbx_free(trigger->eval_ctx_r);
8102 	}
8103 
8104 }
8105 
8106 /******************************************************************************
8107  *                                                                            *
8108  * Function: DCconfig_get_items_by_keys                                       *
8109  *                                                                            *
8110  * Purpose: locate item in configuration cache by host and key                *
8111  *                                                                            *
8112  * Parameters: items    - [OUT] pointer to array of DC_ITEM structures        *
8113  *             keys     - [IN] list of item keys with host names              *
8114  *             errcodes - [OUT] SUCCEED if record located and FAIL otherwise  *
8115  *             num      - [IN] number of elements in items, keys, errcodes    *
8116  *                                                                            *
8117  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
8118  *                                                                            *
8119  ******************************************************************************/
DCconfig_get_items_by_keys(DC_ITEM * items,zbx_host_key_t * keys,int * errcodes,size_t num)8120 void	DCconfig_get_items_by_keys(DC_ITEM *items, zbx_host_key_t *keys, int *errcodes, size_t num)
8121 {
8122 	size_t			i;
8123 	const ZBX_DC_ITEM	*dc_item;
8124 	const ZBX_DC_HOST	*dc_host;
8125 
8126 	RDLOCK_CACHE;
8127 
8128 	for (i = 0; i < num; i++)
8129 	{
8130 		if (NULL == (dc_host = DCfind_host(keys[i].host)) ||
8131 				NULL == (dc_item = DCfind_item(dc_host->hostid, keys[i].key)))
8132 		{
8133 			errcodes[i] = FAIL;
8134 			continue;
8135 		}
8136 
8137 		DCget_host(&items[i].host, dc_host, ZBX_ITEM_GET_ALL);
8138 		DCget_item(&items[i], dc_item, ZBX_ITEM_GET_ALL);
8139 		errcodes[i] = SUCCEED;
8140 	}
8141 
8142 	UNLOCK_CACHE;
8143 }
8144 
DCconfig_get_hostid_by_name(const char * host,zbx_uint64_t * hostid)8145 int	DCconfig_get_hostid_by_name(const char *host, zbx_uint64_t *hostid)
8146 {
8147 	const ZBX_DC_HOST	*dc_host;
8148 	int			ret;
8149 
8150 	RDLOCK_CACHE;
8151 
8152 	if (NULL != (dc_host = DCfind_host(host)))
8153 	{
8154 		*hostid = dc_host->hostid;
8155 		ret = SUCCEED;
8156 	}
8157 	else
8158 		ret = FAIL;
8159 
8160 	UNLOCK_CACHE;
8161 
8162 	return ret;
8163 }
8164 
8165 /******************************************************************************
8166  *                                                                            *
8167  * Function: DCconfig_get_items_by_itemids                                    *
8168  *                                                                            *
8169  * Purpose: Get item with specified ID                                        *
8170  *                                                                            *
8171  * Parameters: items    - [OUT] pointer to DC_ITEM structures                 *
8172  *             itemids  - [IN] array of item IDs                              *
8173  *             errcodes - [OUT] SUCCEED if item found, otherwise FAIL         *
8174  *             num      - [IN] number of elements                             *
8175  *                                                                            *
8176  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
8177  *                                                                            *
8178  ******************************************************************************/
DCconfig_get_items_by_itemids(DC_ITEM * items,const zbx_uint64_t * itemids,int * errcodes,size_t num)8179 void	DCconfig_get_items_by_itemids(DC_ITEM *items, const zbx_uint64_t *itemids, int *errcodes, size_t num)
8180 {
8181 	size_t			i;
8182 	const ZBX_DC_ITEM	*dc_item;
8183 	const ZBX_DC_HOST	*dc_host;
8184 
8185 	RDLOCK_CACHE;
8186 
8187 	for (i = 0; i < num; i++)
8188 	{
8189 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])) ||
8190 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8191 		{
8192 			errcodes[i] = FAIL;
8193 			continue;
8194 		}
8195 
8196 		DCget_host(&items[i].host, dc_host, ZBX_ITEM_GET_ALL);
8197 		DCget_item(&items[i], dc_item, ZBX_ITEM_GET_ALL);
8198 		errcodes[i] = SUCCEED;
8199 	}
8200 
8201 	UNLOCK_CACHE;
8202 }
8203 
DCconfig_get_items_by_itemids_partial(DC_ITEM * items,const zbx_uint64_t * itemids,int * errcodes,size_t num,unsigned int mode)8204 void	DCconfig_get_items_by_itemids_partial(DC_ITEM *items, const zbx_uint64_t *itemids, int *errcodes, size_t num,
8205 		unsigned int mode)
8206 {
8207 	size_t			i;
8208 	const ZBX_DC_ITEM	*dc_item;
8209 	const ZBX_DC_HOST	*dc_host = NULL;
8210 
8211 	memset(items, 0, sizeof(DC_ITEM) * (size_t)num);
8212 	memset(errcodes, 0, sizeof(int) * (size_t)num);
8213 
8214 	RDLOCK_CACHE;
8215 
8216 	for (i = 0; i < num; i++)
8217 	{
8218 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])))
8219 		{
8220 			errcodes[i] = FAIL;
8221 			continue;
8222 		}
8223 
8224 		if (NULL == dc_host || dc_host->hostid != dc_item->hostid)
8225 		{
8226 			if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8227 			{
8228 				errcodes[i] = FAIL;
8229 				continue;
8230 			}
8231 		}
8232 
8233 		DCget_host(&items[i].host, dc_host, mode);
8234 		DCget_item(&items[i], dc_item, mode);
8235 	}
8236 
8237 	UNLOCK_CACHE;
8238 
8239 	/* avoid unnecessary allocations inside lock if there are no error or units */
8240 	for (i = 0; i < num; i++)
8241 	{
8242 		if (FAIL == errcodes[i])
8243 			continue;
8244 
8245 		items[i].itemid = itemids[i];
8246 
8247 		if (NULL == items[i].error)
8248 			items[i].error = zbx_strdup(NULL, "");
8249 
8250 		if (ITEM_VALUE_TYPE_FLOAT == items[i].value_type || ITEM_VALUE_TYPE_UINT64 == items[i].value_type)
8251 		{
8252 			if (NULL == items[i].units)
8253 				items[i].units = zbx_strdup(NULL, "");
8254 		}
8255 	}
8256 }
8257 
8258 /******************************************************************************
8259  *                                                                            *
8260  * Function: dc_preproc_item_init                                             *
8261  *                                                                            *
8262  * Purpose: initialize new preprocessor item from configuration cache         *
8263  *                                                                            *
8264  * Parameters: item   - [OUT] the item to initialize                          *
8265  *             itemid - [IN] the item identifier                              *
8266  *                                                                            *
8267  * Return value: SUCCEED - the item was initialized successfully              *
8268  *               FAIL    - item with the specified itemid is not cached or    *
8269  *                         monitored                                          *
8270  *                                                                            *
8271  ******************************************************************************/
dc_preproc_item_init(zbx_preproc_item_t * item,zbx_uint64_t itemid)8272 static int	dc_preproc_item_init(zbx_preproc_item_t *item, zbx_uint64_t itemid)
8273 {
8274 	const ZBX_DC_ITEM	*dc_item;
8275 	const ZBX_DC_HOST	*dc_host;
8276 
8277 	if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
8278 		return FAIL;
8279 
8280 	if (ITEM_STATUS_ACTIVE != dc_item->status)
8281 		return FAIL;
8282 
8283 	if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8284 		return FAIL;
8285 
8286 	if (HOST_STATUS_MONITORED != dc_host->status)
8287 		return FAIL;
8288 
8289 	item->itemid = itemid;
8290 	item->type = dc_item->type;
8291 	item->value_type = dc_item->value_type;
8292 
8293 	item->dep_itemids = NULL;
8294 	item->dep_itemids_num = 0;
8295 
8296 	item->preproc_ops = NULL;
8297 	item->preproc_ops_num = 0;
8298 	item->update_time = 0;
8299 
8300 	return SUCCEED;
8301 }
8302 
8303 /******************************************************************************
8304  *                                                                            *
8305  * Function: DCconfig_get_preprocessable_items                                *
8306  *                                                                            *
8307  * Purpose: get preprocessable items:                                         *
8308  *              * items with preprocessing steps                              *
8309  *              * items with dependent items                                  *
8310  *              * internal items                                              *
8311  *                                                                            *
8312  * Parameters: items       - [IN/OUT] hashset with DC_ITEMs                   *
8313  *             timestamp   - [IN/OUT] timestamp of a last update              *
8314  *                                                                            *
8315  ******************************************************************************/
DCconfig_get_preprocessable_items(zbx_hashset_t * items,int * timestamp)8316 void	DCconfig_get_preprocessable_items(zbx_hashset_t *items, int *timestamp)
8317 {
8318 	const ZBX_DC_PREPROCITEM	*dc_preprocitem;
8319 	const ZBX_DC_MASTERITEM		*dc_masteritem;
8320 	const ZBX_DC_ITEM		*dc_item;
8321 	const zbx_dc_preproc_op_t	*dc_op;
8322 	zbx_preproc_item_t		*item, item_local;
8323 	zbx_hashset_iter_t		iter;
8324 	zbx_preproc_op_t		*op;
8325 	int				i;
8326 
8327 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
8328 
8329 	/* no changes */
8330 	if (0 != *timestamp && *timestamp == config->item_sync_ts)
8331 		goto out;
8332 
8333 	zbx_hashset_clear(items);
8334 	*timestamp = config->item_sync_ts;
8335 
8336 	RDLOCK_CACHE;
8337 
8338 	zbx_hashset_iter_reset(&config->preprocitems, &iter);
8339 	while (NULL != (dc_preprocitem = (const ZBX_DC_PREPROCITEM *)zbx_hashset_iter_next(&iter)))
8340 	{
8341 		if (FAIL == dc_preproc_item_init(&item_local, dc_preprocitem->itemid))
8342 			continue;
8343 
8344 		item = (zbx_preproc_item_t *)zbx_hashset_insert(items, &item_local, sizeof(item_local));
8345 
8346 		item->preproc_ops_num = dc_preprocitem->preproc_ops.values_num;
8347 		item->preproc_ops = (zbx_preproc_op_t *)zbx_malloc(NULL, sizeof(zbx_preproc_op_t) * item->preproc_ops_num);
8348 		item->update_time = dc_preprocitem->update_time;
8349 
8350 		for (i = 0; i < dc_preprocitem->preproc_ops.values_num; i++)
8351 		{
8352 			dc_op = (const zbx_dc_preproc_op_t *)dc_preprocitem->preproc_ops.values[i];
8353 			op = &item->preproc_ops[i];
8354 			op->type = dc_op->type;
8355 			op->params = zbx_strdup(NULL, dc_op->params);
8356 			op->error_handler = dc_op->error_handler;
8357 			op->error_handler_params = zbx_strdup(NULL, dc_op->error_handler_params);
8358 		}
8359 	}
8360 
8361 	zbx_hashset_iter_reset(&config->masteritems, &iter);
8362 	while (NULL != (dc_masteritem = (const ZBX_DC_MASTERITEM *)zbx_hashset_iter_next(&iter)))
8363 	{
8364 		if (NULL == (item = (zbx_preproc_item_t *)zbx_hashset_search(items, &dc_masteritem->itemid)))
8365 		{
8366 			if (FAIL == dc_preproc_item_init(&item_local, dc_masteritem->itemid))
8367 				continue;
8368 
8369 			item = (zbx_preproc_item_t *)zbx_hashset_insert(items, &item_local, sizeof(item_local));
8370 		}
8371 
8372 		item->dep_itemids_num = 0;
8373 		item->dep_itemids = (zbx_uint64_pair_t *)zbx_malloc(NULL, sizeof(zbx_uint64_pair_t) *
8374 				dc_masteritem->dep_itemids.values_num);
8375 
8376 		for (i = 0; i < dc_masteritem->dep_itemids.values_num; i++)
8377 		{
8378 			if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items,
8379 					&dc_masteritem->dep_itemids.values[i].first)) ||
8380 					ITEM_STATUS_ACTIVE != dc_item->status)
8381 			{
8382 				continue;
8383 			}
8384 			item->dep_itemids[item->dep_itemids_num++] = dc_masteritem->dep_itemids.values[i];
8385 		}
8386 	}
8387 
8388 	zbx_hashset_iter_reset(&config->items, &iter);
8389 	while (NULL != (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_iter_next(&iter)))
8390 	{
8391 		if (ITEM_TYPE_INTERNAL != dc_item->type)
8392 			continue;
8393 
8394 		if (NULL == zbx_hashset_search(items, &dc_item->itemid))
8395 		{
8396 			if (FAIL == dc_preproc_item_init(&item_local, dc_item->itemid))
8397 				continue;
8398 
8399 			zbx_hashset_insert(items, &item_local, sizeof(item_local));
8400 		}
8401 	}
8402 
8403 	UNLOCK_CACHE;
8404 out:
8405 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() items:%d", __func__, items->num_data);
8406 }
8407 
DCconfig_get_hosts_by_itemids(DC_HOST * hosts,const zbx_uint64_t * itemids,int * errcodes,size_t num)8408 void	DCconfig_get_hosts_by_itemids(DC_HOST *hosts, const zbx_uint64_t *itemids, int *errcodes, size_t num)
8409 {
8410 	size_t			i;
8411 	const ZBX_DC_ITEM	*dc_item;
8412 	const ZBX_DC_HOST	*dc_host;
8413 
8414 	RDLOCK_CACHE;
8415 
8416 	for (i = 0; i < num; i++)
8417 	{
8418 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])) ||
8419 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8420 		{
8421 			errcodes[i] = FAIL;
8422 			continue;
8423 		}
8424 
8425 		DCget_host(&hosts[i], dc_host, ZBX_ITEM_GET_ALL);
8426 		errcodes[i] = SUCCEED;
8427 	}
8428 
8429 	UNLOCK_CACHE;
8430 }
8431 
DCconfig_trigger_exists(zbx_uint64_t triggerid)8432 int	DCconfig_trigger_exists(zbx_uint64_t triggerid)
8433 {
8434 	int	ret = SUCCEED;
8435 
8436 	RDLOCK_CACHE;
8437 
8438 	if (NULL == zbx_hashset_search(&config->triggers, &triggerid))
8439 		ret = FAIL;
8440 
8441 	UNLOCK_CACHE;
8442 
8443 	return ret;
8444 }
8445 
DCconfig_get_triggers_by_triggerids(DC_TRIGGER * triggers,const zbx_uint64_t * triggerids,int * errcode,size_t num)8446 void	DCconfig_get_triggers_by_triggerids(DC_TRIGGER *triggers, const zbx_uint64_t *triggerids, int *errcode,
8447 		size_t num)
8448 {
8449 	size_t			i;
8450 	const ZBX_DC_TRIGGER	*dc_trigger;
8451 
8452 	RDLOCK_CACHE;
8453 
8454 	for (i = 0; i < num; i++)
8455 	{
8456 		if (NULL == (dc_trigger = (const ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerids[i])))
8457 		{
8458 			errcode[i] = FAIL;
8459 			continue;
8460 		}
8461 
8462 		DCget_trigger(&triggers[i], dc_trigger);
8463 		errcode[i] = SUCCEED;
8464 	}
8465 
8466 	UNLOCK_CACHE;
8467 }
8468 
8469 /******************************************************************************
8470  *                                                                            *
8471  * Function: DCconfig_get_functions_by_functionids                            *
8472  *                                                                            *
8473  * Purpose: Get functions by IDs                                              *
8474  *                                                                            *
8475  * Parameters: functions   - [OUT] pointer to DC_FUNCTION structures          *
8476  *             functionids - [IN] array of function IDs                       *
8477  *             errcodes    - [OUT] SUCCEED if item found, otherwise FAIL      *
8478  *             num         - [IN] number of elements                          *
8479  *                                                                            *
8480  * Author: Aleksandrs Saveljevs, Alexander Vladishev                          *
8481  *                                                                            *
8482  ******************************************************************************/
DCconfig_get_functions_by_functionids(DC_FUNCTION * functions,zbx_uint64_t * functionids,int * errcodes,size_t num)8483 void	DCconfig_get_functions_by_functionids(DC_FUNCTION *functions, zbx_uint64_t *functionids, int *errcodes,
8484 		size_t num)
8485 {
8486 	size_t			i;
8487 	const ZBX_DC_FUNCTION	*dc_function;
8488 
8489 	RDLOCK_CACHE;
8490 
8491 	for (i = 0; i < num; i++)
8492 	{
8493 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids[i])))
8494 		{
8495 			errcodes[i] = FAIL;
8496 			continue;
8497 		}
8498 
8499 		DCget_function(&functions[i], dc_function);
8500 		errcodes[i] = SUCCEED;
8501 	}
8502 
8503 	UNLOCK_CACHE;
8504 }
8505 
8506 /******************************************************************************
8507  *                                                                            *
8508  * Function: DCconfig_clean_functions                                         *
8509  *                                                                            *
8510  * Author: Alexander Vladishev                                                *
8511  *                                                                            *
8512  ******************************************************************************/
DCconfig_clean_functions(DC_FUNCTION * functions,int * errcodes,size_t num)8513 void	DCconfig_clean_functions(DC_FUNCTION *functions, int *errcodes, size_t num)
8514 {
8515 	size_t	i;
8516 
8517 	for (i = 0; i < num; i++)
8518 	{
8519 		if (SUCCEED != errcodes[i])
8520 			continue;
8521 
8522 		zbx_free(functions[i].function);
8523 	}
8524 }
8525 
DCconfig_clean_triggers(DC_TRIGGER * triggers,int * errcodes,size_t num)8526 void	DCconfig_clean_triggers(DC_TRIGGER *triggers, int *errcodes, size_t num)
8527 {
8528 	size_t	i;
8529 
8530 	for (i = 0; i < num; i++)
8531 	{
8532 		if (SUCCEED != errcodes[i])
8533 			continue;
8534 
8535 		DCclean_trigger(&triggers[i]);
8536 	}
8537 }
8538 
8539 /******************************************************************************
8540  *                                                                            *
8541  * Function: DCconfig_lock_triggers_by_history_items                          *
8542  *                                                                            *
8543  * Purpose: Lock triggers for specified items so that multiple processes do   *
8544  *          not process one trigger simultaneously. Otherwise, this leads to  *
8545  *          problems like multiple successive OK events or escalations being  *
8546  *          started and not cancelled, because they are not seen in parallel  *
8547  *          transactions.                                                     *
8548  *                                                                            *
8549  * Parameters: history_items - [IN/OUT] list of history items history syncer  *
8550  *                                    wishes to take for processing; on       *
8551  *                                    output, the item locked field is set    *
8552  *                                    to 0 if the corresponding item cannot   *
8553  *                                    be taken                                *
8554  *             triggerids  - [OUT] list of trigger IDs that this function has *
8555  *                                 locked for processing; unlock those using  *
8556  *                                 DCconfig_unlock_triggers() function        *
8557  *                                                                            *
8558  * Author: Aleksandrs Saveljevs                                               *
8559  *                                                                            *
8560  * Comments: This does not solve the problem fully (e.g., ZBX-7484). There is *
8561  *           a significant time period between the place where we lock the    *
8562  *           triggers and the place where we process them. So it could happen *
8563  *           that a configuration cache update happens after we have locked   *
8564  *           the triggers and it turns out that in the updated configuration  *
8565  *           there is a new trigger for two of the items that two different   *
8566  *           history syncers have taken for processing. In that situation,    *
8567  *           the problem we are solving here might still happen. However,     *
8568  *           locking triggers makes this problem much less likely and only in *
8569  *           case configuration changes. On a stable configuration, it should *
8570  *           work without any problems.                                       *
8571  *                                                                            *
8572  * Return value: the number of items available for processing (unlocked).     *
8573  *                                                                            *
8574  ******************************************************************************/
DCconfig_lock_triggers_by_history_items(zbx_vector_ptr_t * history_items,zbx_vector_uint64_t * triggerids)8575 int	DCconfig_lock_triggers_by_history_items(zbx_vector_ptr_t *history_items, zbx_vector_uint64_t *triggerids)
8576 {
8577 	int			i, j, locked_num = 0;
8578 	const ZBX_DC_ITEM	*dc_item;
8579 	ZBX_DC_TRIGGER		*dc_trigger;
8580 	zbx_hc_item_t		*history_item;
8581 
8582 	WRLOCK_CACHE;
8583 
8584 	for (i = 0; i < history_items->values_num; i++)
8585 	{
8586 		history_item = (zbx_hc_item_t *)history_items->values[i];
8587 
8588 		if (0 != (ZBX_DC_FLAG_NOVALUE & history_item->tail->flags))
8589 			continue;
8590 
8591 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &history_item->itemid)))
8592 			continue;
8593 
8594 		if (NULL == dc_item->triggers)
8595 			continue;
8596 
8597 		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
8598 		{
8599 			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
8600 				continue;
8601 
8602 			if (1 == dc_trigger->locked)
8603 			{
8604 				locked_num++;
8605 				history_item->status = ZBX_HC_ITEM_STATUS_BUSY;
8606 				goto next;
8607 			}
8608 		}
8609 
8610 		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
8611 		{
8612 			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
8613 				continue;
8614 
8615 			dc_trigger->locked = 1;
8616 			zbx_vector_uint64_append(triggerids, dc_trigger->triggerid);
8617 		}
8618 next:;
8619 	}
8620 
8621 	UNLOCK_CACHE;
8622 
8623 	return history_items->values_num - locked_num;
8624 }
8625 
8626 /******************************************************************************
8627  *                                                                            *
8628  * Function: DCconfig_lock_triggers_by_triggerids                             *
8629  *                                                                            *
8630  * Purpose: Lock triggers so that multiple processes do not process one       *
8631  *          trigger simultaneously.                                           *
8632  *                                                                            *
8633  * Parameters: triggerids_in  - [IN] ids of triggers to lock                  *
8634  *             triggerids_out - [OUT] ids of locked triggers                  *
8635  *                                                                            *
8636  ******************************************************************************/
DCconfig_lock_triggers_by_triggerids(zbx_vector_uint64_t * triggerids_in,zbx_vector_uint64_t * triggerids_out)8637 void	DCconfig_lock_triggers_by_triggerids(zbx_vector_uint64_t *triggerids_in, zbx_vector_uint64_t *triggerids_out)
8638 {
8639 	int		i;
8640 	ZBX_DC_TRIGGER	*dc_trigger;
8641 
8642 	if (0 == triggerids_in->values_num)
8643 		return;
8644 
8645 	WRLOCK_CACHE;
8646 
8647 	for (i = 0; i < triggerids_in->values_num; i++)
8648 	{
8649 		if (NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerids_in->values[i])))
8650 			continue;
8651 
8652 		if (1 == dc_trigger->locked)
8653 			continue;
8654 
8655 		dc_trigger->locked = 1;
8656 		zbx_vector_uint64_append(triggerids_out, dc_trigger->triggerid);
8657 	}
8658 
8659 	UNLOCK_CACHE;
8660 }
8661 
8662 /******************************************************************************
8663  *                                                                            *
8664  * Function: DCconfig_unlock_triggers                                         *
8665  *                                                                            *
8666  * Author: Aleksandrs Saveljevs                                               *
8667  *                                                                            *
8668  ******************************************************************************/
DCconfig_unlock_triggers(const zbx_vector_uint64_t * triggerids)8669 void	DCconfig_unlock_triggers(const zbx_vector_uint64_t *triggerids)
8670 {
8671 	int		i;
8672 	ZBX_DC_TRIGGER	*dc_trigger;
8673 
8674 	/* no other process can modify already locked triggers without write lock */
8675 	RDLOCK_CACHE;
8676 
8677 	for (i = 0; i < triggerids->values_num; i++)
8678 	{
8679 		if (NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerids->values[i])))
8680 			continue;
8681 
8682 		dc_trigger->locked = 0;
8683 	}
8684 
8685 	UNLOCK_CACHE;
8686 }
8687 
8688 /******************************************************************************
8689  *                                                                            *
8690  * Function: DCconfig_unlock_all_triggers                                     *
8691  *                                                                            *
8692  * Purpose: Unlocks all locked triggers before doing full history sync at     *
8693  *          program exit                                                      *
8694  *                                                                            *
8695  ******************************************************************************/
DCconfig_unlock_all_triggers(void)8696 void	DCconfig_unlock_all_triggers(void)
8697 {
8698 	ZBX_DC_TRIGGER		*dc_trigger;
8699 	zbx_hashset_iter_t	iter;
8700 
8701 	WRLOCK_CACHE;
8702 
8703 	zbx_hashset_iter_reset(&config->triggers, &iter);
8704 
8705 	while (NULL != (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
8706 		dc_trigger->locked = 0;
8707 
8708 	UNLOCK_CACHE;
8709 }
8710 
8711 /******************************************************************************
8712  *                                                                            *
8713  * Function: DCconfig_get_triggers_by_itemids                                 *
8714  *                                                                            *
8715  * Purpose: get enabled triggers for specified items                          *
8716  *                                                                            *
8717  * Author: Aleksandrs Saveljevs                                               *
8718  *                                                                            *
8719  ******************************************************************************/
DCconfig_get_triggers_by_itemids(zbx_hashset_t * trigger_info,zbx_vector_ptr_t * trigger_order,const zbx_uint64_t * itemids,const zbx_timespec_t * timespecs,int itemids_num)8720 void	DCconfig_get_triggers_by_itemids(zbx_hashset_t *trigger_info, zbx_vector_ptr_t *trigger_order,
8721 		const zbx_uint64_t *itemids, const zbx_timespec_t *timespecs, int itemids_num)
8722 {
8723 	int			i, j, found;
8724 	const ZBX_DC_ITEM	*dc_item;
8725 	const ZBX_DC_TRIGGER	*dc_trigger;
8726 	DC_TRIGGER		*trigger;
8727 
8728 	RDLOCK_CACHE;
8729 
8730 	for (i = 0; i < itemids_num; i++)
8731 	{
8732 		/* skip items which are not in configuration cache and items without triggers */
8733 
8734 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])) || NULL == dc_item->triggers)
8735 			continue;
8736 
8737 		/* process all triggers for the specified item */
8738 
8739 		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
8740 		{
8741 			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
8742 				continue;
8743 
8744 			/* find trigger by id or create a new record in hashset if not found */
8745 			trigger = (DC_TRIGGER *)DCfind_id(trigger_info, dc_trigger->triggerid, sizeof(DC_TRIGGER), &found);
8746 
8747 			if (0 == found)
8748 			{
8749 				DCget_trigger(trigger, dc_trigger);
8750 				zbx_vector_ptr_append(trigger_order, trigger);
8751 			}
8752 
8753 			/* copy latest change timestamp */
8754 
8755 			if (trigger->timespec.sec < timespecs[i].sec ||
8756 					(trigger->timespec.sec == timespecs[i].sec &&
8757 					trigger->timespec.ns < timespecs[i].ns))
8758 			{
8759 				/* DCconfig_get_triggers_by_itemids() function is called during trigger processing */
8760 				/* when syncing history cache. A trigger cannot be processed by two syncers at the */
8761 				/* same time, so its safe to update trigger timespec within read lock.             */
8762 				trigger->timespec = timespecs[i];
8763 			}
8764 		}
8765 	}
8766 
8767 	UNLOCK_CACHE;
8768 }
8769 
8770 /******************************************************************************
8771  *                                                                            *
8772  * Function: DCconfig_find_active_time_function                               *
8773  *                                                                            *
8774  * Purpose: check if the expression contains time based functions             *
8775  *                                                                            *
8776  * Parameters: expression    - [IN] the original expression                   *
8777  *             data          - [IN] the parsed and serialized expression      *
8778  *             trigger_timer - [IN] the trigger time function flags           *
8779  *                                                                            *
8780  ******************************************************************************/
DCconfig_find_active_time_function(const char * expression,const unsigned char * data,unsigned char trigger_timer)8781 static int	DCconfig_find_active_time_function(const char *expression, const unsigned char *data,
8782 		unsigned char trigger_timer)
8783 {
8784 	int			i, ret = SUCCEED;
8785 	const ZBX_DC_FUNCTION	*dc_function;
8786 	const ZBX_DC_HOST	*dc_host;
8787 	const ZBX_DC_ITEM	*dc_item;
8788 	zbx_vector_uint64_t	functionids;
8789 
8790 	zbx_vector_uint64_create(&functionids);
8791 	zbx_get_serialized_expression_functionids(expression, data, &functionids);
8792 
8793 	for (i = 0; i < functionids.values_num; i++)
8794 	{
8795 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions,
8796 				&functionids.values[i])))
8797 		{
8798 			continue;
8799 		}
8800 
8801 		if (ZBX_TRIGGER_TIMER_DEFAULT != trigger_timer || ZBX_FUNCTION_TYPE_TRENDS == dc_function->type ||
8802 				ZBX_FUNCTION_TYPE_TIMER == dc_function->type)
8803 		{
8804 			if (NULL == (dc_item = zbx_hashset_search(&config->items, &dc_function->itemid)))
8805 				continue;
8806 
8807 			if (NULL == (dc_host = zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8808 				continue;
8809 
8810 			if (SUCCEED != DCin_maintenance_without_data_collection(dc_host, dc_item))
8811 				goto out;
8812 		}
8813 	}
8814 
8815 	ret = (ZBX_TRIGGER_TIMER_DEFAULT != trigger_timer ? SUCCEED : FAIL);
8816 out:
8817 	zbx_vector_uint64_destroy(&functionids);
8818 
8819 	return ret;
8820 }
8821 
8822 /******************************************************************************
8823  *                                                                            *
8824  * Function: zbx_dc_get_triggers_by_timers                                    *
8825  *                                                                            *
8826  * Purpose: gets timer triggers from cache                                    *
8827  *                                                                            *
8828  * Parameters: trigger_info  - [IN/OUT] triggers                              *
8829  *             trigger_order - [IN/OUT] triggers in processing order          *
8830  *             timers        - [IN] timers of triggers to retrieve            *
8831  *                                                                            *
8832  ******************************************************************************/
zbx_dc_get_triggers_by_timers(zbx_hashset_t * trigger_info,zbx_vector_ptr_t * trigger_order,const zbx_vector_ptr_t * timers)8833 void	zbx_dc_get_triggers_by_timers(zbx_hashset_t *trigger_info, zbx_vector_ptr_t *trigger_order,
8834 		const zbx_vector_ptr_t *timers)
8835 {
8836 	int		i;
8837 	ZBX_DC_TRIGGER	*dc_trigger;
8838 
8839 	RDLOCK_CACHE;
8840 
8841 	for (i = 0; i < timers->values_num; i++)
8842 	{
8843 		zbx_trigger_timer_t	*timer = (zbx_trigger_timer_t *)timers->values[i];
8844 
8845 		/* skip timers of 'busy' (being processed) triggers */
8846 		if (0 == timer->lock)
8847 			continue;
8848 
8849 		if (NULL != (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &timer->triggerid)))
8850 		{
8851 			DC_TRIGGER	*trigger, trigger_local;
8852 			unsigned char	flags;
8853 
8854 			if (SUCCEED == DCconfig_find_active_time_function(dc_trigger->expression,
8855 					dc_trigger->expression_bin, dc_trigger->timer & ZBX_TRIGGER_TIMER_EXPRESSION))
8856 			{
8857 				flags = ZBX_DC_TRIGGER_PROBLEM_EXPRESSION;
8858 			}
8859 			else
8860 			{
8861 				if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION != dc_trigger->recovery_mode)
8862 					continue;
8863 
8864 				if (TRIGGER_VALUE_PROBLEM != dc_trigger->value)
8865 					continue;
8866 
8867 				if (SUCCEED != DCconfig_find_active_time_function(dc_trigger->recovery_expression,
8868 						dc_trigger->recovery_expression_bin,
8869 						dc_trigger->timer & ZBX_TRIGGER_TIMER_RECOVERY_EXPRESSION))
8870 				{
8871 					continue;
8872 				}
8873 
8874 				flags = 0;
8875 			}
8876 
8877 			trigger_local.triggerid = dc_trigger->triggerid;
8878 			trigger = (DC_TRIGGER *)zbx_hashset_insert(trigger_info, &trigger_local, sizeof(trigger_local));
8879 			DCget_trigger(trigger, dc_trigger);
8880 
8881 			trigger->timespec = timer->eval_ts;
8882 			trigger->flags = flags;
8883 
8884 			zbx_vector_ptr_append(trigger_order, trigger);
8885 		}
8886 	}
8887 
8888 	UNLOCK_CACHE;
8889 }
8890 
8891 /******************************************************************************
8892  *                                                                            *
8893  * Function: trigger_timer_validate                                           *
8894  *                                                                            *
8895  * Purpose: validate trigger timer                                            *
8896  *                                                                            *
8897  * Parameters: timer      - [IN] trigger timer                                *
8898  *             dc_trigger - [OUT] the trigger data                            *
8899  *                                                                            *
8900  * Return value: SUCCEED - the timer is valid                                 *
8901  *               FAIL    - otherwise                                          *
8902  *                                                                            *
8903  ******************************************************************************/
trigger_timer_validate(zbx_trigger_timer_t * timer,ZBX_DC_TRIGGER ** dc_trigger)8904 static int	trigger_timer_validate(zbx_trigger_timer_t *timer, ZBX_DC_TRIGGER **dc_trigger)
8905 {
8906 	ZBX_DC_FUNCTION		*dc_function;
8907 
8908 	*dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &timer->triggerid);
8909 
8910 	if (0 != (timer->type & ZBX_TRIGGER_TIMER_FUNCTION))
8911 	{
8912 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &timer->objectid)))
8913 			return FAIL;
8914 
8915 		if (dc_function->revision > timer->revision ||
8916 				NULL == *dc_trigger ||
8917 				TRIGGER_STATUS_ENABLED != (*dc_trigger)->status ||
8918 				TRIGGER_FUNCTIONAL_TRUE != (*dc_trigger)->functional)
8919 		{
8920 			if (dc_function->timer_revision == timer->revision)
8921 				dc_function->timer_revision = 0;
8922 			return FAIL;
8923 		}
8924 	}
8925 	else
8926 	{
8927 		if (NULL == (*dc_trigger))
8928 			return FAIL;
8929 
8930 		if ((*dc_trigger)->revision > timer->revision ||
8931 				TRIGGER_STATUS_ENABLED != (*dc_trigger)->status ||
8932 				TRIGGER_FUNCTIONAL_TRUE != (*dc_trigger)->functional)
8933 		{
8934 			if ((*dc_trigger)->timer_revision == timer->revision)
8935 				(*dc_trigger)->timer_revision = 0;
8936 			return FAIL;
8937 		}
8938 	}
8939 
8940 	return SUCCEED;
8941 }
8942 
8943 /******************************************************************************
8944  *                                                                            *
8945  * Function: zbx_dc_get_trigger_timers                                        *
8946  *                                                                            *
8947  * Purpose: gets timers from trigger queue                                    *
8948  *                                                                            *
8949  * Parameters: timers     - [OUT] the timer triggers that must be processed   *
8950  *             now        - [IN] current time                                 *
8951  *             soft_limit - [IN] the number of timers to return unless timers *
8952  *                               of the same trigger are split over multiple  *
8953  *                               batches.                                     *
8954  *                                                                            *
8955  *             hard_limit - [IN] the maximum number of timers to return       *
8956  *                                                                            *
8957  * Comments: This function locks corresponding triggers in configuration      *
8958  *           cache.                                                           *
8959  *           If the returned timer has lock field set, then trigger is        *
8960  *           already being processed and should not be recalculated.          *
8961  *                                                                            *
8962  ******************************************************************************/
zbx_dc_get_trigger_timers(zbx_vector_ptr_t * timers,int now,int soft_limit,int hard_limit)8963 void	zbx_dc_get_trigger_timers(zbx_vector_ptr_t *timers, int now, int soft_limit, int hard_limit)
8964 {
8965 	zbx_trigger_timer_t	*first_timer = NULL, *timer;
8966 	int			found = 0;
8967 	zbx_binary_heap_elem_t	*elem;
8968 
8969 	RDLOCK_CACHE;
8970 
8971 	if (SUCCEED != zbx_binary_heap_empty(&config->trigger_queue))
8972 	{
8973 		elem = zbx_binary_heap_find_min(&config->trigger_queue);
8974 		timer = (zbx_trigger_timer_t *)elem->data;
8975 
8976 		if (timer->exec_ts.sec <= now)
8977 			found = 1;
8978 	}
8979 
8980 	UNLOCK_CACHE;
8981 
8982 	if (0 == found)
8983 		return;
8984 
8985 	WRLOCK_CACHE;
8986 
8987 	while (SUCCEED != zbx_binary_heap_empty(&config->trigger_queue) && timers->values_num < hard_limit)
8988 	{
8989 		ZBX_DC_TRIGGER		*dc_trigger;
8990 
8991 		elem = zbx_binary_heap_find_min(&config->trigger_queue);
8992 		timer = (zbx_trigger_timer_t *)elem->data;
8993 
8994 		if (timer->exec_ts.sec > now)
8995 			break;
8996 
8997 		/* first_timer stores the first timer from a list of timers of the same trigger with the same */
8998 		/* evaluation timestamp. Reset first_timer if the conditions do not apply.                    */
8999 		if (NULL != first_timer && (timer->triggerid != first_timer->triggerid ||
9000 				0 != zbx_timespec_compare(&timer->eval_ts, &first_timer->eval_ts)))
9001 		{
9002 			first_timer = NULL;
9003 		}
9004 
9005 		/* use soft limit to avoid (mostly) splitting multiple functions of the same trigger */
9006 		/* over consequent batches                                                           */
9007 		if (timers->values_num >= soft_limit && NULL == first_timer)
9008 			break;
9009 
9010 		zbx_binary_heap_remove_min(&config->trigger_queue);
9011 
9012 		if (SUCCEED != trigger_timer_validate(timer, &dc_trigger))
9013 		{
9014 			dc_trigger_timer_free(timer);
9015 			continue;
9016 		}
9017 
9018 		zbx_vector_ptr_append(timers, timer);
9019 
9020 		/* Trigger expression must be calculated using function evaluation time. If a trigger is locked   */
9021 		/* keep rescheduling its timer until trigger is unlocked and can be calculated using the required */
9022 		/* evaluation time. However there are exceptions when evaluation time of a locked trigger is      */
9023 		/* acceptable to evaluate other functions:                                                        */
9024 		/*  1) time functions uses current time, so trigger evaluation time does not affect their results */
9025 		/*  2) trend function of the same trigger with the same evaluation timestamp is being             */
9026 		/*     evaluated by the same process                                                              */
9027 		if (0 == dc_trigger->locked || ZBX_TRIGGER_TIMER_FUNCTION_TREND != timer->type ||
9028 				(NULL != first_timer && 1 == first_timer->lock))
9029 		{
9030 			/* resetting execution timer will cause a new execution time to be set */
9031 			/* when timer is put back into queue                                   */
9032 			timer->exec_ts.sec = 0;
9033 		}
9034 
9035 		/* remember if the timer locked trigger, so it would unlock during rescheduling */
9036 		if (0 == dc_trigger->locked)
9037 			dc_trigger->locked = timer->lock = 1;
9038 
9039 		if (NULL == first_timer)
9040 			first_timer = timer;
9041 	}
9042 
9043 	UNLOCK_CACHE;
9044 }
9045 
9046 /******************************************************************************
9047  *                                                                            *
9048  * Function: dc_reschedule_trigger_timers                                     *
9049  *                                                                            *
9050  * Purpose: reschedule trigger timers                                         *
9051  *                                                                            *
9052  * Comments: Triggers are unlocked by DCconfig_unlock_triggers()              *
9053  *                                                                            *
9054  ******************************************************************************/
dc_reschedule_trigger_timers(zbx_vector_ptr_t * timers)9055 static void	dc_reschedule_trigger_timers(zbx_vector_ptr_t *timers)
9056 {
9057 	int	i;
9058 
9059 	for (i = 0; i < timers->values_num; i++)
9060 	{
9061 		zbx_trigger_timer_t	*timer = (zbx_trigger_timer_t *)timers->values[i];
9062 
9063 		timer->lock = 0;
9064 
9065 		/* schedule calculation error can result in 0 execution time */
9066 		if (0 == timer->exec_ts.sec)
9067 		{
9068 			if (0 != (timer->type & ZBX_TRIGGER_TIMER_FUNCTION))
9069 			{
9070 				ZBX_DC_FUNCTION	*function;
9071 
9072 				if (NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions,
9073 						&timer->objectid)) && function->timer_revision == timer->revision)
9074 				{
9075 					function->timer_revision = 0;
9076 				}
9077 			}
9078 			else if (ZBX_TRIGGER_TIMER_TRIGGER == timer->type)
9079 			{
9080 				ZBX_DC_TRIGGER	*trigger;
9081 
9082 				if (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers,
9083 						&timer->objectid)) && trigger->timer_revision == timer->revision)
9084 				{
9085 					trigger->timer_revision = 0;
9086 				}
9087 			}
9088 			dc_trigger_timer_free(timer);
9089 		}
9090 		else
9091 			dc_schedule_trigger_timer(timer, &timer->eval_ts, &timer->exec_ts);
9092 	}
9093 }
9094 
9095 /******************************************************************************
9096  *                                                                            *
9097  * Function: zbx_dc_reschedule_trigger_timers                                 *
9098  *                                                                            *
9099  * Purpose: reschedule trigger timers while locking configuration cache       *
9100  *                                                                            *
9101  * Comments: Triggers are unlocked by DCconfig_unlock_triggers()              *
9102  *                                                                            *
9103  ******************************************************************************/
zbx_dc_reschedule_trigger_timers(zbx_vector_ptr_t * timers,int now)9104 void	zbx_dc_reschedule_trigger_timers(zbx_vector_ptr_t *timers, int now)
9105 {
9106 	int	i;
9107 
9108 	/* calculate new execution/evaluation time for the evaluated triggers */
9109 	/* (timers with reseted execution time)                               */
9110 	for (i = 0; i < timers->values_num; i++)
9111 	{
9112 		zbx_trigger_timer_t	*timer = (zbx_trigger_timer_t *)timers->values[i];
9113 
9114 		if (0 == timer->exec_ts.sec)
9115 		{
9116 			if (0 != (timer->exec_ts.sec = dc_function_calculate_nextcheck(timer, now, timer->triggerid)))
9117 				timer->eval_ts = timer->exec_ts;
9118 		}
9119 	}
9120 
9121 	WRLOCK_CACHE;
9122 	dc_reschedule_trigger_timers(timers);
9123 	UNLOCK_CACHE;
9124 }
9125 
9126 /******************************************************************************
9127  *                                                                            *
9128  * Function: zbx_dc_get_timer_queue                                           *
9129  *                                                                            *
9130  * Purpose: clears timer trigger queue                                        *
9131  *                                                                            *
9132  ******************************************************************************/
zbx_dc_clear_timer_queue(zbx_vector_ptr_t * timers)9133 void	zbx_dc_clear_timer_queue(zbx_vector_ptr_t *timers)
9134 {
9135 	ZBX_DC_FUNCTION	*function;
9136 	int		i;
9137 
9138 	zbx_vector_ptr_reserve(timers, config->trigger_queue.elems_num);
9139 
9140 	WRLOCK_CACHE;
9141 
9142 	for (i = 0; i < config->trigger_queue.elems_num; i++)
9143 	{
9144 		zbx_trigger_timer_t	*timer = (zbx_trigger_timer_t *)config->trigger_queue.elems[i].data;
9145 
9146 		if (ZBX_TRIGGER_TIMER_FUNCTION_TREND == timer->type &&
9147 				NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions,
9148 						&timer->objectid)) &&
9149 				function->timer_revision == timer->revision)
9150 		{
9151 			zbx_vector_ptr_append(timers, timer);
9152 		}
9153 		else
9154 			dc_trigger_timer_free(timer);
9155 	}
9156 
9157 	zbx_binary_heap_clear(&config->trigger_queue);
9158 
9159 	UNLOCK_CACHE;
9160 }
9161 
9162 /******************************************************************************
9163  *                                                                            *
9164  * Function: zbx_dc_free_timers                                               *
9165  *                                                                            *
9166  ******************************************************************************/
zbx_dc_free_timers(zbx_vector_ptr_t * timers)9167 void	zbx_dc_free_timers(zbx_vector_ptr_t *timers)
9168 {
9169 	int	i;
9170 
9171 	WRLOCK_CACHE;
9172 
9173 	for (i = 0; i < timers->values_num; i++)
9174 		dc_trigger_timer_free(timers->values[i]);
9175 
9176 	UNLOCK_CACHE;
9177 }
9178 
DCfree_triggers(zbx_vector_ptr_t * triggers)9179 void	DCfree_triggers(zbx_vector_ptr_t *triggers)
9180 {
9181 	int	i;
9182 
9183 	for (i = 0; i < triggers->values_num; i++)
9184 		DCclean_trigger((DC_TRIGGER *)triggers->values[i]);
9185 
9186 	zbx_vector_ptr_clear(triggers);
9187 }
9188 
DCconfig_update_interface_snmp_stats(zbx_uint64_t interfaceid,int max_snmp_succeed,int min_snmp_fail)9189 void	DCconfig_update_interface_snmp_stats(zbx_uint64_t interfaceid, int max_snmp_succeed, int min_snmp_fail)
9190 {
9191 	ZBX_DC_SNMPINTERFACE	*dc_snmp;
9192 
9193 	WRLOCK_CACHE;
9194 
9195 	if (NULL != (dc_snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid)) &&
9196 			SNMP_BULK_ENABLED == dc_snmp->bulk)
9197 	{
9198 		if (dc_snmp->max_succeed < max_snmp_succeed)
9199 			dc_snmp->max_succeed = (unsigned char)max_snmp_succeed;
9200 
9201 		if (dc_snmp->min_fail > min_snmp_fail)
9202 			dc_snmp->min_fail = (unsigned char)min_snmp_fail;
9203 	}
9204 
9205 	UNLOCK_CACHE;
9206 }
9207 
DCconfig_get_suggested_snmp_vars_nolock(zbx_uint64_t interfaceid,int * bulk)9208 static int	DCconfig_get_suggested_snmp_vars_nolock(zbx_uint64_t interfaceid, int *bulk)
9209 {
9210 	int				num;
9211 	const ZBX_DC_SNMPINTERFACE	*dc_snmp;
9212 
9213 	dc_snmp = (const ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid);
9214 
9215 	if (NULL != bulk)
9216 		*bulk = (NULL == dc_snmp ? SNMP_BULK_DISABLED : dc_snmp->bulk);
9217 
9218 	if (NULL == dc_snmp || SNMP_BULK_ENABLED != dc_snmp->bulk)
9219 		return 1;
9220 
9221 	/* The general strategy is to multiply request size by 3/2 in order to approach the limit faster. */
9222 	/* However, once we are over the limit, we change the strategy to increasing the value by 1. This */
9223 	/* is deemed better than going backwards from the error because less timeouts are going to occur. */
9224 
9225 	if (1 >= dc_snmp->max_succeed || MAX_SNMP_ITEMS + 1 != dc_snmp->min_fail)
9226 		num = dc_snmp->max_succeed + 1;
9227 	else
9228 		num = dc_snmp->max_succeed * 3 / 2;
9229 
9230 	if (num < dc_snmp->min_fail)
9231 		return num;
9232 
9233 	/* If we have already found the optimal number of variables to query, we wish to base our suggestion on that */
9234 	/* number. If we occasionally get a timeout in this area, it can mean two things: either the device's actual */
9235 	/* limit is a bit lower than that (it can process requests above it, but only sometimes) or a UDP packet in  */
9236 	/* one of the directions was lost. In order to account for the former, we allow ourselves to lower the count */
9237 	/* of variables, but only up to two times. Otherwise, performance will gradually degrade due to the latter.  */
9238 
9239 	return MAX(dc_snmp->max_succeed - 2, dc_snmp->min_fail - 1);
9240 }
9241 
DCconfig_get_suggested_snmp_vars(zbx_uint64_t interfaceid,int * bulk)9242 int	DCconfig_get_suggested_snmp_vars(zbx_uint64_t interfaceid, int *bulk)
9243 {
9244 	int	ret;
9245 
9246 	RDLOCK_CACHE;
9247 
9248 	ret = DCconfig_get_suggested_snmp_vars_nolock(interfaceid, bulk);
9249 
9250 	UNLOCK_CACHE;
9251 
9252 	return ret;
9253 }
9254 
dc_get_interface_by_type(DC_INTERFACE * interface,zbx_uint64_t hostid,unsigned char type)9255 static int	dc_get_interface_by_type(DC_INTERFACE *interface, zbx_uint64_t hostid, unsigned char type)
9256 {
9257 	int				res = FAIL;
9258 	const ZBX_DC_INTERFACE		*dc_interface;
9259 	const ZBX_DC_INTERFACE_HT	*interface_ht;
9260 	ZBX_DC_INTERFACE_HT		interface_ht_local;
9261 
9262 	interface_ht_local.hostid = hostid;
9263 	interface_ht_local.type = type;
9264 
9265 	if (NULL != (interface_ht = (const ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local)))
9266 	{
9267 		dc_interface = interface_ht->interface_ptr;
9268 		DCget_interface(interface, dc_interface);
9269 		res = SUCCEED;
9270 	}
9271 
9272 	return res;
9273 }
9274 
9275 /******************************************************************************
9276  *                                                                            *
9277  * Function: DCconfig_get_interface_by_type                                   *
9278  *                                                                            *
9279  * Purpose: Locate main interface of specified type in configuration cache    *
9280  *                                                                            *
9281  * Parameters: interface - [OUT] pointer to DC_INTERFACE structure            *
9282  *             hostid - [IN] host ID                                          *
9283  *             type - [IN] interface type                                     *
9284  *                                                                            *
9285  * Return value: SUCCEED if record located and FAIL otherwise                 *
9286  *                                                                            *
9287  ******************************************************************************/
DCconfig_get_interface_by_type(DC_INTERFACE * interface,zbx_uint64_t hostid,unsigned char type)9288 int	DCconfig_get_interface_by_type(DC_INTERFACE *interface, zbx_uint64_t hostid, unsigned char type)
9289 {
9290 	int	res;
9291 
9292 	RDLOCK_CACHE;
9293 
9294 	res = dc_get_interface_by_type(interface, hostid, type);
9295 
9296 	UNLOCK_CACHE;
9297 
9298 	return res;
9299 }
9300 
9301 /******************************************************************************
9302  *                                                                            *
9303  * Function: DCconfig_get_interface                                           *
9304  *                                                                            *
9305  * Purpose: Locate interface in configuration cache                           *
9306  *                                                                            *
9307  * Parameters: interface - [OUT] pointer to DC_INTERFACE structure            *
9308  *             hostid - [IN] host ID                                          *
9309  *             itemid - [IN] item ID                                          *
9310  *                                                                            *
9311  * Return value: SUCCEED if record located and FAIL otherwise                 *
9312  *                                                                            *
9313  ******************************************************************************/
DCconfig_get_interface(DC_INTERFACE * interface,zbx_uint64_t hostid,zbx_uint64_t itemid)9314 int	DCconfig_get_interface(DC_INTERFACE *interface, zbx_uint64_t hostid, zbx_uint64_t itemid)
9315 {
9316 	int			res = FAIL, i;
9317 	const ZBX_DC_ITEM	*dc_item;
9318 	const ZBX_DC_INTERFACE	*dc_interface;
9319 
9320 	RDLOCK_CACHE;
9321 
9322 	if (0 != itemid)
9323 	{
9324 		if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
9325 			goto unlock;
9326 
9327 		if (0 != dc_item->interfaceid)
9328 		{
9329 			if (NULL == (dc_interface = (const ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces,
9330 					&dc_item->interfaceid)))
9331 			{
9332 				goto unlock;
9333 			}
9334 
9335 			DCget_interface(interface, dc_interface);
9336 			res = SUCCEED;
9337 			goto unlock;
9338 		}
9339 
9340 		hostid = dc_item->hostid;
9341 	}
9342 
9343 	if (0 == hostid)
9344 		goto unlock;
9345 
9346 	for (i = 0; i < (int)ARRSIZE(INTERFACE_TYPE_PRIORITY); i++)
9347 	{
9348 		if (SUCCEED == (res = dc_get_interface_by_type(interface, hostid, INTERFACE_TYPE_PRIORITY[i])))
9349 			break;
9350 	}
9351 
9352 unlock:
9353 	UNLOCK_CACHE;
9354 
9355 	return res;
9356 }
9357 
9358 /******************************************************************************
9359  *                                                                            *
9360  * Function: dc_config_get_queue_nextcheck                                    *
9361  *                                                                            *
9362  * Purpose: Get nextcheck for selected queue                                  *
9363  *                                                                            *
9364  * Parameters: queue - [IN] the queue                                         *
9365  *                                                                            *
9366  * Return value: nextcheck or FAIL if no items for the specified queue        *
9367  *                                                                            *
9368  ******************************************************************************/
dc_config_get_queue_nextcheck(zbx_binary_heap_t * queue)9369 static int	dc_config_get_queue_nextcheck(zbx_binary_heap_t *queue)
9370 {
9371 	int				nextcheck;
9372 	const zbx_binary_heap_elem_t	*min;
9373 	const ZBX_DC_ITEM		*dc_item;
9374 
9375 	if (FAIL == zbx_binary_heap_empty(queue))
9376 	{
9377 		min = zbx_binary_heap_find_min(queue);
9378 		dc_item = (const ZBX_DC_ITEM *)min->data;
9379 
9380 		nextcheck = dc_item->nextcheck;
9381 	}
9382 	else
9383 		nextcheck = FAIL;
9384 
9385 	return nextcheck;
9386 }
9387 
9388 /******************************************************************************
9389  *                                                                            *
9390  * Function: DCconfig_get_poller_nextcheck                                    *
9391  *                                                                            *
9392  * Purpose: Get nextcheck for selected poller                                 *
9393  *                                                                            *
9394  * Parameters: poller_type - [IN] poller type (ZBX_POLLER_TYPE_...)           *
9395  *                                                                            *
9396  * Return value: nextcheck or FAIL if no items for selected poller            *
9397  *                                                                            *
9398  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
9399  *                                                                            *
9400  ******************************************************************************/
DCconfig_get_poller_nextcheck(unsigned char poller_type)9401 int	DCconfig_get_poller_nextcheck(unsigned char poller_type)
9402 {
9403 	int			nextcheck;
9404 	zbx_binary_heap_t	*queue;
9405 
9406 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() poller_type:%d", __func__, (int)poller_type);
9407 
9408 	queue = &config->queues[poller_type];
9409 
9410 	RDLOCK_CACHE;
9411 
9412 	nextcheck = dc_config_get_queue_nextcheck(queue);
9413 
9414 	UNLOCK_CACHE;
9415 
9416 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, nextcheck);
9417 
9418 	return nextcheck;
9419 }
9420 
dc_requeue_item(ZBX_DC_ITEM * dc_item,const ZBX_DC_HOST * dc_host,const ZBX_DC_INTERFACE * dc_interface,int flags,int lastclock)9421 static void	dc_requeue_item(ZBX_DC_ITEM *dc_item, const ZBX_DC_HOST *dc_host, const ZBX_DC_INTERFACE *dc_interface,
9422 		int flags, int lastclock)
9423 {
9424 	unsigned char	old_poller_type;
9425 	int		old_nextcheck;
9426 
9427 	old_nextcheck = dc_item->nextcheck;
9428 	DCitem_nextcheck_update(dc_item, dc_interface, flags, lastclock, NULL);
9429 
9430 	old_poller_type = dc_item->poller_type;
9431 	DCitem_poller_type_update(dc_item, dc_host, flags);
9432 
9433 	DCupdate_item_queue(dc_item, old_poller_type, old_nextcheck);
9434 }
9435 
9436 /******************************************************************************
9437  *                                                                            *
9438  * Function: dc_requeue_item_at                                               *
9439  *                                                                            *
9440  * Purpose: requeues items at the specified time                              *
9441  *                                                                            *
9442  * Parameters: dc_item   - [IN] the item to reque                             *
9443  *             dc_host   - [IN] item's host                                   *
9444  *             nextcheck - [IN] the scheduled time                            *
9445  *                                                                            *
9446  ******************************************************************************/
dc_requeue_item_at(ZBX_DC_ITEM * dc_item,ZBX_DC_HOST * dc_host,int nextcheck)9447 static void	dc_requeue_item_at(ZBX_DC_ITEM *dc_item, ZBX_DC_HOST *dc_host, int nextcheck)
9448 {
9449 	unsigned char	old_poller_type;
9450 	int		old_nextcheck;
9451 
9452 	dc_item->queue_priority = ZBX_QUEUE_PRIORITY_HIGH;
9453 
9454 	old_nextcheck = dc_item->nextcheck;
9455 	dc_item->nextcheck = nextcheck;
9456 
9457 	old_poller_type = dc_item->poller_type;
9458 	DCitem_poller_type_update(dc_item, dc_host, ZBX_ITEM_COLLECTED);
9459 
9460 	DCupdate_item_queue(dc_item, old_poller_type, old_nextcheck);
9461 }
9462 
9463 /******************************************************************************
9464  *                                                                            *
9465  * Function: DCconfig_get_poller_items                                        *
9466  *                                                                            *
9467  * Purpose: Get array of items for selected poller                            *
9468  *                                                                            *
9469  * Parameters: poller_type - [IN] poller type (ZBX_POLLER_TYPE_...)           *
9470  *             items       - [OUT] array of items                             *
9471  *                                                                            *
9472  * Return value: number of items in items array                               *
9473  *                                                                            *
9474  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
9475  *                                                                            *
9476  * Comments: Items leave the queue only through this function. Pollers must   *
9477  *           always return the items they have taken using DCrequeue_items()  *
9478  *           or DCpoller_requeue_items().                                     *
9479  *                                                                            *
9480  *           Currently batch polling is supported only for JMX, SNMP and      *
9481  *           icmpping* simple checks. In other cases only single item is      *
9482  *           retrieved.                                                       *
9483  *                                                                            *
9484  *           IPMI poller queue are handled by DCconfig_get_ipmi_poller_items()*
9485  *           function.                                                        *
9486  *                                                                            *
9487  ******************************************************************************/
DCconfig_get_poller_items(unsigned char poller_type,DC_ITEM ** items)9488 int	DCconfig_get_poller_items(unsigned char poller_type, DC_ITEM **items)
9489 {
9490 	int			now, num = 0, max_items;
9491 	zbx_binary_heap_t	*queue;
9492 
9493 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() poller_type:%d", __func__, (int)poller_type);
9494 
9495 	now = time(NULL);
9496 
9497 	queue = &config->queues[poller_type];
9498 
9499 	switch (poller_type)
9500 	{
9501 		case ZBX_POLLER_TYPE_JAVA:
9502 			max_items = MAX_JAVA_ITEMS;
9503 			break;
9504 		case ZBX_POLLER_TYPE_PINGER:
9505 			max_items = MAX_PINGER_ITEMS;
9506 			break;
9507 		default:
9508 			max_items = 1;
9509 	}
9510 
9511 	WRLOCK_CACHE;
9512 
9513 	while (num < max_items && FAIL == zbx_binary_heap_empty(queue))
9514 	{
9515 		int				disable_until;
9516 		const zbx_binary_heap_elem_t	*min;
9517 		ZBX_DC_HOST			*dc_host;
9518 		ZBX_DC_INTERFACE		*dc_interface;
9519 		ZBX_DC_ITEM			*dc_item;
9520 		static const ZBX_DC_ITEM	*dc_item_prev = NULL;
9521 
9522 		min = zbx_binary_heap_find_min(queue);
9523 		dc_item = (ZBX_DC_ITEM *)min->data;
9524 
9525 		if (dc_item->nextcheck > now)
9526 			break;
9527 
9528 		if (0 != num)
9529 		{
9530 			if (ITEM_TYPE_SNMP == dc_item_prev->type)
9531 			{
9532 				if (0 != __config_snmp_item_compare(dc_item_prev, dc_item))
9533 					break;
9534 			}
9535 			else if (ITEM_TYPE_JMX == dc_item_prev->type)
9536 			{
9537 				if (0 != __config_java_item_compare(dc_item_prev, dc_item))
9538 					break;
9539 			}
9540 		}
9541 
9542 		zbx_binary_heap_remove_min(queue);
9543 		dc_item->location = ZBX_LOC_NOWHERE;
9544 
9545 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
9546 			continue;
9547 
9548 		dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &dc_item->interfaceid);
9549 
9550 		if (HOST_STATUS_MONITORED != dc_host->status)
9551 			continue;
9552 
9553 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
9554 		{
9555 			dc_requeue_item(dc_item, dc_host, dc_interface, ZBX_ITEM_COLLECTED, now);
9556 			continue;
9557 		}
9558 
9559 		/* don't apply unreachable item/host throttling for prioritized items */
9560 		if (ZBX_QUEUE_PRIORITY_HIGH != dc_item->queue_priority)
9561 		{
9562 			if (0 == (disable_until = DCget_disable_until(dc_item, dc_interface)))
9563 			{
9564 				/* move reachable items on reachable hosts to normal pollers */
9565 				if (ZBX_POLLER_TYPE_UNREACHABLE == poller_type &&
9566 						ZBX_QUEUE_PRIORITY_LOW != dc_item->queue_priority)
9567 				{
9568 					dc_requeue_item(dc_item, dc_host, dc_interface, ZBX_ITEM_COLLECTED, now);
9569 					continue;
9570 				}
9571 			}
9572 			else
9573 			{
9574 				/* move items on unreachable hosts to unreachable pollers or    */
9575 				/* postpone checks on hosts that have been checked recently and */
9576 				/* are still unreachable                                        */
9577 				if (ZBX_POLLER_TYPE_NORMAL == poller_type || ZBX_POLLER_TYPE_JAVA == poller_type ||
9578 						disable_until > now)
9579 				{
9580 					dc_requeue_item(dc_item, dc_host, dc_interface,
9581 							ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE, now);
9582 					continue;
9583 				}
9584 
9585 				DCincrease_disable_until(dc_interface, now);
9586 			}
9587 		}
9588 
9589 		if (0 == num)
9590 		{
9591 			if (ZBX_POLLER_TYPE_NORMAL == poller_type && ITEM_TYPE_SNMP == dc_item->type &&
9592 					0 == (ZBX_FLAG_DISCOVERY_RULE & dc_item->flags))
9593 			{
9594 				ZBX_DC_SNMPITEM	*snmpitem;
9595 
9596 				snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &dc_item->itemid);
9597 
9598 				if (ZBX_SNMP_OID_TYPE_NORMAL == snmpitem->snmp_oid_type ||
9599 						ZBX_SNMP_OID_TYPE_DYNAMIC == snmpitem->snmp_oid_type)
9600 				{
9601 					max_items = DCconfig_get_suggested_snmp_vars_nolock(dc_item->interfaceid, NULL);
9602 				}
9603 			}
9604 
9605 			if (1 < max_items)
9606 				*items = zbx_malloc(NULL, sizeof(DC_ITEM) * max_items);
9607 		}
9608 
9609 		dc_item_prev = dc_item;
9610 		dc_item->location = ZBX_LOC_POLLER;
9611 		DCget_host(&(*items)[num].host, dc_host, ZBX_ITEM_GET_ALL);
9612 		DCget_item(&(*items)[num], dc_item, ZBX_ITEM_GET_ALL);
9613 		num++;
9614 	}
9615 
9616 	UNLOCK_CACHE;
9617 
9618 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, num);
9619 
9620 	return num;
9621 }
9622 
9623 /******************************************************************************
9624  *                                                                            *
9625  * Function: DCconfig_get_ipmi_poller_items                                   *
9626  *                                                                            *
9627  * Purpose: Get array of items for IPMI poller                                *
9628  *                                                                            *
9629  * Parameters: now       - [IN] current timestamp                             *
9630  *             items     - [OUT] array of items                               *
9631  *             items_num - [IN] the number of items to get                    *
9632  *             nextcheck - [OUT] the next scheduled check                     *
9633  *                                                                            *
9634  * Return value: number of items in items array                               *
9635  *                                                                            *
9636  * Comments: IPMI items leave the queue only through this function. IPMI      *
9637  *           manager must always return the items they have taken using       *
9638  *           DCrequeue_items() or DCpoller_requeue_items().                   *
9639  *                                                                            *
9640  ******************************************************************************/
DCconfig_get_ipmi_poller_items(int now,DC_ITEM * items,int items_num,int * nextcheck)9641 int	DCconfig_get_ipmi_poller_items(int now, DC_ITEM *items, int items_num, int *nextcheck)
9642 {
9643 	int			num = 0;
9644 	zbx_binary_heap_t	*queue;
9645 
9646 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
9647 
9648 	queue = &config->queues[ZBX_POLLER_TYPE_IPMI];
9649 
9650 	WRLOCK_CACHE;
9651 
9652 	while (num < items_num && FAIL == zbx_binary_heap_empty(queue))
9653 	{
9654 		int				disable_until;
9655 		const zbx_binary_heap_elem_t	*min;
9656 		ZBX_DC_HOST			*dc_host;
9657 		ZBX_DC_INTERFACE		*dc_interface;
9658 		ZBX_DC_ITEM			*dc_item;
9659 
9660 		min = zbx_binary_heap_find_min(queue);
9661 		dc_item = (ZBX_DC_ITEM *)min->data;
9662 
9663 		if (dc_item->nextcheck > now)
9664 			break;
9665 
9666 		zbx_binary_heap_remove_min(queue);
9667 		dc_item->location = ZBX_LOC_NOWHERE;
9668 
9669 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
9670 			continue;
9671 
9672 		if (HOST_STATUS_MONITORED != dc_host->status)
9673 			continue;
9674 
9675 		if (NULL == (dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces,
9676 				&dc_item->interfaceid)))
9677 		{
9678 			continue;
9679 		}
9680 
9681 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
9682 		{
9683 			dc_requeue_item(dc_item, dc_host, dc_interface, ZBX_ITEM_COLLECTED, now);
9684 			continue;
9685 		}
9686 
9687 		/* don't apply unreachable item/host throttling for prioritized items */
9688 		if (ZBX_QUEUE_PRIORITY_HIGH != dc_item->queue_priority)
9689 		{
9690 			if (0 != (disable_until = DCget_disable_until(dc_item, dc_interface)))
9691 			{
9692 				if (disable_until > now)
9693 				{
9694 					dc_requeue_item(dc_item, dc_host, dc_interface,
9695 							ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE, now);
9696 					continue;
9697 				}
9698 
9699 				DCincrease_disable_until(dc_interface, now);
9700 			}
9701 		}
9702 
9703 		dc_item->location = ZBX_LOC_POLLER;
9704 		DCget_host(&items[num].host, dc_host, ZBX_ITEM_GET_ALL);
9705 		DCget_item(&items[num], dc_item, ZBX_ITEM_GET_ALL);
9706 		num++;
9707 	}
9708 
9709 	*nextcheck = dc_config_get_queue_nextcheck(&config->queues[ZBX_POLLER_TYPE_IPMI]);
9710 
9711 	UNLOCK_CACHE;
9712 
9713 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, num);
9714 
9715 	return num;
9716 }
9717 
9718 
9719 /******************************************************************************
9720  *                                                                            *
9721  * Function: DCconfig_get_snmp_interfaceids_by_addr                           *
9722  *                                                                            *
9723  * Purpose: get array of interface IDs for the specified address              *
9724  *                                                                            *
9725  * Return value: number of interface IDs returned                             *
9726  *                                                                            *
9727  * Author: Rudolfs Kreicbergs                                                 *
9728  *                                                                            *
9729  ******************************************************************************/
DCconfig_get_snmp_interfaceids_by_addr(const char * addr,zbx_uint64_t ** interfaceids)9730 int	DCconfig_get_snmp_interfaceids_by_addr(const char *addr, zbx_uint64_t **interfaceids)
9731 {
9732 	int				count = 0, i;
9733 	const ZBX_DC_INTERFACE_ADDR	*dc_interface_snmpaddr;
9734 	ZBX_DC_INTERFACE_ADDR		dc_interface_snmpaddr_local;
9735 
9736 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() addr:'%s'", __func__, addr);
9737 
9738 	dc_interface_snmpaddr_local.addr = addr;
9739 
9740 	RDLOCK_CACHE;
9741 
9742 	if (NULL == (dc_interface_snmpaddr = (const ZBX_DC_INTERFACE_ADDR *)zbx_hashset_search(&config->interface_snmpaddrs, &dc_interface_snmpaddr_local)))
9743 		goto unlock;
9744 
9745 	*interfaceids = (zbx_uint64_t *)zbx_malloc(*interfaceids, dc_interface_snmpaddr->interfaceids.values_num * sizeof(zbx_uint64_t));
9746 
9747 	for (i = 0; i < dc_interface_snmpaddr->interfaceids.values_num; i++)
9748 		(*interfaceids)[i] = dc_interface_snmpaddr->interfaceids.values[i];
9749 
9750 	count = i;
9751 unlock:
9752 	UNLOCK_CACHE;
9753 
9754 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, count);
9755 
9756 	return count;
9757 }
9758 
9759 /******************************************************************************
9760  *                                                                            *
9761  * Function: DCconfig_get_snmp_items_by_interfaceid                           *
9762  *                                                                            *
9763  * Purpose: get array of snmp trap items for the specified interfaceid        *
9764  *                                                                            *
9765  * Return value: number of items returned                                     *
9766  *                                                                            *
9767  * Author: Rudolfs Kreicbergs                                                 *
9768  *                                                                            *
9769  ******************************************************************************/
DCconfig_get_snmp_items_by_interfaceid(zbx_uint64_t interfaceid,DC_ITEM ** items)9770 size_t	DCconfig_get_snmp_items_by_interfaceid(zbx_uint64_t interfaceid, DC_ITEM **items)
9771 {
9772 	size_t				items_num = 0, items_alloc = 8;
9773 	int				i;
9774 	const ZBX_DC_ITEM		*dc_item;
9775 	const ZBX_DC_INTERFACE_ITEM	*dc_interface_snmpitem;
9776 	const ZBX_DC_INTERFACE		*dc_interface;
9777 	const ZBX_DC_HOST		*dc_host;
9778 
9779 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() interfaceid:" ZBX_FS_UI64, __func__, interfaceid);
9780 
9781 	RDLOCK_CACHE;
9782 
9783 	if (NULL == (dc_interface = (const ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &interfaceid)))
9784 		goto unlock;
9785 
9786 	if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_interface->hostid)))
9787 		goto unlock;
9788 
9789 	if (HOST_STATUS_MONITORED != dc_host->status)
9790 		goto unlock;
9791 
9792 	if (NULL == (dc_interface_snmpitem = (const ZBX_DC_INTERFACE_ITEM *)zbx_hashset_search(&config->interface_snmpitems, &interfaceid)))
9793 		goto unlock;
9794 
9795 	*items = (DC_ITEM *)zbx_malloc(*items, items_alloc * sizeof(DC_ITEM));
9796 
9797 	for (i = 0; i < dc_interface_snmpitem->itemids.values_num; i++)
9798 	{
9799 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_interface_snmpitem->itemids.values[i])))
9800 			continue;
9801 
9802 		if (ITEM_STATUS_ACTIVE != dc_item->status)
9803 			continue;
9804 
9805 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
9806 			continue;
9807 
9808 		if (items_num == items_alloc)
9809 		{
9810 			items_alloc += 8;
9811 			*items = (DC_ITEM *)zbx_realloc(*items, items_alloc * sizeof(DC_ITEM));
9812 		}
9813 
9814 		DCget_host(&(*items)[items_num].host, dc_host, ZBX_ITEM_GET_ALL);
9815 		DCget_item(&(*items)[items_num], dc_item, ZBX_ITEM_GET_ALL);
9816 		items_num++;
9817 	}
9818 unlock:
9819 	UNLOCK_CACHE;
9820 
9821 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():" ZBX_FS_SIZE_T, __func__, (zbx_fs_size_t)items_num);
9822 
9823 	return items_num;
9824 }
9825 
dc_requeue_items(const zbx_uint64_t * itemids,const int * lastclocks,const int * errcodes,size_t num)9826 static void	dc_requeue_items(const zbx_uint64_t *itemids, const int *lastclocks, const int *errcodes, size_t num)
9827 {
9828 	size_t			i;
9829 	ZBX_DC_ITEM		*dc_item;
9830 	ZBX_DC_HOST		*dc_host;
9831 	ZBX_DC_INTERFACE	*dc_interface;
9832 
9833 	for (i = 0; i < num; i++)
9834 	{
9835 		if (FAIL == errcodes[i])
9836 			continue;
9837 
9838 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])))
9839 			continue;
9840 
9841 		if (ZBX_LOC_POLLER == dc_item->location)
9842 			dc_item->location = ZBX_LOC_NOWHERE;
9843 
9844 		if (ITEM_STATUS_ACTIVE != dc_item->status)
9845 			continue;
9846 
9847 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
9848 			continue;
9849 
9850 		if (HOST_STATUS_MONITORED != dc_host->status)
9851 			continue;
9852 
9853 		if (SUCCEED != zbx_is_counted_in_item_queue(dc_item->type, dc_item->key))
9854 			continue;
9855 
9856 		dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &dc_item->interfaceid);
9857 
9858 		switch (errcodes[i])
9859 		{
9860 			case SUCCEED:
9861 			case NOTSUPPORTED:
9862 			case AGENT_ERROR:
9863 			case CONFIG_ERROR:
9864 				dc_item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
9865 				dc_requeue_item(dc_item, dc_host, dc_interface, ZBX_ITEM_COLLECTED, lastclocks[i]);
9866 				break;
9867 			case NETWORK_ERROR:
9868 			case GATEWAY_ERROR:
9869 			case TIMEOUT_ERROR:
9870 				dc_item->queue_priority = ZBX_QUEUE_PRIORITY_LOW;
9871 				dc_requeue_item(dc_item, dc_host, dc_interface,
9872 						ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE, time(NULL));
9873 				break;
9874 			default:
9875 				THIS_SHOULD_NEVER_HAPPEN;
9876 		}
9877 	}
9878 }
9879 
DCrequeue_items(const zbx_uint64_t * itemids,const int * lastclocks,const int * errcodes,size_t num)9880 void	DCrequeue_items(const zbx_uint64_t *itemids, const int *lastclocks,
9881 		const int *errcodes, size_t num)
9882 {
9883 	WRLOCK_CACHE;
9884 
9885 	dc_requeue_items(itemids, lastclocks, errcodes, num);
9886 
9887 	UNLOCK_CACHE;
9888 }
9889 
DCpoller_requeue_items(const zbx_uint64_t * itemids,const int * lastclocks,const int * errcodes,size_t num,unsigned char poller_type,int * nextcheck)9890 void	DCpoller_requeue_items(const zbx_uint64_t *itemids, const int *lastclocks,
9891 		const int *errcodes, size_t num, unsigned char poller_type, int *nextcheck)
9892 {
9893 	WRLOCK_CACHE;
9894 
9895 	dc_requeue_items(itemids, lastclocks, errcodes, num);
9896 	*nextcheck = dc_config_get_queue_nextcheck(&config->queues[poller_type]);
9897 
9898 	UNLOCK_CACHE;
9899 }
9900 
9901 /******************************************************************************
9902  *                                                                            *
9903  * Function: zbx_dc_requeue_unreachable_items                                 *
9904  *                                                                            *
9905  * Purpose: requeue unreachable items                                         *
9906  *                                                                            *
9907  * Parameters: itemids     - [IN] the item id array                           *
9908  *             itemids_num - [IN] the number of values in itemids array       *
9909  *                                                                            *
9910  * Comments: This function is used when items must be put back in the queue   *
9911  *           without polling them. For example if a poller has taken a batch  *
9912  *           of items from queue, host becomes unreachable during while       *
9913  *           polling the items, so the unpolled items of the same host must   *
9914  *           be returned to queue without updating their status.              *
9915  *                                                                            *
9916  ******************************************************************************/
zbx_dc_requeue_unreachable_items(zbx_uint64_t * itemids,size_t itemids_num)9917 void	zbx_dc_requeue_unreachable_items(zbx_uint64_t *itemids, size_t itemids_num)
9918 {
9919 	size_t			i;
9920 	ZBX_DC_ITEM		*dc_item;
9921 	ZBX_DC_HOST		*dc_host;
9922 	ZBX_DC_INTERFACE	*dc_interface;
9923 
9924 	WRLOCK_CACHE;
9925 
9926 	for (i = 0; i < itemids_num; i++)
9927 	{
9928 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])))
9929 			continue;
9930 
9931 		if (ZBX_LOC_POLLER == dc_item->location)
9932 			dc_item->location = ZBX_LOC_NOWHERE;
9933 
9934 		if (ITEM_STATUS_ACTIVE != dc_item->status)
9935 			continue;
9936 
9937 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
9938 			continue;
9939 
9940 		if (HOST_STATUS_MONITORED != dc_host->status)
9941 			continue;
9942 
9943 		dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &dc_item->interfaceid);
9944 
9945 		dc_requeue_item(dc_item, dc_host, dc_interface, ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE,
9946 				time(NULL));
9947 	}
9948 
9949 	UNLOCK_CACHE;
9950 }
9951 
9952 /******************************************************************************
9953  *                                                                            *
9954  * Function: DCinterface_get_agent_availability                               *
9955  *                                                                            *
9956  * Purpose: get interface availability data for the specified agent           *
9957  *                                                                            *
9958  * Parameters: dc_interface - [IN] the interface                              *
9959  *             availability - [OUT] the interface availability data           *
9960  *                                                                            *
9961  * Comments: The configuration cache must be locked already.                  *
9962  *                                                                            *
9963  ******************************************************************************/
DCinterface_get_agent_availability(const ZBX_DC_INTERFACE * dc_interface,zbx_agent_availability_t * agent)9964 static void	DCinterface_get_agent_availability(const ZBX_DC_INTERFACE *dc_interface,
9965 		zbx_agent_availability_t *agent)
9966 {
9967 
9968 	agent->flags = ZBX_FLAGS_AGENT_STATUS;
9969 
9970 	agent->available = dc_interface->available;
9971 	agent->error = zbx_strdup(agent->error, dc_interface->error);
9972 	agent->errors_from = dc_interface->errors_from;
9973 	agent->disable_until = dc_interface->disable_until;
9974 }
9975 
DCagent_set_availability(zbx_agent_availability_t * av,unsigned char * available,const char ** error,int * errors_from,int * disable_until)9976 static void	DCagent_set_availability(zbx_agent_availability_t *av,  unsigned char *available, const char **error,
9977 		int *errors_from, int *disable_until)
9978 {
9979 #define AGENT_AVAILABILITY_ASSIGN(flags, mask, dst, src)	\
9980 	if (0 != (flags & mask))				\
9981 	{							\
9982 		if (dst != src)					\
9983 			dst = src;				\
9984 		else						\
9985 			flags &= (~(mask));			\
9986 	}
9987 
9988 #define AGENT_AVAILABILITY_ASSIGN_STR(flags, mask, dst, src)	\
9989 	if (0 != (flags & mask))				\
9990 	{							\
9991 		if (0 != strcmp(dst, src))			\
9992 			DCstrpool_replace(1, &dst, src);	\
9993 		else						\
9994 			flags &= (~(mask));			\
9995 	}
9996 
9997 	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_AVAILABLE, *available, av->available);
9998 	AGENT_AVAILABILITY_ASSIGN_STR(av->flags, ZBX_FLAGS_AGENT_STATUS_ERROR, *error, av->error);
9999 	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM, *errors_from, av->errors_from);
10000 	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL, *disable_until, av->disable_until);
10001 
10002 #undef AGENT_AVAILABILITY_ASSIGN_STR
10003 #undef AGENT_AVAILABILITY_ASSIGN
10004 }
10005 
10006 /******************************************************************************
10007  *                                                                            *
10008  * Function: DCinterface_set_agent_availability                               *
10009  *                                                                            *
10010  * Purpose: set interface availability data in configuration cache            *
10011  *                                                                            *
10012  * Parameters: dc_interface - [OUT] the interface                             *
10013  *             now          - [IN] current timestamp                          *
10014  *             agent        - [IN/OUT] the agent availability data            *
10015  *                                                                            *
10016  * Return value: SUCCEED - at least one availability field was updated        *
10017  *               FAIL    - no availability fields were updated                *
10018  *                                                                            *
10019  * Comments: The configuration cache must be locked already.                  *
10020  *                                                                            *
10021  *           This function clears availability flags of non updated fields    *
10022  *           updated leaving only flags identifying changed fields.           *
10023  *                                                                            *
10024  ******************************************************************************/
DCinterface_set_agent_availability(ZBX_DC_INTERFACE * dc_interface,int now,zbx_agent_availability_t * agent)10025 static int	DCinterface_set_agent_availability(ZBX_DC_INTERFACE *dc_interface, int now,
10026 		zbx_agent_availability_t *agent)
10027 {
10028 	DCagent_set_availability(agent, &dc_interface->available, &dc_interface->error,
10029 			&dc_interface->errors_from, &dc_interface->disable_until);
10030 
10031 	if (ZBX_FLAGS_AGENT_STATUS_NONE == agent->flags)
10032 		return FAIL;
10033 
10034 	if (0 != (agent->flags & (ZBX_FLAGS_AGENT_STATUS_AVAILABLE | ZBX_FLAGS_AGENT_STATUS_ERROR)))
10035 		dc_interface->availability_ts = now;
10036 
10037 	return SUCCEED;
10038 }
10039 
10040 /******************************************************************************
10041  *                                                                            *
10042  * Function: DCinterface_set_availability                                     *
10043  *                                                                            *
10044  * Purpose: set interface availability data in configuration cache            *
10045  *                                                                            *
10046  * Parameters: dc_interface - [OUT] the interface                             *
10047  *             ia           - [IN/OUT] the interface availability data        *
10048  *                                                                            *
10049  * Return value: SUCCEED - at least one availability field was updated        *
10050  *               FAIL    - no availability fields were updated                *
10051  *                                                                            *
10052  * Comments: The configuration cache must be locked already.                  *
10053  *                                                                            *
10054  *           This function clears availability flags of non updated fields    *
10055  *           updated leaving only flags identifying changed fields.           *
10056  *                                                                            *
10057  ******************************************************************************/
DCinterface_set_availability(ZBX_DC_INTERFACE * dc_interface,int now,zbx_interface_availability_t * ia)10058 static int	DCinterface_set_availability(ZBX_DC_INTERFACE *dc_interface, int now, zbx_interface_availability_t *ia)
10059 {
10060 	unsigned char	flags = ZBX_FLAGS_AGENT_STATUS_NONE;
10061 
10062 	DCagent_set_availability(&ia->agent, &dc_interface->available, &dc_interface->error,
10063 			&dc_interface->errors_from, &dc_interface->disable_until);
10064 
10065 	flags |= ia->agent.flags;
10066 
10067 	if (ZBX_FLAGS_AGENT_STATUS_NONE == flags)
10068 		return FAIL;
10069 
10070 	if (0 != (flags & (ZBX_FLAGS_AGENT_STATUS_AVAILABLE | ZBX_FLAGS_AGENT_STATUS_ERROR)))
10071 		dc_interface->availability_ts = now;
10072 
10073 	return SUCCEED;
10074 }
10075 
10076 /******************************************************************************
10077  *                                                                            *
10078  * Function: zbx_interface_availability_init                                  *
10079  *                                                                            *
10080  * Purpose: initializes interface availability data                           *
10081  *                                                                            *
10082  * Parameters: availability - [IN/OUT] interface availability data            *
10083  *             interfaceid  - [IN] interface id                               *
10084  *                                                                            *
10085  ******************************************************************************/
zbx_interface_availability_init(zbx_interface_availability_t * availability,zbx_uint64_t interfaceid)10086 void	zbx_interface_availability_init(zbx_interface_availability_t *availability, zbx_uint64_t interfaceid)
10087 {
10088 	memset(availability, 0, sizeof(zbx_interface_availability_t));
10089 	availability->interfaceid = interfaceid;
10090 }
10091 
10092 /********************************************************************************
10093  *                                                                              *
10094  * Function: zbx_interface_availability_clean                                   *
10095  *                                                                              *
10096  * Purpose: releases resources allocated to store interface availability data   *
10097  *                                                                              *
10098  * Parameters: ia - [IN] interface availability data                            *
10099  *                                                                              *
10100  ********************************************************************************/
zbx_interface_availability_clean(zbx_interface_availability_t * ia)10101 void	zbx_interface_availability_clean(zbx_interface_availability_t *ia)
10102 {
10103 	zbx_free(ia->agent.error);
10104 }
10105 
10106 /******************************************************************************
10107  *                                                                            *
10108  * Function: zbx_interface_availability_free                                  *
10109  *                                                                            *
10110  * Purpose: frees interface availability data                                 *
10111  *                                                                            *
10112  * Parameters: availability - [IN] interface availability data                *
10113  *                                                                            *
10114  ******************************************************************************/
zbx_interface_availability_free(zbx_interface_availability_t * availability)10115 void	zbx_interface_availability_free(zbx_interface_availability_t *availability)
10116 {
10117 	zbx_interface_availability_clean(availability);
10118 	zbx_free(availability);
10119 }
10120 
10121 ZBX_PTR_VECTOR_IMPL(availability_ptr, zbx_interface_availability_t *);
10122 /******************************************************************************
10123  *                                                                            *
10124  * Function: zbx_agent_availability_init                                      *
10125  *                                                                            *
10126  * Purpose: initializes agent availability with the specified data            *
10127  *                                                                            *
10128  * Parameters: agent         - [IN/OUT] agent availability data               *
10129  *             available     - [IN] the availability data                     *
10130  *             error         - [IN] the availability error                    *
10131  *             errors_from   - [IN] error starting timestamp                  *
10132  *             disable_until - [IN] disable until timestamp                   *
10133  *                                                                            *
10134  ******************************************************************************/
zbx_agent_availability_init(zbx_agent_availability_t * agent,unsigned char available,const char * error,int errors_from,int disable_until)10135 static void	zbx_agent_availability_init(zbx_agent_availability_t *agent, unsigned char available, const char *error,
10136 		int errors_from, int disable_until)
10137 {
10138 	agent->flags = ZBX_FLAGS_AGENT_STATUS;
10139 	agent->available = available;
10140 	agent->error = zbx_strdup(NULL, error);
10141 	agent->errors_from = errors_from;
10142 	agent->disable_until = disable_until;
10143 }
10144 
10145 /******************************************************************************
10146  *                                                                            *
10147  * Function: zbx_interface_availability_is_set                                *
10148  *                                                                            *
10149  * Purpose: checks interface availability if agent availability field is set  *
10150  *                                                                            *
10151  * Parameters: ia - [IN] interface availability data                          *
10152  *                                                                            *
10153  * Return value: SUCCEED - an agent availability field is set                 *
10154  *               FAIL - no agent availability field is set                    *
10155  *                                                                            *
10156  ******************************************************************************/
zbx_interface_availability_is_set(const zbx_interface_availability_t * ia)10157 int	zbx_interface_availability_is_set(const zbx_interface_availability_t *ia)
10158 {
10159 	if (ZBX_FLAGS_AGENT_STATUS_NONE != ia->agent.flags)
10160 		return SUCCEED;
10161 
10162 	return FAIL;
10163 }
10164 
10165 /**************************************************************************************
10166  *                                                                                    *
10167  * Host availability update example                                                   *
10168  *                                                                                    *
10169  *                                                                                    *
10170  *               |            UnreachablePeriod                                       *
10171  *               |               (conf file)                                          *
10172  *               |              ______________                                        *
10173  *               |             /              \                                       *
10174  *               |             p     p     p     p       p       p                    *
10175  *               |             o     o     o     o       o       o                    *
10176  *               |             l     l     l     l       l       l                    *
10177  *               |             l     l     l     l       l       l                    *
10178  *               | n                                                                  *
10179  *               | e           e     e     e     e       e       e                    *
10180  *     agent     | w   p   p   r     r     r     r       r       r       p   p   p    *
10181  *       polls   |     o   o   r     r     r     r       r       r       o   o   o    *
10182  *               | h   l   l   o     o     o     o       o       o       l   l   l    *
10183  *               | o   l   l   r     r     r     r       r       r       l   l   l    *
10184  *               | s                                                                  *
10185  *               | t   ok  ok  E1    E1    E2    E1      E1      E2      ok  ok  ok   *
10186  *  --------------------------------------------------------------------------------  *
10187  *  available    | 0   1   1   1     1     1     2       2       2       0   0   0    *
10188  *               |                                                                    *
10189  *  error        | ""  ""  ""  ""    ""    ""    E1      E1      E2      ""  ""  ""   *
10190  *               |                                                                    *
10191  *  errors_from  | 0   0   0   T4    T4    T4    T4      T4      T4      0   0   0    *
10192  *               |                                                                    *
10193  *  disable_until| 0   0   0   T5    T6    T7    T8      T9      T10     0   0   0    *
10194  *  --------------------------------------------------------------------------------  *
10195  *   timestamps  | T1  T2  T3  T4    T5    T6    T7      T8      T9     T10 T11 T12   *
10196  *               |  \_/ \_/ \_/ \___/ \___/ \___/ \_____/ \_____/ \_____/ \_/ \_/     *
10197  *               |   |   |   |    |     |     |      |       |       |     |   |      *
10198  *  polling      |  item delay   UnreachableDelay    UnavailableDelay     item |      *
10199  *      periods  |                 (conf file)         (conf file)         delay      *
10200  *                                                                                    *
10201  *                                                                                    *
10202  **************************************************************************************/
10203 
10204 /*******************************************************************************
10205  *                                                                             *
10206  * Function: DCinterface_activate                                              *
10207  *                                                                             *
10208  * Purpose: set interface as available based on the agent availability data    *
10209  *                                                                             *
10210  * Parameters: interfaceid - [IN] the interface identifier                     *
10211  *             ts          - [IN] the last timestamp                           *
10212  *             in          - [IN/OUT] IN: the caller's agent availability data *
10213  *                                   OUT: the agent availability data in cache *
10214  *                                        before changes                       *
10215  *             out         - [OUT] the agent availability data after changes   *
10216  *                                                                             *
10217  * Return value: SUCCEED - the interface was activated successfully            *
10218  *               FAIL    - the interface was already activated or activation   *
10219  *                         failed                                              *
10220  *                                                                             *
10221  * Comments: The interface availability fields are updated according to the    *
10222  *           above schema.                                                     *
10223  *                                                                             *
10224  *******************************************************************************/
DCinterface_activate(zbx_uint64_t interfaceid,const zbx_timespec_t * ts,zbx_agent_availability_t * in,zbx_agent_availability_t * out)10225 int	DCinterface_activate(zbx_uint64_t interfaceid, const zbx_timespec_t *ts,
10226 		zbx_agent_availability_t *in, zbx_agent_availability_t *out)
10227 {
10228 	int			ret = FAIL;
10229 	ZBX_DC_HOST		*dc_host;
10230 	ZBX_DC_INTERFACE	*dc_interface;
10231 
10232 	/* don't try activating interface if there were no errors detected */
10233 	if (0 == in->errors_from && INTERFACE_AVAILABLE_TRUE == in->available)
10234 		goto out;
10235 
10236 	WRLOCK_CACHE;
10237 
10238 	if (NULL == (dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &interfaceid)))
10239 		goto unlock;
10240 
10241 	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_interface->hostid)))
10242 		goto unlock;
10243 
10244 	/* Don't try activating interface if:                */
10245 	/* - (server, proxy) host is not monitored any more; */
10246 	/* - (server) host is monitored by proxy.            */
10247 	if ((0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != dc_host->proxy_hostid) ||
10248 			HOST_STATUS_MONITORED != dc_host->status)
10249 	{
10250 		goto unlock;
10251 	}
10252 
10253 	DCinterface_get_agent_availability(dc_interface, in);
10254 	zbx_agent_availability_init(out, INTERFACE_AVAILABLE_TRUE, "", 0, 0);
10255 
10256 	if (SUCCEED == DCinterface_set_agent_availability(dc_interface, ts->sec, out) &&
10257 			ZBX_FLAGS_AGENT_STATUS_NONE != out->flags)
10258 	{
10259 		ret = SUCCEED;
10260 	}
10261 unlock:
10262 	UNLOCK_CACHE;
10263 out:
10264 	return ret;
10265 }
10266 
10267 /************************************************************************************
10268  *                                                                                  *
10269  * Function: DCinterface_deactivate                                                 *
10270  *                                                                                  *
10271  * Purpose: attempt to set interface as unavailable based on agent availability     *
10272  *                                                                                  *
10273  * Parameters: interfaceid - [IN] the interface identifier                          *
10274  *             ts          - [IN] the last timestamp                                *
10275  *             in          - [IN/OUT] IN: the caller's interface availability data  *
10276  *                                   OUT: the interface availability data in cache  *
10277  *                                        before changes                            *
10278  *             out         - [OUT] the interface availability data after changes    *
10279  *             error_msg   - [IN] the error message                                 *
10280  *                                                                                  *
10281  * Return value: SUCCEED - the interface was deactivated successfully               *
10282  *               FAIL    - the interface was already deactivated or deactivation    *
10283  *                         failed                                                   *
10284  *                                                                                  *
10285  * Comments: The interface availability fields are updated according to the above   *
10286  *           schema.                                                                *
10287  *                                                                                  *
10288  ***********************************************************************************/
DCinterface_deactivate(zbx_uint64_t interfaceid,const zbx_timespec_t * ts,zbx_agent_availability_t * in,zbx_agent_availability_t * out,const char * error_msg)10289 int	DCinterface_deactivate(zbx_uint64_t interfaceid, const zbx_timespec_t *ts, zbx_agent_availability_t *in,
10290 		zbx_agent_availability_t *out, const char *error_msg)
10291 {
10292 	int			ret = FAIL, errors_from, disable_until;
10293 	const char		*error;
10294 	unsigned char		available;
10295 	ZBX_DC_HOST		*dc_host;
10296 	ZBX_DC_INTERFACE	*dc_interface;
10297 
10298 	/* don't try deactivating interface if the unreachable delay has not passed since the first error */
10299 	if (CONFIG_UNREACHABLE_DELAY > ts->sec - in->errors_from)
10300 		goto out;
10301 
10302 	WRLOCK_CACHE;
10303 
10304 	if (NULL == (dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &interfaceid)))
10305 		goto unlock;
10306 
10307 	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_interface->hostid)))
10308 		goto unlock;
10309 
10310 	/* Don't try deactivating interface if:               */
10311 	/* - (server, proxy) host is not monitored any more;  */
10312 	/* - (server) host is monitored by proxy.             */
10313 	if ((0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != dc_host->proxy_hostid) ||
10314 			HOST_STATUS_MONITORED != dc_host->status)
10315 	{
10316 		goto unlock;
10317 	}
10318 
10319 	DCinterface_get_agent_availability(dc_interface, in);
10320 
10321 	available = in->available;
10322 	error = in->error;
10323 
10324 	if (0 == in->errors_from)
10325 	{
10326 		/* first error, schedule next unreachable check */
10327 		errors_from = ts->sec;
10328 		disable_until = ts->sec + CONFIG_UNREACHABLE_DELAY;
10329 	}
10330 	else
10331 	{
10332 		errors_from = in->errors_from;
10333 		disable_until = in->disable_until;
10334 
10335 		/* Check if other pollers haven't already attempted deactivating host. */
10336 		/* In that case should wait the initial unreachable delay before       */
10337 		/* trying to make it unavailable.                                      */
10338 		if (CONFIG_UNREACHABLE_DELAY <= ts->sec - errors_from)
10339 		{
10340 			/* repeating error */
10341 			if (CONFIG_UNREACHABLE_PERIOD > ts->sec - errors_from)
10342 			{
10343 				/* leave host available, schedule next unreachable check */
10344 				disable_until = ts->sec + CONFIG_UNREACHABLE_DELAY;
10345 			}
10346 			else
10347 			{
10348 				/* make host unavailable, schedule next unavailable check */
10349 				disable_until = ts->sec + CONFIG_UNAVAILABLE_DELAY;
10350 				available = INTERFACE_AVAILABLE_FALSE;
10351 				error = error_msg;
10352 			}
10353 		}
10354 	}
10355 
10356 	zbx_agent_availability_init(out, available, error, errors_from, disable_until);
10357 
10358 	if (SUCCEED == DCinterface_set_agent_availability(dc_interface, ts->sec, out) &&
10359 			ZBX_FLAGS_AGENT_STATUS_NONE != out->flags)
10360 	{
10361 		ret = SUCCEED;
10362 	}
10363 unlock:
10364 	UNLOCK_CACHE;
10365 out:
10366 	return ret;
10367 }
10368 
10369 /******************************************************************************
10370  *                                                                            *
10371  * Function: DCset_interfaces_availability                                    *
10372  *                                                                            *
10373  * Purpose: update availability of interfaces in configuration cache and      *
10374  *          return the updated field flags                                    *
10375  *                                                                            *
10376  * Parameters: availabilities - [IN/OUT] the interfacess availability data    *
10377  *                                                                            *
10378  * Return value: SUCCEED - at least one interface availability data           *
10379  *                         was updated                                        *
10380  *               FAIL    - no interfaces were updated                         *
10381  *                                                                            *
10382  ******************************************************************************/
DCset_interfaces_availability(zbx_vector_availability_ptr_t * availabilities)10383 int	DCset_interfaces_availability(zbx_vector_availability_ptr_t *availabilities)
10384 {
10385 	int				i;
10386 	ZBX_DC_INTERFACE		*dc_interface;
10387 	zbx_interface_availability_t	*ia;
10388 	int				ret = FAIL, now;
10389 
10390 	now = time(NULL);
10391 
10392 	WRLOCK_CACHE;
10393 
10394 	for (i = 0; i < availabilities->values_num; i++)
10395 	{
10396 		ia = availabilities->values[i];
10397 
10398 		if (NULL == (dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces,
10399 				&ia->interfaceid)))
10400 		{
10401 			int	j;
10402 
10403 			/* reset availability flag so this host is ignored when saving availability diff to DB */
10404 			for (j = 0; j < ZBX_AGENT_MAX; j++)
10405 				ia->agent.flags = ZBX_FLAGS_AGENT_STATUS_NONE;
10406 
10407 			continue;
10408 		}
10409 
10410 		if (SUCCEED == DCinterface_set_availability(dc_interface, now, ia))
10411 			ret = SUCCEED;
10412 	}
10413 
10414 	UNLOCK_CACHE;
10415 
10416 	return ret;
10417 }
10418 
10419 /******************************************************************************
10420  *                                                                            *
10421  * Comments: helper function for trigger dependency checking                  *
10422  *                                                                            *
10423  * Parameters: trigdep        - [IN] the trigger dependency data              *
10424  *             level          - [IN] the trigger dependency level             *
10425  *             triggerids     - [IN] the currently processing trigger ids     *
10426  *                                   for bulk trigger operations              *
10427  *                                   (optional, can be NULL)                  *
10428  *             master_triggerids - [OUT] unresolved master trigger ids        *
10429  *                                   for bulk trigger operations              *
10430  *                                   (optional together with triggerids       *
10431  *                                   parameter)                               *
10432  *                                                                            *
10433  * Return value: SUCCEED - trigger dependency check succeed / was unresolved  *
10434  *               FAIL    - otherwise                                          *
10435  *                                                                            *
10436  * Comments: With bulk trigger processing a master trigger can be in the same *
10437  *           batch as dependent trigger. In this case it might be impossible  *
10438  *           to perform dependency check based on cashed trigger values. The  *
10439  *           unresolved master trigger ids will be added to master_triggerids *
10440  *           vector, so the dependency check can be performed after a new     *
10441  *           master trigger value has been calculated.                        *
10442  *                                                                            *
10443  ******************************************************************************/
DCconfig_check_trigger_dependencies_rec(const ZBX_DC_TRIGGER_DEPLIST * trigdep,int level,const zbx_vector_uint64_t * triggerids,zbx_vector_uint64_t * master_triggerids)10444 static int	DCconfig_check_trigger_dependencies_rec(const ZBX_DC_TRIGGER_DEPLIST *trigdep, int level,
10445 		const zbx_vector_uint64_t *triggerids, zbx_vector_uint64_t *master_triggerids)
10446 {
10447 	int				i;
10448 	const ZBX_DC_TRIGGER		*next_trigger;
10449 	const ZBX_DC_TRIGGER_DEPLIST	*next_trigdep;
10450 
10451 	if (ZBX_TRIGGER_DEPENDENCY_LEVELS_MAX < level)
10452 	{
10453 		zabbix_log(LOG_LEVEL_CRIT, "recursive trigger dependency is too deep (triggerid:" ZBX_FS_UI64 ")",
10454 				trigdep->triggerid);
10455 		return SUCCEED;
10456 	}
10457 
10458 	if (0 != trigdep->dependencies.values_num)
10459 	{
10460 		for (i = 0; i < trigdep->dependencies.values_num; i++)
10461 		{
10462 			next_trigdep = (const ZBX_DC_TRIGGER_DEPLIST *)trigdep->dependencies.values[i];
10463 
10464 			if (NULL != (next_trigger = next_trigdep->trigger) &&
10465 					TRIGGER_STATUS_ENABLED == next_trigger->status &&
10466 					TRIGGER_FUNCTIONAL_TRUE == next_trigger->functional)
10467 			{
10468 
10469 				if (NULL == triggerids || FAIL == zbx_vector_uint64_bsearch(triggerids,
10470 						next_trigger->triggerid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
10471 				{
10472 					if (TRIGGER_VALUE_PROBLEM == next_trigger->value)
10473 						return FAIL;
10474 				}
10475 				else
10476 					zbx_vector_uint64_append(master_triggerids, next_trigger->triggerid);
10477 			}
10478 
10479 			if (FAIL == DCconfig_check_trigger_dependencies_rec(next_trigdep, level + 1, triggerids,
10480 					master_triggerids))
10481 			{
10482 				return FAIL;
10483 			}
10484 		}
10485 	}
10486 
10487 	return SUCCEED;
10488 }
10489 
10490 /******************************************************************************
10491  *                                                                            *
10492  * Function: DCconfig_check_trigger_dependencies                              *
10493  *                                                                            *
10494  * Purpose: check whether any of trigger dependencies have value PROBLEM      *
10495  *                                                                            *
10496  * Return value: SUCCEED - trigger can change its value                       *
10497  *               FAIL - otherwise                                             *
10498  *                                                                            *
10499  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
10500  *                                                                            *
10501  ******************************************************************************/
DCconfig_check_trigger_dependencies(zbx_uint64_t triggerid)10502 int	DCconfig_check_trigger_dependencies(zbx_uint64_t triggerid)
10503 {
10504 	int				ret = SUCCEED;
10505 	const ZBX_DC_TRIGGER_DEPLIST	*trigdep;
10506 
10507 	RDLOCK_CACHE;
10508 
10509 	if (NULL != (trigdep = (const ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps, &triggerid)))
10510 		ret = DCconfig_check_trigger_dependencies_rec(trigdep, 0, NULL, NULL);
10511 
10512 	UNLOCK_CACHE;
10513 
10514 	return ret;
10515 }
10516 
10517 /******************************************************************************
10518  *                                                                            *
10519  * Comments: helper function for DCconfig_sort_triggers_topologically()       *
10520  *                                                                            *
10521  ******************************************************************************/
DCconfig_sort_triggers_topologically_rec(const ZBX_DC_TRIGGER_DEPLIST * trigdep,int level)10522 static unsigned char	DCconfig_sort_triggers_topologically_rec(const ZBX_DC_TRIGGER_DEPLIST *trigdep, int level)
10523 {
10524 	int				i;
10525 	unsigned char			topoindex = 2, next_topoindex;
10526 	const ZBX_DC_TRIGGER_DEPLIST	*next_trigdep;
10527 
10528 	if (32 < level)
10529 	{
10530 		zabbix_log(LOG_LEVEL_CRIT, "recursive trigger dependency is too deep (triggerid:" ZBX_FS_UI64 ")",
10531 				trigdep->triggerid);
10532 		goto exit;
10533 	}
10534 
10535 	if (0 == trigdep->trigger->topoindex)
10536 	{
10537 		zabbix_log(LOG_LEVEL_CRIT, "trigger dependencies contain a cycle (triggerid:" ZBX_FS_UI64 ")",
10538 				trigdep->triggerid);
10539 		goto exit;
10540 	}
10541 
10542 	trigdep->trigger->topoindex = 0;
10543 
10544 	for (i = 0; i < trigdep->dependencies.values_num; i++)
10545 	{
10546 		next_trigdep = (const ZBX_DC_TRIGGER_DEPLIST *)trigdep->dependencies.values[i];
10547 
10548 		if (1 < (next_topoindex = next_trigdep->trigger->topoindex))
10549 			goto next;
10550 
10551 		if (0 == next_trigdep->dependencies.values_num)
10552 			continue;
10553 
10554 		next_topoindex = DCconfig_sort_triggers_topologically_rec(next_trigdep, level + 1);
10555 next:
10556 		if (topoindex < next_topoindex + 1)
10557 			topoindex = next_topoindex + 1;
10558 	}
10559 
10560 	trigdep->trigger->topoindex = topoindex;
10561 exit:
10562 	return topoindex;
10563 }
10564 
10565 /******************************************************************************
10566  *                                                                            *
10567  * Function: DCconfig_sort_triggers_topologically                             *
10568  *                                                                            *
10569  * Purpose: assign each trigger an index based on trigger dependency topology *
10570  *                                                                            *
10571  * Author: Aleksandrs Saveljevs                                               *
10572  *                                                                            *
10573  ******************************************************************************/
DCconfig_sort_triggers_topologically(void)10574 static void	DCconfig_sort_triggers_topologically(void)
10575 {
10576 	zbx_hashset_iter_t		iter;
10577 	ZBX_DC_TRIGGER			*trigger;
10578 	const ZBX_DC_TRIGGER_DEPLIST	*trigdep;
10579 
10580 	zbx_hashset_iter_reset(&config->trigdeps, &iter);
10581 
10582 	while (NULL != (trigdep = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_iter_next(&iter)))
10583 	{
10584 		trigger = trigdep->trigger;
10585 
10586 		if (NULL == trigger || 1 < trigger->topoindex || 0 == trigdep->dependencies.values_num)
10587 			continue;
10588 
10589 		DCconfig_sort_triggers_topologically_rec(trigdep, 0);
10590 	}
10591 }
10592 
10593 /******************************************************************************
10594  *                                                                            *
10595  * Function: DCconfig_triggers_apply_changes                                  *
10596  *                                                                            *
10597  * Purpose: apply trigger value,state,lastchange or error changes to          *
10598  *          configuration cache after committed to database                   *
10599  *                                                                            *
10600  ******************************************************************************/
DCconfig_triggers_apply_changes(zbx_vector_ptr_t * trigger_diff)10601 void	DCconfig_triggers_apply_changes(zbx_vector_ptr_t *trigger_diff)
10602 {
10603 	int			i;
10604 	zbx_trigger_diff_t	*diff;
10605 	ZBX_DC_TRIGGER		*dc_trigger;
10606 
10607 	if (0 == trigger_diff->values_num)
10608 		return;
10609 
10610 	WRLOCK_CACHE;
10611 
10612 	for (i = 0; i < trigger_diff->values_num; i++)
10613 	{
10614 		diff = (zbx_trigger_diff_t *)trigger_diff->values[i];
10615 
10616 		if (NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &diff->triggerid)))
10617 			continue;
10618 
10619 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_LASTCHANGE))
10620 			dc_trigger->lastchange = diff->lastchange;
10621 
10622 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE))
10623 			dc_trigger->value = diff->value;
10624 
10625 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_STATE))
10626 			dc_trigger->state = diff->state;
10627 
10628 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_ERROR))
10629 			DCstrpool_replace(1, &dc_trigger->error, diff->error);
10630 	}
10631 
10632 	UNLOCK_CACHE;
10633 }
10634 
10635 /******************************************************************************
10636  *                                                                            *
10637  * Function: DCconfig_get_stats                                               *
10638  *                                                                            *
10639  * Purpose: get statistics of the database cache                              *
10640  *                                                                            *
10641  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
10642  *                                                                            *
10643  ******************************************************************************/
DCconfig_get_stats(int request)10644 void	*DCconfig_get_stats(int request)
10645 {
10646 	static zbx_uint64_t	value_uint;
10647 	static double		value_double;
10648 
10649 	switch (request)
10650 	{
10651 		case ZBX_CONFSTATS_BUFFER_TOTAL:
10652 			value_uint = config_mem->orig_size;
10653 			return &value_uint;
10654 		case ZBX_CONFSTATS_BUFFER_USED:
10655 			value_uint = config_mem->orig_size - config_mem->free_size;
10656 			return &value_uint;
10657 		case ZBX_CONFSTATS_BUFFER_FREE:
10658 			value_uint = config_mem->free_size;
10659 			return &value_uint;
10660 		case ZBX_CONFSTATS_BUFFER_PUSED:
10661 			value_double = 100 * (double)(config_mem->orig_size - config_mem->free_size) /
10662 					config_mem->orig_size;
10663 			return &value_double;
10664 		case ZBX_CONFSTATS_BUFFER_PFREE:
10665 			value_double = 100 * (double)config_mem->free_size / config_mem->orig_size;
10666 			return &value_double;
10667 		default:
10668 			return NULL;
10669 	}
10670 }
10671 
DCget_proxy(DC_PROXY * dst_proxy,const ZBX_DC_PROXY * src_proxy)10672 static void	DCget_proxy(DC_PROXY *dst_proxy, const ZBX_DC_PROXY *src_proxy)
10673 {
10674 	const ZBX_DC_HOST	*host;
10675 	ZBX_DC_INTERFACE_HT	*interface_ht, interface_ht_local;
10676 
10677 	dst_proxy->hostid = src_proxy->hostid;
10678 	dst_proxy->proxy_config_nextcheck = src_proxy->proxy_config_nextcheck;
10679 	dst_proxy->proxy_data_nextcheck = src_proxy->proxy_data_nextcheck;
10680 	dst_proxy->proxy_tasks_nextcheck = src_proxy->proxy_tasks_nextcheck;
10681 	dst_proxy->last_cfg_error_time = src_proxy->last_cfg_error_time;
10682 	dst_proxy->version = src_proxy->version;
10683 	dst_proxy->lastaccess = src_proxy->lastaccess;
10684 	dst_proxy->auto_compress = src_proxy->auto_compress;
10685 	dst_proxy->last_version_error_time = src_proxy->last_version_error_time;
10686 
10687 	if (NULL != (host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &src_proxy->hostid)))
10688 	{
10689 		strscpy(dst_proxy->host, host->host);
10690 		strscpy(dst_proxy->proxy_address, src_proxy->proxy_address);
10691 
10692 		dst_proxy->tls_connect = host->tls_connect;
10693 		dst_proxy->tls_accept = host->tls_accept;
10694 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
10695 		strscpy(dst_proxy->tls_issuer, host->tls_issuer);
10696 		strscpy(dst_proxy->tls_subject, host->tls_subject);
10697 
10698 		if (NULL == host->tls_dc_psk)
10699 		{
10700 			*dst_proxy->tls_psk_identity = '\0';
10701 			*dst_proxy->tls_psk = '\0';
10702 		}
10703 		else
10704 		{
10705 			strscpy(dst_proxy->tls_psk_identity, host->tls_dc_psk->tls_psk_identity);
10706 			strscpy(dst_proxy->tls_psk, host->tls_dc_psk->tls_psk);
10707 		}
10708 #endif
10709 	}
10710 	else
10711 	{
10712 		/* DCget_proxy() is called only from DCconfig_get_proxypoller_hosts(), which is called only from */
10713 		/* process_proxy(). So, this branch should never happen. */
10714 		*dst_proxy->host = '\0';
10715 		*dst_proxy->proxy_address = '\0';
10716 		dst_proxy->tls_connect = ZBX_TCP_SEC_TLS_PSK;	/* set PSK to deliberately fail in this case */
10717 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
10718 		*dst_proxy->tls_psk_identity = '\0';
10719 		*dst_proxy->tls_psk = '\0';
10720 #endif
10721 		THIS_SHOULD_NEVER_HAPPEN;
10722 	}
10723 
10724 	interface_ht_local.hostid = src_proxy->hostid;
10725 	interface_ht_local.type = INTERFACE_TYPE_UNKNOWN;
10726 
10727 	if (NULL != (interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local)))
10728 	{
10729 		const ZBX_DC_INTERFACE	*interface = interface_ht->interface_ptr;
10730 
10731 		strscpy(dst_proxy->addr_orig, interface->useip ? interface->ip : interface->dns);
10732 		strscpy(dst_proxy->port_orig, interface->port);
10733 	}
10734 	else
10735 	{
10736 		*dst_proxy->addr_orig = '\0';
10737 		*dst_proxy->port_orig = '\0';
10738 	}
10739 
10740 	dst_proxy->addr = NULL;
10741 	dst_proxy->port = 0;
10742 }
10743 
DCconfig_get_last_sync_time(void)10744 int	DCconfig_get_last_sync_time(void)
10745 {
10746 	return config->sync_ts;
10747 }
10748 
DCconfig_wait_sync(void)10749 void	DCconfig_wait_sync(void)
10750 {
10751 	struct timespec	ts = {0, 1e8};
10752 
10753 	while (0 == config->sync_ts)
10754 		nanosleep(&ts, NULL);
10755 }
10756 
10757 /******************************************************************************
10758  *                                                                            *
10759  * Function: DCconfig_get_proxypoller_hosts                                   *
10760  *                                                                            *
10761  * Purpose: Get array of proxies for proxy poller                             *
10762  *                                                                            *
10763  * Parameters: hosts - [OUT] array of hosts                                   *
10764  *             max_hosts - [IN] elements in hosts array                       *
10765  *                                                                            *
10766  * Return value: number of proxies in hosts array                             *
10767  *                                                                            *
10768  * Author: Alexander Vladishev                                                *
10769  *                                                                            *
10770  * Comments: Proxies leave the queue only through this function. Pollers must *
10771  *           always return the proxies they have taken using DCrequeue_proxy. *
10772  *                                                                            *
10773  ******************************************************************************/
DCconfig_get_proxypoller_hosts(DC_PROXY * proxies,int max_hosts)10774 int	DCconfig_get_proxypoller_hosts(DC_PROXY *proxies, int max_hosts)
10775 {
10776 	int			now, num = 0;
10777 	zbx_binary_heap_t	*queue;
10778 
10779 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
10780 
10781 	now = time(NULL);
10782 
10783 	queue = &config->pqueue;
10784 
10785 	WRLOCK_CACHE;
10786 
10787 	while (num < max_hosts && FAIL == zbx_binary_heap_empty(queue))
10788 	{
10789 		const zbx_binary_heap_elem_t	*min;
10790 		ZBX_DC_PROXY			*dc_proxy;
10791 
10792 		min = zbx_binary_heap_find_min(queue);
10793 		dc_proxy = (ZBX_DC_PROXY *)min->data;
10794 
10795 		if (dc_proxy->nextcheck > now)
10796 			break;
10797 
10798 		zbx_binary_heap_remove_min(queue);
10799 		dc_proxy->location = ZBX_LOC_POLLER;
10800 
10801 		DCget_proxy(&proxies[num], dc_proxy);
10802 		num++;
10803 	}
10804 
10805 	UNLOCK_CACHE;
10806 
10807 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, num);
10808 
10809 	return num;
10810 }
10811 
10812 /******************************************************************************
10813  *                                                                            *
10814  * Function: DCconfig_get_proxypoller_nextcheck                               *
10815  *                                                                            *
10816  * Purpose: Get nextcheck for passive proxies                                 *
10817  *                                                                            *
10818  * Return value: nextcheck or FAIL if no passive proxies in queue             *
10819  *                                                                            *
10820  * Author: Alexander Vladishev                                                *
10821  *                                                                            *
10822  ******************************************************************************/
DCconfig_get_proxypoller_nextcheck(void)10823 int	DCconfig_get_proxypoller_nextcheck(void)
10824 {
10825 	int			nextcheck;
10826 	zbx_binary_heap_t	*queue;
10827 
10828 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
10829 
10830 	queue = &config->pqueue;
10831 
10832 	RDLOCK_CACHE;
10833 
10834 	if (FAIL == zbx_binary_heap_empty(queue))
10835 	{
10836 		const zbx_binary_heap_elem_t	*min;
10837 		const ZBX_DC_PROXY		*dc_proxy;
10838 
10839 		min = zbx_binary_heap_find_min(queue);
10840 		dc_proxy = (const ZBX_DC_PROXY *)min->data;
10841 
10842 		nextcheck = dc_proxy->nextcheck;
10843 	}
10844 	else
10845 		nextcheck = FAIL;
10846 
10847 	UNLOCK_CACHE;
10848 
10849 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, nextcheck);
10850 
10851 	return nextcheck;
10852 }
10853 
DCrequeue_proxy(zbx_uint64_t hostid,unsigned char update_nextcheck,int proxy_conn_err)10854 void	DCrequeue_proxy(zbx_uint64_t hostid, unsigned char update_nextcheck, int proxy_conn_err)
10855 {
10856 	time_t		now;
10857 	ZBX_DC_HOST	*dc_host;
10858 	ZBX_DC_PROXY	*dc_proxy;
10859 
10860 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() update_nextcheck:%d", __func__, (int)update_nextcheck);
10861 
10862 	now = time(NULL);
10863 
10864 	WRLOCK_CACHE;
10865 
10866 	if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)) &&
10867 			NULL != (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
10868 	{
10869 		if (ZBX_LOC_POLLER == dc_proxy->location)
10870 			dc_proxy->location = ZBX_LOC_NOWHERE;
10871 
10872 		/* set or clear passive proxy misconfiguration error timestamp */
10873 		if (SUCCEED == proxy_conn_err)
10874 			dc_proxy->last_cfg_error_time = 0;
10875 		else if (CONFIG_ERROR == proxy_conn_err)
10876 			dc_proxy->last_cfg_error_time = (int)now;
10877 
10878 		if (HOST_STATUS_PROXY_PASSIVE == dc_host->status)
10879 		{
10880 			if (0 != (update_nextcheck & ZBX_PROXY_CONFIG_NEXTCHECK))
10881 			{
10882 				dc_proxy->proxy_config_nextcheck = (int)calculate_proxy_nextcheck(
10883 						hostid, CONFIG_PROXYCONFIG_FREQUENCY, now);
10884 			}
10885 
10886 			if (0 != (update_nextcheck & ZBX_PROXY_DATA_NEXTCHECK))
10887 			{
10888 				dc_proxy->proxy_data_nextcheck = (int)calculate_proxy_nextcheck(
10889 						hostid, CONFIG_PROXYDATA_FREQUENCY, now);
10890 			}
10891 			if (0 != (update_nextcheck & ZBX_PROXY_TASKS_NEXTCHECK))
10892 			{
10893 				dc_proxy->proxy_tasks_nextcheck = (int)calculate_proxy_nextcheck(
10894 						hostid, ZBX_TASK_UPDATE_FREQUENCY, now);
10895 			}
10896 
10897 			DCupdate_proxy_queue(dc_proxy);
10898 		}
10899 	}
10900 
10901 	UNLOCK_CACHE;
10902 
10903 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
10904 }
10905 
dc_get_host_macro_value(const ZBX_DC_HMACRO * macro,char ** value)10906 static void	dc_get_host_macro_value(const ZBX_DC_HMACRO *macro, char **value)
10907 {
10908 	if (ZBX_MACRO_ENV_NONSECURE == macro_env && (ZBX_MACRO_VALUE_SECRET == macro->type ||
10909 			ZBX_MACRO_VALUE_VAULT == macro->type))
10910 	{
10911 		*value = zbx_strdup(*value, ZBX_MACRO_SECRET_MASK);
10912 	}
10913 	else if (ZBX_MACRO_VALUE_VAULT == macro->type)
10914 	{
10915 		if (NULL == macro->kv->value)
10916 			*value = zbx_strdup(*value, ZBX_MACRO_SECRET_MASK);
10917 		else
10918 			*value = zbx_strdup(*value, macro->kv->value);
10919 	}
10920 	else
10921 		*value = zbx_strdup(*value, macro->value);
10922 }
10923 
dc_match_macro_context(const char * context,const char * pattern,unsigned char op)10924 static int	dc_match_macro_context(const char *context, const char *pattern, unsigned char op)
10925 {
10926 	switch (op)
10927 	{
10928 		case CONDITION_OPERATOR_EQUAL:
10929 			return 0 == zbx_strcmp_null(context, pattern) ? SUCCEED : FAIL;
10930 		case CONDITION_OPERATOR_REGEXP:
10931 			if (NULL == context)
10932 				return FAIL;
10933 			return NULL != zbx_regexp_match(context, pattern, NULL) ? SUCCEED : FAIL;
10934 		default:
10935 			THIS_SHOULD_NEVER_HAPPEN;
10936 			return FAIL;
10937 	}
10938 }
10939 
dc_get_host_macro(const zbx_uint64_t * hostids,int host_num,const char * macro,const char * context,char ** value,char ** value_default)10940 static void	dc_get_host_macro(const zbx_uint64_t *hostids, int host_num, const char *macro, const char *context,
10941 		char **value, char **value_default)
10942 {
10943 	int			i, j;
10944 	const ZBX_DC_HMACRO_HM	*hmacro_hm;
10945 	ZBX_DC_HMACRO_HM	hmacro_hm_local;
10946 	const ZBX_DC_HTMPL	*htmpl;
10947 	zbx_vector_uint64_t	templateids;
10948 	const ZBX_DC_HMACRO	*hmacro;
10949 
10950 	if (0 == host_num)
10951 		return;
10952 
10953 	hmacro_hm_local.macro = macro;
10954 
10955 	for (i = 0; i < host_num; i++)
10956 	{
10957 		hmacro_hm_local.hostid = hostids[i];
10958 
10959 		if (NULL != (hmacro_hm = (const ZBX_DC_HMACRO_HM *)zbx_hashset_search(&config->hmacros_hm, &hmacro_hm_local)))
10960 		{
10961 			for (j = 0; j < hmacro_hm->hmacros.values_num; j++)
10962 			{
10963 				hmacro = (const ZBX_DC_HMACRO *)hmacro_hm->hmacros.values[j];
10964 
10965 				if (SUCCEED == dc_match_macro_context(context, hmacro->context, hmacro->context_op))
10966 				{
10967 					dc_get_host_macro_value(hmacro, value);
10968 					return;
10969 				}
10970 			}
10971 			/* Check for the default (without context) macro value. If macro has a value without */
10972 			/* context it will be the first element in the macro index vector.                   */
10973 			hmacro = (const ZBX_DC_HMACRO *)hmacro_hm->hmacros.values[0];
10974 			if (NULL == *value_default && NULL != context && NULL == hmacro->context)
10975 				dc_get_host_macro_value(hmacro, value_default);
10976 		}
10977 	}
10978 
10979 	zbx_vector_uint64_create(&templateids);
10980 	zbx_vector_uint64_reserve(&templateids, 32);
10981 
10982 	for (i = 0; i < host_num; i++)
10983 	{
10984 		if (NULL != (htmpl = (const ZBX_DC_HTMPL *)zbx_hashset_search(&config->htmpls, &hostids[i])))
10985 		{
10986 			for (j = 0; j < htmpl->templateids.values_num; j++)
10987 				zbx_vector_uint64_append(&templateids, htmpl->templateids.values[j]);
10988 		}
10989 	}
10990 
10991 	if (0 != templateids.values_num)
10992 	{
10993 		zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
10994 		dc_get_host_macro(templateids.values, templateids.values_num, macro, context, value, value_default);
10995 	}
10996 
10997 	zbx_vector_uint64_destroy(&templateids);
10998 }
10999 
dc_get_global_macro_value(const ZBX_DC_GMACRO * macro,char ** value)11000 static void	dc_get_global_macro_value(const ZBX_DC_GMACRO *macro, char **value)
11001 {
11002 	if (ZBX_MACRO_ENV_NONSECURE == macro_env && (ZBX_MACRO_VALUE_SECRET == macro->type ||
11003 			ZBX_MACRO_VALUE_VAULT == macro->type))
11004 	{
11005 		*value = zbx_strdup(*value, ZBX_MACRO_SECRET_MASK);
11006 	}
11007 	else if (ZBX_MACRO_VALUE_VAULT == macro->type)
11008 	{
11009 		if (NULL == macro->kv->value)
11010 			*value = zbx_strdup(*value, ZBX_MACRO_SECRET_MASK);
11011 		else
11012 			*value = zbx_strdup(*value, macro->kv->value);
11013 	}
11014 	else
11015 		*value = zbx_strdup(*value, macro->value);
11016 }
11017 
dc_get_global_macro(const char * macro,const char * context,char ** value,char ** value_default)11018 static void	dc_get_global_macro(const char *macro, const char *context, char **value, char **value_default)
11019 {
11020 	int			i;
11021 	const ZBX_DC_GMACRO_M	*gmacro_m;
11022 	ZBX_DC_GMACRO_M		gmacro_m_local;
11023 	const ZBX_DC_GMACRO	*gmacro;
11024 
11025 	gmacro_m_local.macro = macro;
11026 
11027 	if (NULL != (gmacro_m = (const ZBX_DC_GMACRO_M *)zbx_hashset_search(&config->gmacros_m, &gmacro_m_local)))
11028 	{
11029 		for (i = 0; i < gmacro_m->gmacros.values_num; i++)
11030 		{
11031 			gmacro = (const ZBX_DC_GMACRO *)gmacro_m->gmacros.values[i];
11032 
11033 			if (SUCCEED == dc_match_macro_context(context, gmacro->context, gmacro->context_op))
11034 			{
11035 				dc_get_global_macro_value(gmacro, value);
11036 				break;
11037 			}
11038 		}
11039 
11040 		/* Check for the default (without context) macro value. If macro has a value without */
11041 		/* context it will be the first element in the macro index vector.                   */
11042 		gmacro = (const ZBX_DC_GMACRO *)gmacro_m->gmacros.values[0];
11043 		if (NULL == *value_default && NULL != context && NULL == gmacro->context)
11044 			dc_get_global_macro_value(gmacro, value_default);
11045 	}
11046 }
11047 
dc_get_user_macro(const zbx_uint64_t * hostids,int hostids_num,const char * macro,const char * context,char ** replace_to)11048 static void	dc_get_user_macro(const zbx_uint64_t *hostids, int hostids_num, const char *macro, const char *context,
11049 		char **replace_to)
11050 {
11051 	char	*value = NULL, *value_default = NULL;
11052 
11053 	/* User macros should be expanded according to the following priority: */
11054 	/*                                                                     */
11055 	/*  1) host context macro                                              */
11056 	/*  2) global context macro                                            */
11057 	/*  3) host base (default) macro                                       */
11058 	/*  4) global base (default) macro                                     */
11059 	/*                                                                     */
11060 	/* We try to expand host macros first. If there is no perfect match on */
11061 	/* the host level, we try to expand global macros, passing the default */
11062 	/* macro value found on the host level, if any.                        */
11063 
11064 	dc_get_host_macro(hostids, hostids_num, macro, context, &value, &value_default);
11065 
11066 	if (NULL == value)
11067 		dc_get_global_macro(macro, context, &value, &value_default);
11068 
11069 	if (NULL != value)
11070 	{
11071 		zbx_free(*replace_to);
11072 		*replace_to = value;
11073 
11074 		zbx_free(value_default);
11075 	}
11076 	else if (NULL != value_default)
11077 	{
11078 		zbx_free(*replace_to);
11079 		*replace_to = value_default;
11080 	}
11081 }
11082 
DCget_user_macro(const zbx_uint64_t * hostids,int hostids_num,const char * macro,char ** replace_to)11083 void	DCget_user_macro(const zbx_uint64_t *hostids, int hostids_num, const char *macro, char **replace_to)
11084 {
11085 	char	*name = NULL, *context = NULL;
11086 
11087 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() macro:'%s'", __func__, macro);
11088 
11089 	if (SUCCEED != zbx_user_macro_parse_dyn(macro, &name, &context, NULL, NULL))
11090 		goto out;
11091 
11092 	RDLOCK_CACHE;
11093 
11094 	dc_get_user_macro(hostids, hostids_num, name, context, replace_to);
11095 
11096 	UNLOCK_CACHE;
11097 
11098 	zbx_free(context);
11099 	zbx_free(name);
11100 out:
11101 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
11102 }
11103 
11104 /******************************************************************************
11105  *                                                                            *
11106  * Function: dc_expand_user_macros                                            *
11107  *                                                                            *
11108  * Purpose: expand user macros in the specified text value                    *
11109  *                                                                            *
11110  * Parameters: text         - [IN] the text value to expand                   *
11111  *             len          - [IN] the text length                            *
11112  *             hostids      - [IN] an array of related hostids                *
11113  *             hostids_num  - [IN] the number of hostids                      *
11114  *             value        - [IN] the expanded macro with expanded user      *
11115  *                                 macros. Unknown or invalid macros will be  *
11116  *                                 left unresolved.                           *
11117  *             error        - [IN] the error message, optional. If specified  *
11118  *                                 the function will return failure on first  *
11119  *                                 unknown user macro                         *
11120  *                                                                            *
11121  * Return value: SUCCEED - the macros were expanded successfully              *
11122  *               FAIL    - error parameter was given and at least one of      *
11123  *                         macros was not expanded                            *
11124  *                                                                            *
11125  * Comments: The returned value must be freed by the caller.                  *
11126  *                                                                            *
11127  ******************************************************************************/
dc_expand_user_macros_len(const char * text,size_t text_len,zbx_uint64_t * hostids,int hostids_num,char ** value,char ** error)11128 int	dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num,
11129 		char **value, char **error)
11130 {
11131 	zbx_token_t	token;
11132 	int		len;
11133 	char		*str = NULL, *name = NULL, *context = NULL, *macro_value = NULL;
11134 	size_t		str_alloc = 0, str_offset = 0, pos = 0, last_pos = 0;
11135 
11136 	if ('\0' == *text)
11137 	{
11138 		*value = zbx_strdup(NULL, text);
11139 		return SUCCEED;
11140 	}
11141 
11142 	for (; SUCCEED == zbx_token_find(text, pos, &token, ZBX_TOKEN_SEARCH_BASIC) && token.loc.r < text_len; pos++)
11143 	{
11144 		if (ZBX_TOKEN_USER_MACRO != token.type)
11145 			continue;
11146 
11147 		if (SUCCEED != zbx_user_macro_parse_dyn(text + token.loc.l, &name, &context, &len, NULL))
11148 			continue;
11149 
11150 		if (last_pos < token.loc.l)
11151 			zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, token.loc.l - last_pos);
11152 
11153 		dc_get_user_macro(hostids, hostids_num, name, context, &macro_value);
11154 
11155 		zbx_free(name);
11156 		zbx_free(context);
11157 
11158 		if (NULL != macro_value)
11159 		{
11160 			zbx_strcpy_alloc(&str, &str_alloc, &str_offset, macro_value);
11161 			zbx_free(macro_value);
11162 		}
11163 		else
11164 		{
11165 			if (NULL != error)
11166 			{
11167 				*error = zbx_dsprintf(NULL, "unknown user macro \"%.*s\"",
11168 						(int)(token.loc.r - token.loc.l + 1), text + token.loc.l);
11169 				zbx_free(str);
11170 				return FAIL;
11171 			}
11172 			zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + token.loc.l,
11173 					token.loc.r - token.loc.l + 1);
11174 		}
11175 
11176 		pos = token.loc.r;
11177 		last_pos = pos + 1;
11178 	}
11179 
11180 	if (last_pos < text_len)
11181 		zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, text_len - last_pos);
11182 
11183 	*value = str;
11184 
11185 	return SUCCEED;
11186 }
11187 
11188 /******************************************************************************
11189  *                                                                            *
11190  * Function: zbx_dc_expand_user_macros_len                                    *
11191  *                                                                            *
11192  * Purpose: expand user macros in the specified text                          *
11193  *                                                                            *
11194  * Parameters: text         - [IN] the text value to expand                   *
11195  *             len          - [IN] the text length                            *
11196  *             hostids      - [IN] an array of related hostids                *
11197  *             hostids_num  - [IN] the number of hostids                      *
11198  *             value        - [IN] the expanded macro with expanded user      *
11199  *                                 macros. Unknown or invalid macros will be  *
11200  *                                 left unresolved.                           *
11201  *             error        - [IN] the error message, optional. If specified  *
11202  *                                 the function will return failure on first  *
11203  *                                 unknown user macro                         *
11204  *                                                                            *
11205  * Return value: SUCCEED - the macros were expanded successfully              *
11206  *               FAIL    - error parameter was given and at least one of      *
11207  *                         macros was not expanded                            *
11208  *                                                                            *
11209  * Comments: The returned value must be freed by the caller.                  *
11210  *                                                                            *
11211  ******************************************************************************/
zbx_dc_expand_user_macros_len(const char * text,size_t text_len,zbx_uint64_t * hostids,int hostids_num,char ** value,char ** error)11212 int	zbx_dc_expand_user_macros_len(const char *text, size_t text_len, zbx_uint64_t *hostids, int hostids_num,
11213 		char **value, char **error)
11214 {
11215 	int	ret;
11216 
11217 	RDLOCK_CACHE;
11218 	ret = dc_expand_user_macros_len(text, text_len, hostids, hostids_num, value, error);
11219 	UNLOCK_CACHE;
11220 
11221 	return ret;
11222 }
11223 
11224 /******************************************************************************
11225  *                                                                            *
11226  * Function: dc_expand_user_macros                                            *
11227  *                                                                            *
11228  * Purpose: expand user macros in the specified text value                    *
11229  * WARNING - DO NOT USE FOR TRIGGERS, for triggers use the dedicated function *
11230  *                                                                            *
11231  * Parameters: text           - [IN] the text value to expand                 *
11232  *             hostids        - [IN] an array of related hostids              *
11233  *             hostids_num    - [IN] the number of hostids                    *
11234  *                                                                            *
11235  * Return value: The text value with expanded user macros. Unknown or invalid *
11236  *               macros will be left unresolved.                              *
11237  *                                                                            *
11238  * Comments: The returned value must be freed by the caller.                  *
11239  *           This function must be used only by configuration syncer          *
11240  *                                                                            *
11241  ******************************************************************************/
dc_expand_user_macros(const char * text,zbx_uint64_t * hostids,int hostids_num)11242 char	*dc_expand_user_macros(const char *text, zbx_uint64_t *hostids, int hostids_num)
11243 {
11244 	zbx_token_t	token;
11245 	int		pos = 0, len, last_pos = 0;
11246 	char		*str = NULL, *name = NULL, *context = NULL, *value = NULL;
11247 	size_t		str_alloc = 0, str_offset = 0;
11248 
11249 	if ('\0' == *text)
11250 		return zbx_strdup(NULL, text);
11251 
11252 	for (; SUCCEED == zbx_token_find(text, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
11253 	{
11254 		if (ZBX_TOKEN_USER_MACRO != token.type)
11255 			continue;
11256 
11257 		if (SUCCEED != zbx_user_macro_parse_dyn(text + token.loc.l, &name, &context, &len, NULL))
11258 			continue;
11259 
11260 		zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, token.loc.l - last_pos);
11261 		dc_get_user_macro(hostids, hostids_num, name, context, &value);
11262 
11263 		if (NULL != value)
11264 		{
11265 			zbx_strcpy_alloc(&str, &str_alloc, &str_offset, value);
11266 			zbx_free(value);
11267 
11268 		}
11269 		else
11270 		{
11271 			zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + token.loc.l,
11272 					token.loc.r - token.loc.l + 1);
11273 		}
11274 
11275 		zbx_free(name);
11276 		zbx_free(context);
11277 
11278 		pos = token.loc.r;
11279 		last_pos = pos + 1;
11280 	}
11281 
11282 	zbx_strcpy_alloc(&str, &str_alloc, &str_offset, text + last_pos);
11283 
11284 	return str;
11285 }
11286 
11287 /******************************************************************************
11288  *                                                                            *
11289  * Function: zbx_dc_expand_user_macros                                        *
11290  *                                                                            *
11291  * Purpose: expand user macros in the specified text value                    *
11292  *                                                                            *
11293  * Parameters: text           - [IN] the text value to expand                 *
11294  *             hostid         - [IN] related hostid                           *
11295  *                                                                            *
11296  * Return value: The text value with expanded user macros. Unknown or invalid *
11297  *               macros will be left unresolved.                              *
11298  *                                                                            *
11299  * Comments: The returned value must be freed by the caller.                  *
11300  *                                                                            *
11301  ******************************************************************************/
zbx_dc_expand_user_macros(const char * text,zbx_uint64_t hostid)11302 char	*zbx_dc_expand_user_macros(const char *text, zbx_uint64_t hostid)
11303 {
11304 	char	*resolved_text;
11305 
11306 	RDLOCK_CACHE;
11307 	resolved_text = dc_expand_user_macros(text, &hostid, 1);
11308 	UNLOCK_CACHE;
11309 
11310 	return resolved_text;
11311 }
11312 
11313 /******************************************************************************
11314  *                                                                            *
11315  * Function: DCfree_item_queue                                                *
11316  *                                                                            *
11317  * Purpose: frees the item queue data vector created by DCget_item_queue()    *
11318  *                                                                            *
11319  * Parameters: queue - [IN] the item queue data vector to free                *
11320  *                                                                            *
11321  ******************************************************************************/
DCfree_item_queue(zbx_vector_ptr_t * queue)11322 void	DCfree_item_queue(zbx_vector_ptr_t *queue)
11323 {
11324 	int	i;
11325 
11326 	for (i = 0; i < queue->values_num; i++)
11327 		zbx_free(queue->values[i]);
11328 }
11329 
11330 /******************************************************************************
11331  *                                                                            *
11332  * Function: DCget_item_queue                                                 *
11333  *                                                                            *
11334  * Purpose: retrieves vector of delayed items                                 *
11335  *                                                                            *
11336  * Parameters: queue - [OUT] the vector of delayed items (optional)           *
11337  *             from  - [IN] the minimum delay time in seconds (non-negative)  *
11338  *             to    - [IN] the maximum delay time in seconds or              *
11339  *                          ZBX_QUEUE_TO_INFINITY if there is no limit        *
11340  *                                                                            *
11341  * Return value: the number of delayed items                                  *
11342  *                                                                            *
11343  ******************************************************************************/
DCget_item_queue(zbx_vector_ptr_t * queue,int from,int to)11344 int	DCget_item_queue(zbx_vector_ptr_t *queue, int from, int to)
11345 {
11346 	zbx_hashset_iter_t	iter;
11347 	const ZBX_DC_ITEM	*dc_item;
11348 	int			now, nitems = 0, data_expected_from, delay;
11349 	zbx_queue_item_t	*queue_item;
11350 
11351 	now = time(NULL);
11352 
11353 	RDLOCK_CACHE;
11354 
11355 	zbx_hashset_iter_reset(&config->items, &iter);
11356 
11357 	while (NULL != (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_iter_next(&iter)))
11358 	{
11359 		const ZBX_DC_HOST	*dc_host;
11360 		const ZBX_DC_INTERFACE	*dc_interface;
11361 
11362 		if (ITEM_STATUS_ACTIVE != dc_item->status)
11363 			continue;
11364 
11365 		if (SUCCEED != zbx_is_counted_in_item_queue(dc_item->type, dc_item->key))
11366 			continue;
11367 
11368 		if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
11369 			continue;
11370 
11371 		if (HOST_STATUS_MONITORED != dc_host->status)
11372 			continue;
11373 
11374 		if (NULL == (dc_interface = (const ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces,
11375 				&dc_item->interfaceid)))
11376 		{
11377 			continue;
11378 		}
11379 
11380 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
11381 			continue;
11382 
11383 		switch (dc_item->type)
11384 		{
11385 			case ITEM_TYPE_ZABBIX:
11386 			case ITEM_TYPE_SNMP:
11387 			case ITEM_TYPE_IPMI:
11388 			case ITEM_TYPE_JMX:
11389 				if (INTERFACE_AVAILABLE_TRUE != dc_interface->available)
11390 					continue;
11391 				break;
11392 			case ITEM_TYPE_ZABBIX_ACTIVE:
11393 				if (dc_host->data_expected_from > (data_expected_from = dc_item->data_expected_from))
11394 					data_expected_from = dc_host->data_expected_from;
11395 				if (SUCCEED != zbx_interval_preproc(dc_item->delay, &delay, NULL, NULL))
11396 					continue;
11397 				if (data_expected_from + delay > now)
11398 					continue;
11399 				break;
11400 
11401 		}
11402 
11403 		if (now - dc_item->nextcheck < from || (ZBX_QUEUE_TO_INFINITY != to && now - dc_item->nextcheck >= to))
11404 			continue;
11405 
11406 		if (NULL != queue)
11407 		{
11408 			queue_item = (zbx_queue_item_t *)zbx_malloc(NULL, sizeof(zbx_queue_item_t));
11409 			queue_item->itemid = dc_item->itemid;
11410 			queue_item->type = dc_item->type;
11411 			queue_item->nextcheck = dc_item->nextcheck;
11412 			queue_item->proxy_hostid = dc_host->proxy_hostid;
11413 
11414 			zbx_vector_ptr_append(queue, queue_item);
11415 		}
11416 		nitems++;
11417 	}
11418 
11419 	UNLOCK_CACHE;
11420 
11421 	return nitems;
11422 }
11423 
11424 /******************************************************************************
11425  *                                                                            *
11426  * Function: dc_trigger_items_hosts_enabled                                   *
11427  *                                                                            *
11428  * Purpose: check that functionids in trigger (recovery) expression           *
11429  *                                                                            *
11430  * Parameters: expression - [IN] trigger (recovery) expression                *
11431  *             data       - [IN] parsed and serialized expression             *
11432  *                                                                            *
11433  * Return value: SUCCEED - all functionids correspond to enabled items and    *
11434  *                           enabled hosts                                    *
11435  *               FAIL    - at least one item or host is disabled              *
11436  *                                                                            *
11437  ******************************************************************************/
dc_trigger_items_hosts_enabled(const char * expression,const unsigned char * data)11438 static int	dc_trigger_items_hosts_enabled(const char *expression, const unsigned char *data)
11439 {
11440 	zbx_uint64_t		functionid;
11441 	const ZBX_DC_ITEM	*dc_item;
11442 	const ZBX_DC_FUNCTION	*dc_function;
11443 	const ZBX_DC_HOST	*dc_host;
11444 	int			i, ret = FAIL;
11445 	zbx_vector_uint64_t	functionids;
11446 
11447 	zbx_vector_uint64_create(&functionids);
11448 	zbx_get_serialized_expression_functionids(expression, data, &functionids);
11449 
11450 	for (i = 0; i < functionids.values_num; i++)
11451 	{
11452 		functionid = functionids.values[i];
11453 
11454 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionid)))
11455 			goto out;
11456 
11457 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_function->itemid)))
11458 			goto out;
11459 
11460 		if (ITEM_STATUS_ACTIVE != dc_item->status)
11461 			goto out;
11462 
11463 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
11464 			goto out;
11465 
11466 		if (HOST_STATUS_MONITORED != dc_host->status)
11467 			goto out;
11468 	}
11469 
11470 	ret = SUCCEED;
11471 out:
11472 	zbx_vector_uint64_destroy(&functionids);
11473 
11474 	return ret;
11475 }
11476 
11477 /******************************************************************************
11478  *                                                                            *
11479  * Function: dc_status_update                                                 *
11480  *                                                                            *
11481  * Purpose: check when status information stored in configuration cache was   *
11482  *          updated last time and update it if necessary                      *
11483  *                                                                            *
11484  * Comments: This function gathers the following information:                 *
11485  *             - number of enabled hosts (total and per proxy)                *
11486  *             - number of disabled hosts (total and per proxy)               *
11487  *             - number of enabled and supported items (total, per host and   *
11488  *                                                                 per proxy) *
11489  *             - number of enabled and not supported items (total, per host   *
11490  *                                                             and per proxy) *
11491  *             - number of disabled items (total and per proxy)               *
11492  *             - number of enabled triggers with value OK                     *
11493  *             - number of enabled triggers with value PROBLEM                *
11494  *             - number of disabled triggers                                  *
11495  *             - required performance (total and per proxy)                   *
11496  *           Gathered information can then be displayed in the frontend (see  *
11497  *           "status.get" request) and used in calculation of zabbix[] items. *
11498  *                                                                            *
11499  * NOTE: Always call this function before accessing information stored in     *
11500  *       config->status as well as host and required performance counters     *
11501  *       stored in elements of config->proxies and item counters in elements  *
11502  *       of config->hosts.                                                    *
11503  *                                                                            *
11504  ******************************************************************************/
dc_status_update(void)11505 static void	dc_status_update(void)
11506 {
11507 #define ZBX_STATUS_LIFETIME	SEC_PER_MIN
11508 
11509 	zbx_hashset_iter_t	iter;
11510 	ZBX_DC_PROXY		*dc_proxy;
11511 	ZBX_DC_HOST		*dc_host, *dc_proxy_host;
11512 	const ZBX_DC_ITEM	*dc_item;
11513 	const ZBX_DC_TRIGGER	*dc_trigger;
11514 
11515 	if (0 != config->status->last_update && config->status->last_update + ZBX_STATUS_LIFETIME > time(NULL))
11516 		return;
11517 
11518 	/* reset global counters */
11519 
11520 	config->status->hosts_monitored = 0;
11521 	config->status->hosts_not_monitored = 0;
11522 	config->status->items_active_normal = 0;
11523 	config->status->items_active_notsupported = 0;
11524 	config->status->items_disabled = 0;
11525 	config->status->triggers_enabled_ok = 0;
11526 	config->status->triggers_enabled_problem = 0;
11527 	config->status->triggers_disabled = 0;
11528 	config->status->required_performance = 0.0;
11529 
11530 	/* loop over proxies to reset per-proxy host and required performance counters */
11531 
11532 	zbx_hashset_iter_reset(&config->proxies, &iter);
11533 
11534 	while (NULL != (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_iter_next(&iter)))
11535 	{
11536 		dc_proxy->hosts_monitored = 0;
11537 		dc_proxy->hosts_not_monitored = 0;
11538 		dc_proxy->required_performance = 0.0;
11539 	}
11540 
11541 	/* loop over hosts */
11542 
11543 	zbx_hashset_iter_reset(&config->hosts, &iter);
11544 
11545 	while (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
11546 	{
11547 		/* reset per-host/per-proxy item counters */
11548 
11549 		dc_host->items_active_normal = 0;
11550 		dc_host->items_active_notsupported = 0;
11551 		dc_host->items_disabled = 0;
11552 
11553 		/* gather per-proxy statistics of enabled and disabled hosts */
11554 		switch (dc_host->status)
11555 		{
11556 			case HOST_STATUS_MONITORED:
11557 				config->status->hosts_monitored++;
11558 				if (0 == dc_host->proxy_hostid)
11559 					break;
11560 				if (NULL == (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->proxy_hostid)))
11561 					break;
11562 				dc_proxy->hosts_monitored++;
11563 				break;
11564 			case HOST_STATUS_NOT_MONITORED:
11565 				config->status->hosts_not_monitored++;
11566 				if (0 == dc_host->proxy_hostid)
11567 					break;
11568 				if (NULL == (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->proxy_hostid)))
11569 					break;
11570 				dc_proxy->hosts_not_monitored++;
11571 				break;
11572 		}
11573 	}
11574 
11575 	/* loop over items to gather per-host and per-proxy statistics */
11576 
11577 	zbx_hashset_iter_reset(&config->items, &iter);
11578 
11579 	while (NULL != (dc_item = (ZBX_DC_ITEM *)zbx_hashset_iter_next(&iter)))
11580 	{
11581 		dc_proxy = NULL;
11582 		dc_proxy_host = NULL;
11583 
11584 		if (ZBX_FLAG_DISCOVERY_NORMAL != dc_item->flags && ZBX_FLAG_DISCOVERY_CREATED != dc_item->flags)
11585 			continue;
11586 
11587 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
11588 			continue;
11589 
11590 		if (0 != dc_host->proxy_hostid)
11591 		{
11592 			dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->proxy_hostid);
11593 			dc_proxy_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_host->proxy_hostid);
11594 		}
11595 
11596 		switch (dc_item->status)
11597 		{
11598 			case ITEM_STATUS_ACTIVE:
11599 				if (HOST_STATUS_MONITORED == dc_host->status)
11600 				{
11601 					int	delay;
11602 
11603 					if (SUCCEED == zbx_interval_preproc(dc_item->delay, &delay, NULL, NULL) &&
11604 							0 != delay)
11605 					{
11606 						config->status->required_performance += 1.0 / delay;
11607 
11608 						if (NULL != dc_proxy)
11609 							dc_proxy->required_performance += 1.0 / delay;
11610 					}
11611 
11612 					switch (dc_item->state)
11613 					{
11614 						case ITEM_STATE_NORMAL:
11615 							config->status->items_active_normal++;
11616 							dc_host->items_active_normal++;
11617 							if (NULL != dc_proxy_host)
11618 								dc_proxy_host->items_active_normal++;
11619 							break;
11620 						case ITEM_STATE_NOTSUPPORTED:
11621 							config->status->items_active_notsupported++;
11622 							dc_host->items_active_notsupported++;
11623 							if (NULL != dc_proxy_host)
11624 								dc_proxy_host->items_active_notsupported++;
11625 							break;
11626 						default:
11627 							THIS_SHOULD_NEVER_HAPPEN;
11628 					}
11629 
11630 					break;
11631 				}
11632 				ZBX_FALLTHROUGH;
11633 			case ITEM_STATUS_DISABLED:
11634 				config->status->items_disabled++;
11635 				if (NULL != dc_proxy_host)
11636 					dc_proxy_host->items_disabled++;
11637 				break;
11638 			default:
11639 				THIS_SHOULD_NEVER_HAPPEN;
11640 		}
11641 	}
11642 
11643 	/* loop over triggers to gather enabled and disabled trigger statistics */
11644 
11645 	zbx_hashset_iter_reset(&config->triggers, &iter);
11646 
11647 	while (NULL != (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
11648 	{
11649 		switch (dc_trigger->status)
11650 		{
11651 			case TRIGGER_STATUS_ENABLED:
11652 				if (SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->expression,
11653 						dc_trigger->expression_bin) &&
11654 						(TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION != dc_trigger->recovery_mode ||
11655 						SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->recovery_expression,
11656 								dc_trigger->recovery_expression_bin)))
11657 				{
11658 					switch (dc_trigger->value)
11659 					{
11660 						case TRIGGER_VALUE_OK:
11661 							config->status->triggers_enabled_ok++;
11662 							break;
11663 						case TRIGGER_VALUE_PROBLEM:
11664 							config->status->triggers_enabled_problem++;
11665 							break;
11666 						default:
11667 							THIS_SHOULD_NEVER_HAPPEN;
11668 					}
11669 
11670 					break;
11671 				}
11672 				ZBX_FALLTHROUGH;
11673 			case TRIGGER_STATUS_DISABLED:
11674 				config->status->triggers_disabled++;
11675 				break;
11676 			default:
11677 				THIS_SHOULD_NEVER_HAPPEN;
11678 		}
11679 	}
11680 
11681 	config->status->last_update = time(NULL);
11682 
11683 #undef ZBX_STATUS_LIFETIME
11684 }
11685 
11686 /******************************************************************************
11687  *                                                                            *
11688  * Function: DCget_item_count                                                 *
11689  *                                                                            *
11690  * Purpose: return the number of active items                                 *
11691  *                                                                            *
11692  * Parameters: hostid - [IN] the host id, pass 0 to specify all hosts         *
11693  *                                                                            *
11694  * Return value: the number of active items                                   *
11695  *                                                                            *
11696  ******************************************************************************/
DCget_item_count(zbx_uint64_t hostid)11697 zbx_uint64_t	DCget_item_count(zbx_uint64_t hostid)
11698 {
11699 	zbx_uint64_t		count;
11700 	const ZBX_DC_HOST	*dc_host;
11701 
11702 	WRLOCK_CACHE;
11703 
11704 	dc_status_update();
11705 
11706 	if (0 == hostid)
11707 		count = config->status->items_active_normal + config->status->items_active_notsupported;
11708 	else if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
11709 		count = dc_host->items_active_normal + dc_host->items_active_notsupported;
11710 	else
11711 		count = 0;
11712 
11713 	UNLOCK_CACHE;
11714 
11715 	return count;
11716 }
11717 
11718 /******************************************************************************
11719  *                                                                            *
11720  * Function: DCget_item_unsupported_count                                     *
11721  *                                                                            *
11722  * Purpose: return the number of active unsupported items                     *
11723  *                                                                            *
11724  * Parameters: hostid - [IN] the host id, pass 0 to specify all hosts         *
11725  *                                                                            *
11726  * Return value: the number of active unsupported items                       *
11727  *                                                                            *
11728  ******************************************************************************/
DCget_item_unsupported_count(zbx_uint64_t hostid)11729 zbx_uint64_t	DCget_item_unsupported_count(zbx_uint64_t hostid)
11730 {
11731 	zbx_uint64_t		count;
11732 	const ZBX_DC_HOST	*dc_host;
11733 
11734 	WRLOCK_CACHE;
11735 
11736 	dc_status_update();
11737 
11738 	if (0 == hostid)
11739 		count = config->status->items_active_notsupported;
11740 	else if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
11741 		count = dc_host->items_active_notsupported;
11742 	else
11743 		count = 0;
11744 
11745 	UNLOCK_CACHE;
11746 
11747 	return count;
11748 }
11749 
11750 /******************************************************************************
11751  *                                                                            *
11752  * Function: DCget_trigger_count                                              *
11753  *                                                                            *
11754  * Purpose: count active triggers                                             *
11755  *                                                                            *
11756  ******************************************************************************/
DCget_trigger_count(void)11757 zbx_uint64_t	DCget_trigger_count(void)
11758 {
11759 	zbx_uint64_t	count;
11760 
11761 	WRLOCK_CACHE;
11762 
11763 	dc_status_update();
11764 
11765 	count = config->status->triggers_enabled_ok + config->status->triggers_enabled_problem;
11766 
11767 	UNLOCK_CACHE;
11768 
11769 	return count;
11770 }
11771 
11772 /******************************************************************************
11773  *                                                                            *
11774  * Function: DCget_host_count                                                 *
11775  *                                                                            *
11776  * Purpose: count monitored and not monitored hosts                           *
11777  *                                                                            *
11778  ******************************************************************************/
DCget_host_count(void)11779 zbx_uint64_t	DCget_host_count(void)
11780 {
11781 	zbx_uint64_t	nhosts;
11782 
11783 	WRLOCK_CACHE;
11784 
11785 	dc_status_update();
11786 
11787 	nhosts = config->status->hosts_monitored;
11788 
11789 	UNLOCK_CACHE;
11790 
11791 	return nhosts;
11792 }
11793 
11794 /******************************************************************************
11795  *                                                                            *
11796  * Function: DCget_required_performance                                       *
11797  *                                                                            *
11798  * Return value: the required nvps number                                     *
11799  *                                                                            *
11800  ******************************************************************************/
DCget_required_performance(void)11801 double	DCget_required_performance(void)
11802 {
11803 	double	nvps;
11804 
11805 	WRLOCK_CACHE;
11806 
11807 	dc_status_update();
11808 
11809 	nvps = config->status->required_performance;
11810 
11811 	UNLOCK_CACHE;
11812 
11813 	return nvps;
11814 }
11815 
11816 /******************************************************************************
11817  *                                                                            *
11818  * Function: DCget_count_stats_all                                            *
11819  *                                                                            *
11820  * Purpose: retrieves all internal metrics of the configuration cache         *
11821  *                                                                            *
11822  * Parameters: stats - [OUT] the configuration cache statistics               *
11823  *                                                                            *
11824  ******************************************************************************/
DCget_count_stats_all(zbx_config_cache_info_t * stats)11825 void	DCget_count_stats_all(zbx_config_cache_info_t *stats)
11826 {
11827 	WRLOCK_CACHE;
11828 
11829 	dc_status_update();
11830 
11831 	stats->hosts = config->status->hosts_monitored;
11832 	stats->items = config->status->items_active_normal + config->status->items_active_notsupported;
11833 	stats->items_unsupported = config->status->items_active_notsupported;
11834 	stats->requiredperformance = config->status->required_performance;
11835 
11836 	UNLOCK_CACHE;
11837 }
11838 
proxy_counter_ui64_push(zbx_vector_ptr_t * vector,zbx_uint64_t proxyid,zbx_uint64_t counter)11839 static void	proxy_counter_ui64_push(zbx_vector_ptr_t *vector, zbx_uint64_t proxyid, zbx_uint64_t counter)
11840 {
11841 	zbx_proxy_counter_t	*proxy_counter;
11842 
11843 	proxy_counter = (zbx_proxy_counter_t *)zbx_malloc(NULL, sizeof(zbx_proxy_counter_t));
11844 	proxy_counter->proxyid = proxyid;
11845 	proxy_counter->counter_value.ui64 = counter;
11846 	zbx_vector_ptr_append(vector, proxy_counter);
11847 }
11848 
proxy_counter_dbl_push(zbx_vector_ptr_t * vector,zbx_uint64_t proxyid,double counter)11849 static void	proxy_counter_dbl_push(zbx_vector_ptr_t *vector, zbx_uint64_t proxyid, double counter)
11850 {
11851 	zbx_proxy_counter_t	*proxy_counter;
11852 
11853 	proxy_counter = (zbx_proxy_counter_t *)zbx_malloc(NULL, sizeof(zbx_proxy_counter_t));
11854 	proxy_counter->proxyid = proxyid;
11855 	proxy_counter->counter_value.dbl = counter;
11856 	zbx_vector_ptr_append(vector, proxy_counter);
11857 }
11858 
DCget_status(zbx_vector_ptr_t * hosts_monitored,zbx_vector_ptr_t * hosts_not_monitored,zbx_vector_ptr_t * items_active_normal,zbx_vector_ptr_t * items_active_notsupported,zbx_vector_ptr_t * items_disabled,zbx_uint64_t * triggers_enabled_ok,zbx_uint64_t * triggers_enabled_problem,zbx_uint64_t * triggers_disabled,zbx_vector_ptr_t * required_performance)11859 void	DCget_status(zbx_vector_ptr_t *hosts_monitored, zbx_vector_ptr_t *hosts_not_monitored,
11860 		zbx_vector_ptr_t *items_active_normal, zbx_vector_ptr_t *items_active_notsupported,
11861 		zbx_vector_ptr_t *items_disabled, zbx_uint64_t *triggers_enabled_ok,
11862 		zbx_uint64_t *triggers_enabled_problem, zbx_uint64_t *triggers_disabled,
11863 		zbx_vector_ptr_t *required_performance)
11864 {
11865 	zbx_hashset_iter_t	iter;
11866 	const ZBX_DC_PROXY	*dc_proxy;
11867 	const ZBX_DC_HOST	*dc_proxy_host;
11868 
11869 	WRLOCK_CACHE;
11870 
11871 	dc_status_update();
11872 
11873 	proxy_counter_ui64_push(hosts_monitored, 0, config->status->hosts_monitored);
11874 	proxy_counter_ui64_push(hosts_not_monitored, 0, config->status->hosts_not_monitored);
11875 	proxy_counter_ui64_push(items_active_normal, 0, config->status->items_active_normal);
11876 	proxy_counter_ui64_push(items_active_notsupported, 0, config->status->items_active_notsupported);
11877 	proxy_counter_ui64_push(items_disabled, 0, config->status->items_disabled);
11878 	*triggers_enabled_ok = config->status->triggers_enabled_ok;
11879 	*triggers_enabled_problem = config->status->triggers_enabled_problem;
11880 	*triggers_disabled = config->status->triggers_disabled;
11881 	proxy_counter_dbl_push(required_performance, 0, config->status->required_performance);
11882 
11883 	zbx_hashset_iter_reset(&config->proxies, &iter);
11884 
11885 	while (NULL != (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_iter_next(&iter)))
11886 	{
11887 		proxy_counter_ui64_push(hosts_monitored, dc_proxy->hostid, dc_proxy->hosts_monitored);
11888 		proxy_counter_ui64_push(hosts_not_monitored, dc_proxy->hostid, dc_proxy->hosts_not_monitored);
11889 
11890 		if (NULL != (dc_proxy_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_proxy->hostid)))
11891 		{
11892 			proxy_counter_ui64_push(items_active_normal, dc_proxy->hostid,
11893 					dc_proxy_host->items_active_normal);
11894 			proxy_counter_ui64_push(items_active_notsupported, dc_proxy->hostid,
11895 					dc_proxy_host->items_active_notsupported);
11896 			proxy_counter_ui64_push(items_disabled, dc_proxy->hostid, dc_proxy_host->items_disabled);
11897 		}
11898 
11899 		proxy_counter_dbl_push(required_performance, dc_proxy->hostid, dc_proxy->required_performance);
11900 	}
11901 
11902 	UNLOCK_CACHE;
11903 }
11904 
11905 /******************************************************************************
11906  *                                                                            *
11907  * Function: DCget_expressions_by_names                                       *
11908  *                                                                            *
11909  * Purpose: retrieves global expression data from cache                       *
11910  *                                                                            *
11911  * Parameters: expressions  - [OUT] a vector of expression data pointers      *
11912  *             names        - [IN] a vector containing expression names       *
11913  *             names_num    - [IN] the number of items in names vector        *
11914  *                                                                            *
11915  * Comment: The expressions vector contains allocated data, which must be     *
11916  *          freed afterwards with zbx_regexp_clean_expressions() function.    *
11917  *                                                                            *
11918  ******************************************************************************/
DCget_expressions_by_names(zbx_vector_ptr_t * expressions,const char * const * names,int names_num)11919 void	DCget_expressions_by_names(zbx_vector_ptr_t *expressions, const char * const *names, int names_num)
11920 {
11921 	int			i, iname;
11922 	const ZBX_DC_EXPRESSION	*expression;
11923 	const ZBX_DC_REGEXP	*regexp;
11924 	ZBX_DC_REGEXP		search_regexp;
11925 
11926 	RDLOCK_CACHE;
11927 
11928 	for (iname = 0; iname < names_num; iname++)
11929 	{
11930 		search_regexp.name = names[iname];
11931 
11932 		if (NULL != (regexp = (const ZBX_DC_REGEXP *)zbx_hashset_search(&config->regexps, &search_regexp)))
11933 		{
11934 			for (i = 0; i < regexp->expressionids.values_num; i++)
11935 			{
11936 				zbx_uint64_t		expressionid = regexp->expressionids.values[i];
11937 				zbx_expression_t	*rxp;
11938 
11939 				if (NULL == (expression = (const ZBX_DC_EXPRESSION *)zbx_hashset_search(&config->expressions, &expressionid)))
11940 					continue;
11941 
11942 				rxp = (zbx_expression_t *)zbx_malloc(NULL, sizeof(zbx_expression_t));
11943 				rxp->name = zbx_strdup(NULL, regexp->name);
11944 				rxp->expression = zbx_strdup(NULL, expression->expression);
11945 				rxp->exp_delimiter = expression->delimiter;
11946 				rxp->case_sensitive = expression->case_sensitive;
11947 				rxp->expression_type = expression->type;
11948 
11949 				zbx_vector_ptr_append(expressions, rxp);
11950 			}
11951 		}
11952 	}
11953 
11954 	UNLOCK_CACHE;
11955 }
11956 
11957 /******************************************************************************
11958  *                                                                            *
11959  * Function: DCget_expression                                                 *
11960  *                                                                            *
11961  * Purpose: retrieves regular expression data from cache                      *
11962  *                                                                            *
11963  * Parameters: expressions  - [OUT] a vector of expression data pointers      *
11964  *             name         - [IN] the regular expression name                *
11965  *                                                                            *
11966  * Comment: The expressions vector contains allocated data, which must be     *
11967  *          freed afterwards with zbx_regexp_clean_expressions() function.    *
11968  *                                                                            *
11969  ******************************************************************************/
DCget_expressions_by_name(zbx_vector_ptr_t * expressions,const char * name)11970 void	DCget_expressions_by_name(zbx_vector_ptr_t *expressions, const char *name)
11971 {
11972 	DCget_expressions_by_names(expressions, &name, 1);
11973 }
11974 
11975 /******************************************************************************
11976  *                                                                            *
11977  * Function: DCget_data_expected_from                                         *
11978  *                                                                            *
11979  * Purpose: Returns time since which data is expected for the given item. We  *
11980  *          would not mind not having data for the item before that time, but *
11981  *          since that time we expect data to be coming.                      *
11982  *                                                                            *
11983  * Parameters: itemid  - [IN] the item id                                     *
11984  *             seconds - [OUT] the time data is expected as a Unix timestamp  *
11985  *                                                                            *
11986  ******************************************************************************/
DCget_data_expected_from(zbx_uint64_t itemid,int * seconds)11987 int	DCget_data_expected_from(zbx_uint64_t itemid, int *seconds)
11988 {
11989 	const ZBX_DC_ITEM	*dc_item;
11990 	const ZBX_DC_HOST	*dc_host;
11991 	int			ret = FAIL;
11992 
11993 	RDLOCK_CACHE;
11994 
11995 	if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
11996 		goto unlock;
11997 
11998 	if (ITEM_STATUS_ACTIVE != dc_item->status)
11999 		goto unlock;
12000 
12001 	if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
12002 		goto unlock;
12003 
12004 	if (HOST_STATUS_MONITORED != dc_host->status)
12005 		goto unlock;
12006 
12007 	*seconds = MAX(dc_item->data_expected_from, dc_host->data_expected_from);
12008 
12009 	ret = SUCCEED;
12010 unlock:
12011 	UNLOCK_CACHE;
12012 
12013 	return ret;
12014 }
12015 
12016 /******************************************************************************
12017  *                                                                            *
12018  * Function: dc_get_hostids_by_functionids                                    *
12019  *                                                                            *
12020  * Purpose: get host identifiers for the specified list of functions          *
12021  *                                                                            *
12022  * Parameters: functionids     - [IN] the function ids                        *
12023  *             functionids_num - [IN] the number of function ids              *
12024  *             hostids         - [OUT] the host ids                           *
12025  *                                                                            *
12026  * Comments: this function must be used only by configuration syncer          *
12027  *                                                                            *
12028  ******************************************************************************/
dc_get_hostids_by_functionids(const zbx_uint64_t * functionids,int functionids_num,zbx_vector_uint64_t * hostids)12029 void	dc_get_hostids_by_functionids(const zbx_uint64_t *functionids, int functionids_num,
12030 		zbx_vector_uint64_t *hostids)
12031 {
12032 	const ZBX_DC_FUNCTION	*function;
12033 	const ZBX_DC_ITEM	*item;
12034 	int			i;
12035 
12036 	for (i = 0; i < functionids_num; i++)
12037 	{
12038 		if (NULL == (function = (const ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids[i])))
12039 				continue;
12040 
12041 		if (NULL != (item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
12042 			zbx_vector_uint64_append(hostids, item->hostid);
12043 	}
12044 
12045 	zbx_vector_uint64_sort(hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
12046 	zbx_vector_uint64_uniq(hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
12047 }
12048 
12049 /******************************************************************************
12050  *                                                                            *
12051  * Function: DCget_hostids_by_functionids                                     *
12052  *                                                                            *
12053  * Purpose: get function host ids grouped by an object (trigger) id           *
12054  *                                                                            *
12055  * Parameters: functionids - [IN] the function ids                            *
12056  *             hostids     - [OUT] the host ids                               *
12057  *                                                                            *
12058  ******************************************************************************/
DCget_hostids_by_functionids(zbx_vector_uint64_t * functionids,zbx_vector_uint64_t * hostids)12059 void	DCget_hostids_by_functionids(zbx_vector_uint64_t *functionids, zbx_vector_uint64_t *hostids)
12060 {
12061 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
12062 
12063 	RDLOCK_CACHE;
12064 
12065 	dc_get_hostids_by_functionids(functionids->values, functionids->values_num, hostids);
12066 
12067 	UNLOCK_CACHE;
12068 
12069 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s(): found %d hosts", __func__, hostids->values_num);
12070 }
12071 
12072 /******************************************************************************
12073  *                                                                            *
12074  * Function: dc_get_hosts_by_functionids                                      *
12075  *                                                                            *
12076  * Purpose: get hosts for the specified list of functions                     *
12077  *                                                                            *
12078  * Parameters: functionids     - [IN] the function ids                        *
12079  *             functionids_num - [IN] the number of function ids              *
12080  *             hosts           - [OUT] hosts                                  *
12081  *                                                                            *
12082  ******************************************************************************/
dc_get_hosts_by_functionids(const zbx_uint64_t * functionids,int functionids_num,zbx_hashset_t * hosts)12083 static void	dc_get_hosts_by_functionids(const zbx_uint64_t *functionids, int functionids_num, zbx_hashset_t *hosts)
12084 {
12085 	const ZBX_DC_FUNCTION	*dc_function;
12086 	const ZBX_DC_ITEM	*dc_item;
12087 	const ZBX_DC_HOST	*dc_host;
12088 	DC_HOST			host;
12089 	int			i;
12090 
12091 	for (i = 0; i < functionids_num; i++)
12092 	{
12093 		if (NULL == (dc_function = (const ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids[i])))
12094 			continue;
12095 
12096 		if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_function->itemid)))
12097 			continue;
12098 
12099 		if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
12100 			continue;
12101 
12102 		DCget_host(&host, dc_host, ZBX_ITEM_GET_ALL);
12103 		zbx_hashset_insert(hosts, &host, sizeof(host));
12104 	}
12105 }
12106 
12107 /******************************************************************************
12108  *                                                                            *
12109  * Function: DCget_hosts_by_functionids                                       *
12110  *                                                                            *
12111  * Purpose: get hosts for the specified list of functions                     *
12112  *                                                                            *
12113  * Parameters: functionids - [IN] the function ids                            *
12114  *             hosts       - [OUT] hosts                                      *
12115  *                                                                            *
12116  ******************************************************************************/
DCget_hosts_by_functionids(const zbx_vector_uint64_t * functionids,zbx_hashset_t * hosts)12117 void	DCget_hosts_by_functionids(const zbx_vector_uint64_t *functionids, zbx_hashset_t *hosts)
12118 {
12119 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
12120 
12121 	RDLOCK_CACHE;
12122 
12123 	dc_get_hosts_by_functionids(functionids->values, functionids->values_num, hosts);
12124 
12125 	UNLOCK_CACHE;
12126 
12127 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s(): found %d hosts", __func__, hosts->num_data);
12128 }
12129 
12130 /******************************************************************************
12131  *                                                                            *
12132  * Function: DCget_internal_action_count                                      *
12133  *                                                                            *
12134  * Purpose: get number of enabled internal actions                            *
12135  *                                                                            *
12136  * Return value: number of enabled internal actions                           *
12137  *                                                                            *
12138  ******************************************************************************/
DCget_internal_action_count(void)12139 unsigned int	DCget_internal_action_count(void)
12140 {
12141 	unsigned int count;
12142 
12143 	RDLOCK_CACHE;
12144 
12145 	count = config->internal_actions;
12146 
12147 	UNLOCK_CACHE;
12148 
12149 	return count;
12150 }
12151 
12152 /******************************************************************************
12153  *                                                                            *
12154  * Function: zbx_config_get                                                   *
12155  *                                                                            *
12156  * Purpose: get global configuration data                                     *
12157  *                                                                            *
12158  * Parameters: cfg   - [OUT] the global configuration data                    *
12159  *             flags - [IN] the flags specifying fields to get,               *
12160  *                          see ZBX_CONFIG_FLAGS_ defines                     *
12161  *                                                                            *
12162  * Comments: It's recommended to cleanup 'cfg' structure after use with       *
12163  *           zbx_config_clean() function even if only simple fields were      *
12164  *           requested.                                                       *
12165  *                                                                            *
12166  ******************************************************************************/
zbx_config_get(zbx_config_t * cfg,zbx_uint64_t flags)12167 void	zbx_config_get(zbx_config_t *cfg, zbx_uint64_t flags)
12168 {
12169 	RDLOCK_CACHE;
12170 
12171 	if (0 != (flags & ZBX_CONFIG_FLAGS_SEVERITY_NAME))
12172 	{
12173 		int	i;
12174 
12175 		cfg->severity_name = (char **)zbx_malloc(NULL, TRIGGER_SEVERITY_COUNT * sizeof(char *));
12176 
12177 		for (i = 0; i < TRIGGER_SEVERITY_COUNT; i++)
12178 			cfg->severity_name[i] = zbx_strdup(NULL, config->config->severity_name[i]);
12179 	}
12180 
12181 	if (0 != (flags & ZBX_CONFIG_FLAGS_DISCOVERY_GROUPID))
12182 		cfg->discovery_groupid = config->config->discovery_groupid;
12183 
12184 	if (0 != (flags & ZBX_CONFIG_FLAGS_DEFAULT_INVENTORY_MODE))
12185 		cfg->default_inventory_mode = config->config->default_inventory_mode;
12186 
12187 	if (0 != (flags & ZBX_CONFIG_FLAGS_SNMPTRAP_LOGGING))
12188 		cfg->snmptrap_logging = config->config->snmptrap_logging;
12189 
12190 	if (0 != (flags & ZBX_CONFIG_FLAGS_HOUSEKEEPER))
12191 		cfg->hk = config->config->hk;
12192 
12193 	if (0 != (flags & ZBX_CONFIG_FLAGS_DB_EXTENSION))
12194 	{
12195 		cfg->db.extension = zbx_strdup(NULL, config->config->db.extension);
12196 		cfg->db.history_compression_status = config->config->db.history_compression_status;
12197 		cfg->db.history_compress_older = config->config->db.history_compress_older;
12198 	}
12199 
12200 	if (0 != (flags & ZBX_CONFIG_FLAGS_AUTOREG_TLS_ACCEPT))
12201 		cfg->autoreg_tls_accept = config->config->autoreg_tls_accept;
12202 
12203 	if (0 != (flags & ZBX_CONFIG_FLAGS_DEFAULT_TIMEZONE))
12204 		cfg->default_timezone = zbx_strdup(NULL, config->config->default_timezone);
12205 
12206 	UNLOCK_CACHE;
12207 
12208 	cfg->flags = flags;
12209 }
12210 
12211 /******************************************************************************
12212  *                                                                            *
12213  * Function: zbx_config_get_hk_mode                                           *
12214  *                                                                            *
12215  * Purpose: get housekeeping mode for history and trends tables               *
12216  *                                                                            *
12217  * Parameters: history_mode - [OUT] history housekeeping mode, can be either  *
12218  *                                  disabled, enabled or partitioning         *
12219  *             trends_mode  - [OUT] trends housekeeping mode, can be either   *
12220  *                                  disabled, enabled or partitioning         *
12221  *                                                                            *
12222  ******************************************************************************/
zbx_config_get_hk_mode(unsigned char * history_mode,unsigned char * trends_mode)12223 void	zbx_config_get_hk_mode(unsigned char *history_mode, unsigned char *trends_mode)
12224 {
12225 	RDLOCK_CACHE;
12226 	*history_mode = config->config->hk.history_mode;
12227 	*trends_mode = config->config->hk.trends_mode;
12228 	UNLOCK_CACHE;
12229 }
12230 
12231 /******************************************************************************
12232  *                                                                            *
12233  * Function: zbx_config_clean                                                 *
12234  *                                                                            *
12235  * Purpose: cleans global configuration data structure filled                 *
12236  *          by zbx_config_get() function                                      *
12237  *                                                                            *
12238  * Parameters: cfg   - [IN] the global configuration data                     *
12239  *                                                                            *
12240  ******************************************************************************/
zbx_config_clean(zbx_config_t * cfg)12241 void	zbx_config_clean(zbx_config_t *cfg)
12242 {
12243 	if (0 != (cfg->flags & ZBX_CONFIG_FLAGS_SEVERITY_NAME))
12244 	{
12245 		int	i;
12246 
12247 		for (i = 0; i < TRIGGER_SEVERITY_COUNT; i++)
12248 			zbx_free(cfg->severity_name[i]);
12249 
12250 		zbx_free(cfg->severity_name);
12251 	}
12252 
12253 	if (0 != (cfg->flags & ZBX_CONFIG_FLAGS_DB_EXTENSION))
12254 		zbx_free(cfg->db.extension);
12255 
12256 	if (0 != (cfg->flags & ZBX_CONFIG_FLAGS_DEFAULT_TIMEZONE))
12257 		zbx_free(cfg->default_timezone);
12258 }
12259 
12260 /*********************************************************************************
12261  *                                                                               *
12262  * Function: DCreset_interfaces_availability                                     *
12263  *                                                                               *
12264  * Purpose: resets interfaces availability for disabled hosts and hosts          *
12265  *          without enabled items for the corresponding interface                *
12266  *                                                                               *
12267  * Parameters: interfaces - [OUT] changed interface availability data            *
12268  *                                                                               *
12269  * Return value: SUCCEED - interface availability was reset for at least one     *
12270  *                         interface                                             *
12271  *               FAIL    - no interfaces required availability reset             *
12272  *                                                                               *
12273  * Comments: This function resets interface availability in configuration cache. *
12274  *           The caller must perform corresponding database updates based on     *
12275  *           returned interface availability reset data. On server the function  *
12276  *           skips hosts handled by proxies.                                     *
12277  *                                                                               *
12278  ********************************************************************************/
DCreset_interfaces_availability(zbx_vector_availability_ptr_t * interfaces)12279 int	DCreset_interfaces_availability(zbx_vector_availability_ptr_t *interfaces)
12280 {
12281 	ZBX_DC_HOST			*host;
12282 	ZBX_DC_INTERFACE		*interface;
12283 	zbx_hashset_iter_t		iter;
12284 	zbx_interface_availability_t	*ia = NULL;
12285 	int				now;
12286 
12287 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
12288 
12289 	now = time(NULL);
12290 
12291 	WRLOCK_CACHE;
12292 
12293 	zbx_hashset_iter_reset(&config->interfaces, &iter);
12294 
12295 	while (NULL != (interface = (ZBX_DC_INTERFACE *)zbx_hashset_iter_next(&iter)))
12296 	{
12297 		int	items_num = 0;
12298 
12299 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &interface->hostid)))
12300 			continue;
12301 
12302 		/* On server skip hosts handled by proxies. They are handled directly */
12303 		/* when receiving hosts' availability data from proxies.              */
12304 		/* Unless a host was just (re)assigned to a proxy or the proxy has    */
12305 		/* not updated its status during the maximum proxy heartbeat period.  */
12306 		/* In this case reset all interfaces to unknown status.               */
12307 		if (0 == interface->reset_availability &&
12308 				0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != host->proxy_hostid)
12309 		{
12310 			ZBX_DC_PROXY	*proxy;
12311 
12312 			if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &host->proxy_hostid)))
12313 			{
12314 				/* SEC_PER_MIN is a tolerance interval, it was chosen arbitrarily */
12315 				if (ZBX_PROXY_HEARTBEAT_FREQUENCY_MAX + SEC_PER_MIN >= now - proxy->lastaccess)
12316 					continue;
12317 			}
12318 
12319 			interface->reset_availability = 1;
12320 		}
12321 
12322 		if (NULL == ia)
12323 			ia = (zbx_interface_availability_t *)zbx_malloc(NULL, sizeof(zbx_interface_availability_t));
12324 
12325 		zbx_interface_availability_init(ia, interface->interfaceid);
12326 
12327 		if (0 == interface->reset_availability)
12328 			items_num = interface->items_num;
12329 
12330 		if (0 == items_num && INTERFACE_AVAILABLE_UNKNOWN != interface->available)
12331 			zbx_agent_availability_init(&ia->agent, INTERFACE_AVAILABLE_UNKNOWN, "", 0, 0);
12332 
12333 		if (SUCCEED == zbx_interface_availability_is_set(ia))
12334 		{
12335 			if (SUCCEED == DCinterface_set_availability(interface, now, ia))
12336 			{
12337 				zbx_vector_availability_ptr_append(interfaces, ia);
12338 				ia = NULL;
12339 			}
12340 			else
12341 				zbx_interface_availability_clean(ia);
12342 		}
12343 
12344 		interface->reset_availability = 0;
12345 	}
12346 	UNLOCK_CACHE;
12347 
12348 	zbx_free(ia);
12349 
12350 	zbx_vector_availability_ptr_sort(interfaces, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
12351 
12352 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() interfaces:%d", __func__, interfaces->values_num);
12353 
12354 	return 0 == interfaces->values_num ? FAIL : SUCCEED;
12355 }
12356 
12357 /*******************************************************************************
12358  *                                                                             *
12359  * Function: DCget_interfaces_availability                                     *
12360  *                                                                             *
12361  * Purpose: gets availability data for interfaces with availability data       *
12362  *          changed in period from last availability update to the specified   *
12363  *          timestamp                                                          *
12364  *                                                                             *
12365  * Parameters: interfaces - [OUT] changed interfaces availability data         *
12366  *             ts    - [OUT] the availability diff timestamp                   *
12367  *                                                                             *
12368  * Return value: SUCCEED - availability was changed for at least one interface *
12369  *               FAIL    - no interface availability was changed               *
12370  *                                                                             *
12371  *******************************************************************************/
DCget_interfaces_availability(zbx_vector_ptr_t * interfaces,int * ts)12372 int	DCget_interfaces_availability(zbx_vector_ptr_t *interfaces, int *ts)
12373 {
12374 	const ZBX_DC_INTERFACE		*interface;
12375 	zbx_hashset_iter_t		iter;
12376 	zbx_interface_availability_t	*ia = NULL;
12377 
12378 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
12379 
12380 	RDLOCK_CACHE;
12381 
12382 	*ts = time(NULL);
12383 
12384 	zbx_hashset_iter_reset(&config->interfaces, &iter);
12385 
12386 	while (NULL != (interface = (const ZBX_DC_INTERFACE *)zbx_hashset_iter_next(&iter)))
12387 	{
12388 		if (config->availability_diff_ts <= interface->availability_ts && interface->availability_ts < *ts)
12389 		{
12390 			ia = (zbx_interface_availability_t *)zbx_malloc(NULL, sizeof(zbx_interface_availability_t));
12391 			zbx_interface_availability_init(ia, interface->interfaceid);
12392 
12393 			zbx_agent_availability_init(&ia->agent, interface->available, interface->error,
12394 					interface->errors_from, interface->disable_until);
12395 
12396 			zbx_vector_ptr_append(interfaces, ia);
12397 		}
12398 	}
12399 
12400 	UNLOCK_CACHE;
12401 
12402 	zbx_vector_ptr_sort(interfaces, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
12403 
12404 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() interfaces:%d", __func__, interfaces->values_num);
12405 
12406 	return 0 == interfaces->values_num ? FAIL : SUCCEED;
12407 }
12408 
12409 /******************************************************************************
12410  *                                                                            *
12411  * Function: DCtouch_interfaces_availability                                  *
12412  *                                                                            *
12413  * Purpose: sets availability timestamp to current time for the specified     *
12414  *          interfaces                                                        *
12415  *                                                                            *
12416  * Parameters: interfaceids - [IN] the interfaces identifiers                 *
12417  *                                                                            *
12418  ******************************************************************************/
DCtouch_interfaces_availability(const zbx_vector_uint64_t * interfaceids)12419 void	DCtouch_interfaces_availability(const zbx_vector_uint64_t *interfaceids)
12420 {
12421 	ZBX_DC_INTERFACE	*dc_interface;
12422 	int			i, now;
12423 
12424 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() interfaceids:%d", __func__, interfaceids->values_num);
12425 
12426 	now = time(NULL);
12427 
12428 	WRLOCK_CACHE;
12429 
12430 	for (i = 0; i < interfaceids->values_num; i++)
12431 	{
12432 		if (NULL != (dc_interface = zbx_hashset_search(&config->interfaces, &interfaceids->values[i])))
12433 			dc_interface->availability_ts = now;
12434 	}
12435 
12436 	UNLOCK_CACHE;
12437 
12438 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
12439 }
12440 
12441 /******************************************************************************
12442  *                                                                            *
12443  * Function: dc_action_copy_conditions                                        *
12444  *                                                                            *
12445  * Purpose: copies configuration cache action conditions to the specified     *
12446  *          vector                                                            *
12447  *                                                                            *
12448  * Parameters: dc_action  - [IN] the source action                            *
12449  *             conditions - [OUT] the conditions vector                       *
12450  *                                                                            *
12451  ******************************************************************************/
dc_action_copy_conditions(const zbx_dc_action_t * dc_action,zbx_vector_ptr_t * conditions)12452 static void	dc_action_copy_conditions(const zbx_dc_action_t *dc_action, zbx_vector_ptr_t *conditions)
12453 {
12454 	int				i;
12455 	zbx_condition_t			*condition;
12456 	zbx_dc_action_condition_t	*dc_condition;
12457 
12458 	zbx_vector_ptr_reserve(conditions, dc_action->conditions.values_num);
12459 
12460 	for (i = 0; i < dc_action->conditions.values_num; i++)
12461 	{
12462 		dc_condition = (zbx_dc_action_condition_t *)dc_action->conditions.values[i];
12463 
12464 		condition = (zbx_condition_t *)zbx_malloc(NULL, sizeof(zbx_condition_t));
12465 
12466 		condition->conditionid = dc_condition->conditionid;
12467 		condition->actionid = dc_action->actionid;
12468 		condition->conditiontype = dc_condition->conditiontype;
12469 		condition->op = dc_condition->op;
12470 		condition->value = zbx_strdup(NULL, dc_condition->value);
12471 		condition->value2 = zbx_strdup(NULL, dc_condition->value2);
12472 		zbx_vector_uint64_create(&condition->eventids);
12473 
12474 		zbx_vector_ptr_append(conditions, condition);
12475 	}
12476 }
12477 
12478 /******************************************************************************
12479  *                                                                            *
12480  * Function: dc_action_eval_create                                            *
12481  *                                                                            *
12482  * Purpose: creates action evaluation data from configuration cache action    *
12483  *                                                                            *
12484  * Parameters: dc_action - [IN] the source action                             *
12485  *                                                                            *
12486  * Return value: the action evaluation data                                   *
12487  *                                                                            *
12488  * Comments: The returned value must be freed with zbx_action_eval_free()     *
12489  *           function later.                                                  *
12490  *                                                                            *
12491  ******************************************************************************/
dc_action_eval_create(const zbx_dc_action_t * dc_action)12492 static zbx_action_eval_t	*dc_action_eval_create(const zbx_dc_action_t *dc_action)
12493 {
12494 	zbx_action_eval_t		*action;
12495 
12496 	action = (zbx_action_eval_t *)zbx_malloc(NULL, sizeof(zbx_action_eval_t));
12497 
12498 	action->actionid = dc_action->actionid;
12499 	action->eventsource = dc_action->eventsource;
12500 	action->evaltype = dc_action->evaltype;
12501 	action->opflags = dc_action->opflags;
12502 	action->formula = zbx_strdup(NULL, dc_action->formula);
12503 	zbx_vector_ptr_create(&action->conditions);
12504 
12505 	dc_action_copy_conditions(dc_action, &action->conditions);
12506 
12507 	return action;
12508 }
12509 
12510 /******************************************************************************
12511  *                                                                            *
12512  * Function: zbx_dc_get_actions_eval                                          *
12513  *                                                                            *
12514  * Purpose: gets action evaluation data                                       *
12515  *                                                                            *
12516  * Parameters: actions         - [OUT] the action evaluation data             *
12517  *             uniq_conditions - [OUT] unique conditions that actions         *
12518  *                                     point to (several sources)             *
12519  *             opflags         - [IN] flags specifying which actions to get   *
12520  *                                    based on their operation classes        *
12521  *                                    (see ZBX_ACTION_OPCLASS_* defines)      *
12522  *                                                                            *
12523  * Comments: The returned actions and conditions must be freed with           *
12524  *           zbx_action_eval_free() function later.                           *
12525  *                                                                            *
12526  ******************************************************************************/
zbx_dc_get_actions_eval(zbx_vector_ptr_t * actions,unsigned char opflags)12527 void	zbx_dc_get_actions_eval(zbx_vector_ptr_t *actions, unsigned char opflags)
12528 {
12529 	const zbx_dc_action_t		*dc_action;
12530 	zbx_hashset_iter_t		iter;
12531 
12532 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
12533 
12534 	RDLOCK_CACHE;
12535 
12536 	zbx_hashset_iter_reset(&config->actions, &iter);
12537 
12538 	while (NULL != (dc_action = (const zbx_dc_action_t *)zbx_hashset_iter_next(&iter)))
12539 	{
12540 		if (0 != (opflags & dc_action->opflags))
12541 			zbx_vector_ptr_append(actions, dc_action_eval_create(dc_action));
12542 	}
12543 
12544 	UNLOCK_CACHE;
12545 
12546 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() actions:%d", __func__, actions->values_num);
12547 }
12548 
12549 /******************************************************************************
12550  *                                                                            *
12551  * Function: zbx_set_availability_update_ts                                   *
12552  *                                                                            *
12553  * Purpose: sets timestamp of the last availability update                    *
12554  *                                                                            *
12555  * Parameter: ts - [IN] the last availability update timestamp                *
12556  *                                                                            *
12557  * Comments: This function is used only by proxies when preparing host        *
12558  *           availability data to be sent to server.                          *
12559  *                                                                            *
12560  ******************************************************************************/
zbx_set_availability_diff_ts(int ts)12561 void	zbx_set_availability_diff_ts(int ts)
12562 {
12563 	/* this data can't be accessed simultaneously from multiple processes - locking is not necessary */
12564 	config->availability_diff_ts = ts;
12565 }
12566 
12567 /******************************************************************************
12568  *                                                                            *
12569  * Function: corr_condition_clean                                             *
12570  *                                                                            *
12571  * Purpose: frees correlation condition                                       *
12572  *                                                                            *
12573  * Parameter: condition - [IN] the condition to free                          *
12574  *                                                                            *
12575  ******************************************************************************/
corr_condition_clean(zbx_corr_condition_t * condition)12576 static void	corr_condition_clean(zbx_corr_condition_t *condition)
12577 {
12578 	switch (condition->type)
12579 	{
12580 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
12581 			/* break; is not missing here */
12582 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
12583 			zbx_free(condition->data.tag.tag);
12584 			break;
12585 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
12586 			zbx_free(condition->data.tag_pair.oldtag);
12587 			zbx_free(condition->data.tag_pair.newtag);
12588 			break;
12589 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
12590 			/* break; is not missing here */
12591 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
12592 			zbx_free(condition->data.tag_value.tag);
12593 			zbx_free(condition->data.tag_value.value);
12594 			break;
12595 	}
12596 }
12597 
12598 /******************************************************************************
12599  *                                                                            *
12600  * Function: dc_correlation_free                                              *
12601  *                                                                            *
12602  * Purpose: frees global correlation rule                                     *
12603  *                                                                            *
12604  * Parameter: condition - [IN] the condition to free                          *
12605  *                                                                            *
12606  ******************************************************************************/
dc_correlation_free(zbx_correlation_t * correlation)12607 static void	dc_correlation_free(zbx_correlation_t *correlation)
12608 {
12609 	zbx_free(correlation->name);
12610 	zbx_free(correlation->formula);
12611 
12612 	zbx_vector_ptr_clear_ext(&correlation->operations, zbx_ptr_free);
12613 	zbx_vector_ptr_destroy(&correlation->operations);
12614 	zbx_vector_ptr_destroy(&correlation->conditions);
12615 
12616 	zbx_free(correlation);
12617 }
12618 
12619 /******************************************************************************
12620  *                                                                            *
12621  * Function: dc_corr_condition_copy                                           *
12622  *                                                                            *
12623  * Purpose: copies cached correlation condition to memory                     *
12624  *                                                                            *
12625  * Parameter: dc_condition - [IN] the condition to copy                       *
12626  *            condition    - [OUT] the destination condition                  *
12627  *                                                                            *
12628  * Return value: The cloned correlation condition.                            *
12629  *                                                                            *
12630  ******************************************************************************/
dc_corr_condition_copy(const zbx_dc_corr_condition_t * dc_condition,zbx_corr_condition_t * condition)12631 static void	dc_corr_condition_copy(const zbx_dc_corr_condition_t *dc_condition, zbx_corr_condition_t *condition)
12632 {
12633 	condition->type = dc_condition->type;
12634 
12635 	switch (condition->type)
12636 	{
12637 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
12638 			/* break; is not missing here */
12639 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
12640 			condition->data.tag.tag = zbx_strdup(NULL, dc_condition->data.tag.tag);
12641 			break;
12642 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
12643 			condition->data.tag_pair.oldtag = zbx_strdup(NULL, dc_condition->data.tag_pair.oldtag);
12644 			condition->data.tag_pair.newtag = zbx_strdup(NULL, dc_condition->data.tag_pair.newtag);
12645 			break;
12646 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
12647 			/* break; is not missing here */
12648 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
12649 			condition->data.tag_value.tag = zbx_strdup(NULL, dc_condition->data.tag_value.tag);
12650 			condition->data.tag_value.value = zbx_strdup(NULL, dc_condition->data.tag_value.value);
12651 			condition->data.tag_value.op = dc_condition->data.tag_value.op;
12652 			break;
12653 		case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP:
12654 			condition->data.group.groupid = dc_condition->data.group.groupid;
12655 			condition->data.group.op = dc_condition->data.group.op;
12656 			break;
12657 	}
12658 }
12659 
12660 /******************************************************************************
12661  *                                                                            *
12662  * Function: zbx_dc_corr_operation_dup                                        *
12663  *                                                                            *
12664  * Purpose: clones cached correlation operation to memory                     *
12665  *                                                                            *
12666  * Parameter: operation - [IN] the operation to clone                         *
12667  *                                                                            *
12668  * Return value: The cloned correlation operation.                            *
12669  *                                                                            *
12670  ******************************************************************************/
zbx_dc_corr_operation_dup(const zbx_dc_corr_operation_t * dc_operation)12671 static zbx_corr_operation_t	*zbx_dc_corr_operation_dup(const zbx_dc_corr_operation_t *dc_operation)
12672 {
12673 	zbx_corr_operation_t	*operation;
12674 
12675 	operation = (zbx_corr_operation_t *)zbx_malloc(NULL, sizeof(zbx_corr_operation_t));
12676 	operation->type = dc_operation->type;
12677 
12678 	return operation;
12679 }
12680 
12681 /******************************************************************************
12682  *                                                                            *
12683  * Function: dc_correlation_formula_dup                                       *
12684  *                                                                            *
12685  * Purpose: clones cached correlation formula, generating it if necessary     *
12686  *                                                                            *
12687  * Parameter: correlation - [IN] the correlation                              *
12688  *                                                                            *
12689  * Return value: The cloned correlation formula.                              *
12690  *                                                                            *
12691  ******************************************************************************/
dc_correlation_formula_dup(const zbx_dc_correlation_t * dc_correlation)12692 static char	*dc_correlation_formula_dup(const zbx_dc_correlation_t *dc_correlation)
12693 {
12694 #define ZBX_OPERATION_TYPE_UNKNOWN	0
12695 #define ZBX_OPERATION_TYPE_OR		1
12696 #define ZBX_OPERATION_TYPE_AND		2
12697 
12698 	char				*formula = NULL;
12699 	const char			*op = NULL;
12700 	size_t				formula_alloc = 0, formula_offset = 0;
12701 	int				i, last_type = -1, last_op = ZBX_OPERATION_TYPE_UNKNOWN;
12702 	const zbx_dc_corr_condition_t	*dc_condition;
12703 	zbx_uint64_t			last_id;
12704 
12705 	if (CONDITION_EVAL_TYPE_EXPRESSION == dc_correlation->evaltype || 0 == dc_correlation->conditions.values_num)
12706 		return zbx_strdup(NULL, dc_correlation->formula);
12707 
12708 	dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[0];
12709 
12710 	switch (dc_correlation->evaltype)
12711 	{
12712 		case CONDITION_EVAL_TYPE_OR:
12713 			op = " or";
12714 			break;
12715 		case CONDITION_EVAL_TYPE_AND:
12716 			op = " and";
12717 			break;
12718 	}
12719 
12720 	if (NULL != op)
12721 	{
12722 		zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "}",
12723 				dc_condition->corr_conditionid);
12724 
12725 		for (i = 1; i < dc_correlation->conditions.values_num; i++)
12726 		{
12727 			dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[i];
12728 
12729 			zbx_strcpy_alloc(&formula, &formula_alloc, &formula_offset, op);
12730 			zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, " {" ZBX_FS_UI64 "}",
12731 					dc_condition->corr_conditionid);
12732 		}
12733 
12734 		return formula;
12735 	}
12736 
12737 	last_id = dc_condition->corr_conditionid;
12738 	last_type = dc_condition->type;
12739 
12740 	for (i = 1; i < dc_correlation->conditions.values_num; i++)
12741 	{
12742 		dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[i];
12743 
12744 		if (last_type == dc_condition->type)
12745 		{
12746 			if (last_op != ZBX_OPERATION_TYPE_OR)
12747 				zbx_chrcpy_alloc(&formula, &formula_alloc, &formula_offset, '(');
12748 
12749 			zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "} or ", last_id);
12750 			last_op = ZBX_OPERATION_TYPE_OR;
12751 		}
12752 		else
12753 		{
12754 			zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "}", last_id);
12755 
12756 			if (last_op == ZBX_OPERATION_TYPE_OR)
12757 				zbx_chrcpy_alloc(&formula, &formula_alloc, &formula_offset, ')');
12758 
12759 			zbx_strcpy_alloc(&formula, &formula_alloc, &formula_offset, " and ");
12760 
12761 			last_op = ZBX_OPERATION_TYPE_AND;
12762 		}
12763 
12764 		last_type = dc_condition->type;
12765 		last_id = dc_condition->corr_conditionid;
12766 	}
12767 
12768 	zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "}", last_id);
12769 
12770 	if (last_op == ZBX_OPERATION_TYPE_OR)
12771 		zbx_chrcpy_alloc(&formula, &formula_alloc, &formula_offset, ')');
12772 
12773 	return formula;
12774 
12775 #undef ZBX_OPERATION_TYPE_UNKNOWN
12776 #undef ZBX_OPERATION_TYPE_OR
12777 #undef ZBX_OPERATION_TYPE_AND
12778 }
12779 
zbx_dc_correlation_rules_init(zbx_correlation_rules_t * rules)12780 void	zbx_dc_correlation_rules_init(zbx_correlation_rules_t *rules)
12781 {
12782 	zbx_vector_ptr_create(&rules->correlations);
12783 	zbx_hashset_create_ext(&rules->conditions, 0, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC,
12784 			(zbx_clean_func_t)corr_condition_clean, ZBX_DEFAULT_MEM_MALLOC_FUNC,
12785 			ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
12786 
12787 	rules->sync_ts = 0;
12788 }
12789 
zbx_dc_correlation_rules_clean(zbx_correlation_rules_t * rules)12790 void	zbx_dc_correlation_rules_clean(zbx_correlation_rules_t *rules)
12791 {
12792 	zbx_vector_ptr_clear_ext(&rules->correlations, (zbx_clean_func_t)dc_correlation_free);
12793 	zbx_hashset_clear(&rules->conditions);
12794 }
12795 
zbx_dc_correlation_rules_free(zbx_correlation_rules_t * rules)12796 void	zbx_dc_correlation_rules_free(zbx_correlation_rules_t *rules)
12797 {
12798 	zbx_dc_correlation_rules_clean(rules);
12799 	zbx_vector_ptr_destroy(&rules->correlations);
12800 	zbx_hashset_destroy(&rules->conditions);
12801 }
12802 
12803 /******************************************************************************
12804  *                                                                            *
12805  * Function: zbx_dc_correlation_get_rules                                     *
12806  *                                                                            *
12807  * Purpose: gets correlation rules from configuration cache                   *
12808  *                                                                            *
12809  * Parameter: rules   - [IN/OUT] the correlation rules                        *
12810  *                                                                            *
12811  ******************************************************************************/
zbx_dc_correlation_rules_get(zbx_correlation_rules_t * rules)12812 void	zbx_dc_correlation_rules_get(zbx_correlation_rules_t *rules)
12813 {
12814 	int				i;
12815 	zbx_hashset_iter_t		iter;
12816 	const zbx_dc_correlation_t	*dc_correlation;
12817 	const zbx_dc_corr_condition_t	*dc_condition;
12818 	zbx_correlation_t		*correlation;
12819 	zbx_corr_condition_t		*condition, condition_local;
12820 
12821 	RDLOCK_CACHE;
12822 
12823 	/* The correlation rules are refreshed only if the sync timestamp   */
12824 	/* does not match current configuration cache sync timestamp. This  */
12825 	/* allows to locally cache the correlation rules.                   */
12826 	if (config->sync_ts == rules->sync_ts)
12827 	{
12828 		UNLOCK_CACHE;
12829 		return;
12830 	}
12831 
12832 	zbx_dc_correlation_rules_clean(rules);
12833 
12834 	zbx_hashset_iter_reset(&config->correlations, &iter);
12835 	while (NULL != (dc_correlation = (const zbx_dc_correlation_t *)zbx_hashset_iter_next(&iter)))
12836 	{
12837 		correlation = (zbx_correlation_t *)zbx_malloc(NULL, sizeof(zbx_correlation_t));
12838 		correlation->correlationid = dc_correlation->correlationid;
12839 		correlation->evaltype = dc_correlation->evaltype;
12840 		correlation->name = zbx_strdup(NULL, dc_correlation->name);
12841 		correlation->formula = dc_correlation_formula_dup(dc_correlation);
12842 		zbx_vector_ptr_create(&correlation->conditions);
12843 		zbx_vector_ptr_create(&correlation->operations);
12844 
12845 		for (i = 0; i < dc_correlation->conditions.values_num; i++)
12846 		{
12847 			dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[i];
12848 			condition_local.corr_conditionid = dc_condition->corr_conditionid;
12849 			condition = (zbx_corr_condition_t *)zbx_hashset_insert(&rules->conditions, &condition_local, sizeof(condition_local));
12850 			dc_corr_condition_copy(dc_condition, condition);
12851 			zbx_vector_ptr_append(&correlation->conditions, condition);
12852 		}
12853 
12854 		for (i = 0; i < dc_correlation->operations.values_num; i++)
12855 		{
12856 			zbx_vector_ptr_append(&correlation->operations,
12857 					zbx_dc_corr_operation_dup((const zbx_dc_corr_operation_t *)dc_correlation->operations.values[i]));
12858 		}
12859 
12860 		zbx_vector_ptr_append(&rules->correlations, correlation);
12861 	}
12862 
12863 	rules->sync_ts = config->sync_ts;
12864 
12865 	UNLOCK_CACHE;
12866 
12867 	zbx_vector_ptr_sort(&rules->correlations, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
12868 }
12869 
12870 /******************************************************************************
12871  *                                                                            *
12872  * Function: dc_hostgroup_cache_nested_groupids                               *
12873  *                                                                            *
12874  * Purpose: cache nested group identifiers                                    *
12875  *                                                                            *
12876  ******************************************************************************/
dc_hostgroup_cache_nested_groupids(zbx_dc_hostgroup_t * parent_group)12877 void	dc_hostgroup_cache_nested_groupids(zbx_dc_hostgroup_t *parent_group)
12878 {
12879 	zbx_dc_hostgroup_t	*group;
12880 
12881 	if (0 == (parent_group->flags & ZBX_DC_HOSTGROUP_FLAGS_NESTED_GROUPIDS))
12882 	{
12883 		int	index, len;
12884 
12885 		zbx_vector_uint64_create_ext(&parent_group->nested_groupids, __config_mem_malloc_func,
12886 				__config_mem_realloc_func, __config_mem_free_func);
12887 
12888 		index = zbx_vector_ptr_bsearch(&config->hostgroups_name, parent_group, dc_compare_hgroups);
12889 		len = strlen(parent_group->name);
12890 
12891 		while (++index < config->hostgroups_name.values_num)
12892 		{
12893 			group = (zbx_dc_hostgroup_t *)config->hostgroups_name.values[index];
12894 
12895 			if (0 != strncmp(group->name, parent_group->name, len))
12896 				break;
12897 
12898 			if ('\0' == group->name[len] || '/' == group->name[len])
12899 				zbx_vector_uint64_append(&parent_group->nested_groupids, group->groupid);
12900 		}
12901 
12902 		parent_group->flags |= ZBX_DC_HOSTGROUP_FLAGS_NESTED_GROUPIDS;
12903 	}
12904 }
12905 
12906 /******************************************************************************
12907  *                                                                            *
12908  * Function: dc_maintenance_precache_nested_groups                            *
12909  *                                                                            *
12910  * Purpose: pre-caches nested groups for groups used in running maintenances  *
12911  *                                                                            *
12912  ******************************************************************************/
dc_maintenance_precache_nested_groups(void)12913 static void	dc_maintenance_precache_nested_groups(void)
12914 {
12915 	zbx_hashset_iter_t	iter;
12916 	zbx_dc_maintenance_t	*maintenance;
12917 	zbx_vector_uint64_t	groupids;
12918 	int			i;
12919 	zbx_dc_hostgroup_t	*group;
12920 
12921 	if (0 == config->maintenances.num_data)
12922 		return;
12923 
12924 	zbx_vector_uint64_create(&groupids);
12925 	zbx_hashset_iter_reset(&config->maintenances, &iter);
12926 	while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter)))
12927 	{
12928 		if (ZBX_MAINTENANCE_RUNNING != maintenance->state)
12929 			continue;
12930 
12931 		zbx_vector_uint64_append_array(&groupids, maintenance->groupids.values,
12932 				maintenance->groupids.values_num);
12933 	}
12934 
12935 	zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
12936 	zbx_vector_uint64_uniq(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
12937 
12938 	for (i = 0; i < groupids.values_num; i++)
12939 	{
12940 		if (NULL != (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups,
12941 				&groupids.values[i])))
12942 		{
12943 			dc_hostgroup_cache_nested_groupids(group);
12944 		}
12945 	}
12946 
12947 	zbx_vector_uint64_destroy(&groupids);
12948 }
12949 
12950 /******************************************************************************
12951  *                                                                            *
12952  * Function: dc_get_nested_hostgroupids                                       *
12953  *                                                                            *
12954  * Purpose: gets nested group ids for the specified host group                *
12955  *          (including the target group id)                                   *
12956  *                                                                            *
12957  * Parameter: groupid         - [IN] the parent group identifier              *
12958  *            nested_groupids - [OUT] the nested + parent group ids           *
12959  *                                                                            *
12960  ******************************************************************************/
dc_get_nested_hostgroupids(zbx_uint64_t groupid,zbx_vector_uint64_t * nested_groupids)12961 void	dc_get_nested_hostgroupids(zbx_uint64_t groupid, zbx_vector_uint64_t *nested_groupids)
12962 {
12963 	zbx_dc_hostgroup_t	*parent_group;
12964 
12965 	zbx_vector_uint64_append(nested_groupids, groupid);
12966 
12967 	/* The target group id will not be found in the configuration cache if target group was removed */
12968 	/* between call to this function and the configuration cache look-up below. The target group id */
12969 	/* is nevertheless returned so that the SELECT statements of the callers work even if no group  */
12970 	/* was found.                                                                                   */
12971 
12972 	if (NULL != (parent_group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &groupid)))
12973 	{
12974 		dc_hostgroup_cache_nested_groupids(parent_group);
12975 
12976 		if (0 != parent_group->nested_groupids.values_num)
12977 		{
12978 			zbx_vector_uint64_append_array(nested_groupids, parent_group->nested_groupids.values,
12979 					parent_group->nested_groupids.values_num);
12980 		}
12981 	}
12982 }
12983 
12984 /******************************************************************************
12985  *                                                                            *
12986  * Function: zbx_dc_get_nested_hostgroupids                                   *
12987  *                                                                            *
12988  * Purpose: gets nested group ids for the specified host groups               *
12989  *                                                                            *
12990  * Parameter: groupids        - [IN] the parent group identifiers             *
12991  *            groupids_num    - [IN] the number of parent groups              *
12992  *            nested_groupids - [OUT] the nested + parent group ids           *
12993  *                                                                            *
12994  ******************************************************************************/
zbx_dc_get_nested_hostgroupids(zbx_uint64_t * groupids,int groupids_num,zbx_vector_uint64_t * nested_groupids)12995 void	zbx_dc_get_nested_hostgroupids(zbx_uint64_t *groupids, int groupids_num, zbx_vector_uint64_t *nested_groupids)
12996 {
12997 	int	i;
12998 
12999 	WRLOCK_CACHE;
13000 
13001 	for (i = 0; i < groupids_num; i++)
13002 		dc_get_nested_hostgroupids(groupids[i], nested_groupids);
13003 
13004 	UNLOCK_CACHE;
13005 
13006 	zbx_vector_uint64_sort(nested_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13007 	zbx_vector_uint64_uniq(nested_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13008 }
13009 
13010 /******************************************************************************
13011  *                                                                            *
13012  * Function: zbx_dc_get_hostids_by_group_name                                 *
13013  *                                                                            *
13014  * Purpose: gets hostids belonging to the group and its nested groups         *
13015  *                                                                            *
13016  * Parameter: name    - [IN] the group name                                   *
13017  *            hostids - [OUT] the hostids                                     *
13018  *                                                                            *
13019  ******************************************************************************/
zbx_dc_get_hostids_by_group_name(const char * name,zbx_vector_uint64_t * hostids)13020 void	zbx_dc_get_hostids_by_group_name(const char *name, zbx_vector_uint64_t *hostids)
13021 {
13022 	int			i;
13023 	zbx_vector_uint64_t	groupids;
13024 	zbx_dc_hostgroup_t	group_local, *group;
13025 
13026 	zbx_vector_uint64_create(&groupids);
13027 
13028 	group_local.name = name;
13029 
13030 	WRLOCK_CACHE;
13031 
13032 	if (FAIL != (i = zbx_vector_ptr_bsearch(&config->hostgroups_name, &group_local, dc_compare_hgroups)))
13033 	{
13034 		group = (zbx_dc_hostgroup_t *)config->hostgroups_name.values[i];
13035 		dc_get_nested_hostgroupids(group->groupid, &groupids);
13036 	}
13037 
13038 	UNLOCK_CACHE;
13039 
13040 	zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13041 	zbx_vector_uint64_uniq(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13042 
13043 	RDLOCK_CACHE;
13044 
13045 	for (i = 0; i < groupids.values_num; i++)
13046 	{
13047 		zbx_hashset_iter_t	iter;
13048 		zbx_uint64_t		*phostid;
13049 
13050 		if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups,
13051 				&groupids.values[i])))
13052 		{
13053 			continue;
13054 		}
13055 
13056 		zbx_hashset_iter_reset(&group->hostids, &iter);
13057 
13058 		while (NULL != (phostid = (zbx_uint64_t *)zbx_hashset_iter_next(&iter)))
13059 			zbx_vector_uint64_append(hostids, *phostid);
13060 	}
13061 
13062 	UNLOCK_CACHE;
13063 
13064 	zbx_vector_uint64_destroy(&groupids);
13065 
13066 	zbx_vector_uint64_sort(hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13067 	zbx_vector_uint64_uniq(hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13068 }
13069 
13070 /******************************************************************************
13071  *                                                                            *
13072  * Function: zbx_dc_get_active_proxy_by_name                                  *
13073  *                                                                            *
13074  * Purpose: gets active proxy data by its name from configuration cache       *
13075  *                                                                            *
13076  * Parameters:                                                                *
13077  *     name  - [IN] the proxy name                                            *
13078  *     proxy - [OUT] the proxy data                                           *
13079  *     error - [OUT] error message                                            *
13080  *                                                                            *
13081  * Return value:                                                              *
13082  *     SUCCEED - proxy data were retrieved successfully                       *
13083  *     FAIL    - failed to retrieve proxy data, error message is set          *
13084  *                                                                            *
13085  ******************************************************************************/
zbx_dc_get_active_proxy_by_name(const char * name,DC_PROXY * proxy,char ** error)13086 int	zbx_dc_get_active_proxy_by_name(const char *name, DC_PROXY *proxy, char **error)
13087 {
13088 	int			ret = FAIL;
13089 	const ZBX_DC_HOST	*dc_host;
13090 	const ZBX_DC_PROXY	*dc_proxy;
13091 
13092 	RDLOCK_CACHE;
13093 
13094 	if (NULL == (dc_host = DCfind_proxy(name)))
13095 	{
13096 		*error = zbx_dsprintf(*error, "proxy \"%s\" not found", name);
13097 		goto out;
13098 	}
13099 
13100 	if (HOST_STATUS_PROXY_ACTIVE != dc_host->status)
13101 	{
13102 		*error = zbx_dsprintf(*error, "proxy \"%s\" is configured for passive mode", name);
13103 		goto out;
13104 	}
13105 
13106 	if (NULL == (dc_proxy = (const ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->hostid)))
13107 	{
13108 		*error = zbx_dsprintf(*error, "proxy \"%s\" not found in configuration cache", name);
13109 		goto out;
13110 	}
13111 
13112 	DCget_proxy(proxy, dc_proxy);
13113 	ret = SUCCEED;
13114 out:
13115 	UNLOCK_CACHE;
13116 
13117 	return ret;
13118 }
13119 
13120 /******************************************************************************
13121  *                                                                            *
13122  * Function: zbx_dc_items_update_nextcheck                                    *
13123  *                                                                            *
13124  * Purpose: updates item nextcheck values in configuration cache              *
13125  *                                                                            *
13126  * Parameters: items      - [IN] the items to update                          *
13127  *             values     - [IN] the items values containing new properties   *
13128  *             errcodes   - [IN] item error codes. Update only items with     *
13129  *                               SUCCEED code                                 *
13130  *             values_num - [IN] the number of elements in items,values and   *
13131  *                               errcodes arrays                              *
13132  *                                                                            *
13133  ******************************************************************************/
zbx_dc_items_update_nextcheck(DC_ITEM * items,zbx_agent_value_t * values,int * errcodes,size_t values_num)13134 void	zbx_dc_items_update_nextcheck(DC_ITEM *items, zbx_agent_value_t *values, int *errcodes, size_t values_num)
13135 {
13136 	size_t			i;
13137 	ZBX_DC_ITEM		*dc_item;
13138 	ZBX_DC_HOST		*dc_host;
13139 	ZBX_DC_INTERFACE	*dc_interface;
13140 
13141 	RDLOCK_CACHE;
13142 
13143 	for (i = 0; i < values_num; i++)
13144 	{
13145 		if (FAIL == errcodes[i])
13146 			continue;
13147 
13148 		/* update nextcheck for items that are counted in queue for monitoring purposes */
13149 		if (FAIL == zbx_is_counted_in_item_queue(items[i].type, items[i].key_orig))
13150 			continue;
13151 
13152 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &items[i].itemid)))
13153 			continue;
13154 
13155 		if (ITEM_STATUS_ACTIVE != dc_item->status)
13156 			continue;
13157 
13158 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
13159 			continue;
13160 
13161 		if (HOST_STATUS_MONITORED != dc_host->status)
13162 			continue;
13163 
13164 		if (ZBX_LOC_NOWHERE != dc_item->location)
13165 			continue;
13166 
13167 		dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &dc_item->interfaceid);
13168 
13169 		/* update nextcheck for items that are counted in queue for monitoring purposes */
13170 		DCitem_nextcheck_update(dc_item, dc_interface, ZBX_ITEM_COLLECTED, values[i].ts.sec,
13171 				NULL);
13172 	}
13173 
13174 	UNLOCK_CACHE;
13175 }
13176 
13177 /******************************************************************************
13178  *                                                                            *
13179  * Function: zbx_dc_get_host_interfaces                                       *
13180  *                                                                            *
13181  * Purpose: get data of all network interfaces for a host in configuration    *
13182  *          cache                                                             *
13183  *                                                                            *
13184  * Parameter: hostid     - [IN] the host identifier                           *
13185  *            interfaces - [OUT] array with interface data                    *
13186  *            n          - [OUT] number of allocated 'interfaces' elements    *
13187  *                                                                            *
13188  * Return value: SUCCEED - interface data retrieved successfully              *
13189  *               FAIL    - host not found                                     *
13190  *                                                                            *
13191  * Comments: if host is found but has no interfaces (should not happen) this  *
13192  *           function sets 'n' to 0 and no memory is allocated for            *
13193  *           'interfaces'. It is a caller responsibility to deallocate        *
13194  *           memory of 'interfaces' and its components.                       *
13195  *                                                                            *
13196  ******************************************************************************/
zbx_dc_get_host_interfaces(zbx_uint64_t hostid,DC_INTERFACE2 ** interfaces,int * n)13197 int	zbx_dc_get_host_interfaces(zbx_uint64_t hostid, DC_INTERFACE2 **interfaces, int *n)
13198 {
13199 	const ZBX_DC_HOST	*host;
13200 	int			i, ret = FAIL;
13201 
13202 	if (0 == hostid)
13203 		return FAIL;
13204 
13205 	RDLOCK_CACHE;
13206 
13207 	/* find host entry in 'config->hosts' hashset */
13208 
13209 	if (NULL == (host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
13210 		goto unlock;
13211 
13212 	/* allocate memory for results */
13213 
13214 	if (0 < (*n = host->interfaces_v.values_num))
13215 		*interfaces = (DC_INTERFACE2 *)zbx_malloc(NULL, sizeof(DC_INTERFACE2) * (size_t)*n);
13216 
13217 	/* copy data about all host interfaces */
13218 
13219 	for (i = 0; i < *n; i++)
13220 	{
13221 		const ZBX_DC_INTERFACE	*src = (const ZBX_DC_INTERFACE *)host->interfaces_v.values[i];
13222 		DC_INTERFACE2		*dst = *interfaces + i;
13223 
13224 		dst->interfaceid = src->interfaceid;
13225 		dst->type = src->type;
13226 		dst->main = src->main;
13227 		dst->useip = src->useip;
13228 		strscpy(dst->ip_orig, src->ip);
13229 		strscpy(dst->dns_orig, src->dns);
13230 		strscpy(dst->port_orig, src->port);
13231 		dst->addr = (1 == src->useip ? dst->ip_orig : dst->dns_orig);
13232 
13233 		if (INTERFACE_TYPE_SNMP == dst->type)
13234 		{
13235 			ZBX_DC_SNMPINTERFACE *snmp;
13236 
13237 			if (NULL == (snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp,
13238 					&dst->interfaceid)))
13239 			{
13240 				zbx_free(*interfaces);
13241 				goto unlock;
13242 			}
13243 
13244 			dst->bulk = snmp->bulk;
13245 			dst->snmp_version= snmp->version;
13246 		}
13247 	}
13248 
13249 	ret = SUCCEED;
13250 unlock:
13251 	UNLOCK_CACHE;
13252 
13253 	return ret;
13254 }
13255 
13256 /******************************************************************************
13257  *                                                                            *
13258  * Function: DCconfig_items_apply_changes                                     *
13259  *                                                                            *
13260  * Purpose: apply item state, error, mtime, lastlogsize changes to            *
13261  *          configuration cache                                               *
13262  *                                                                            *
13263  ******************************************************************************/
DCconfig_items_apply_changes(const zbx_vector_ptr_t * item_diff)13264 void	DCconfig_items_apply_changes(const zbx_vector_ptr_t *item_diff)
13265 {
13266 	int			i;
13267 	const zbx_item_diff_t	*diff;
13268 	ZBX_DC_ITEM		*dc_item;
13269 
13270 	if (0 == item_diff->values_num)
13271 		return;
13272 
13273 	WRLOCK_CACHE;
13274 
13275 	for (i = 0; i < item_diff->values_num; i++)
13276 	{
13277 		diff = (const zbx_item_diff_t *)item_diff->values[i];
13278 
13279 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &diff->itemid)))
13280 			continue;
13281 
13282 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_LASTLOGSIZE & diff->flags))
13283 			dc_item->lastlogsize = diff->lastlogsize;
13284 
13285 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_MTIME & diff->flags))
13286 			dc_item->mtime = diff->mtime;
13287 
13288 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_ERROR & diff->flags))
13289 			DCstrpool_replace(1, &dc_item->error, diff->error);
13290 
13291 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_STATE & diff->flags))
13292 			dc_item->state = diff->state;
13293 	}
13294 
13295 	UNLOCK_CACHE;
13296 }
13297 
13298 /******************************************************************************
13299  *                                                                            *
13300  * Function: DCconfig_update_inventory_values                                 *
13301  *                                                                            *
13302  * Purpose: update automatic inventory in configuration cache                 *
13303  *                                                                            *
13304  ******************************************************************************/
DCconfig_update_inventory_values(const zbx_vector_ptr_t * inventory_values)13305 void	DCconfig_update_inventory_values(const zbx_vector_ptr_t *inventory_values)
13306 {
13307 	ZBX_DC_HOST_INVENTORY	*host_inventory = NULL;
13308 	int			i;
13309 
13310 	WRLOCK_CACHE;
13311 
13312 	for (i = 0; i < inventory_values->values_num; i++)
13313 	{
13314 		const zbx_inventory_value_t	*inventory_value = (zbx_inventory_value_t *)inventory_values->values[i];
13315 		const char			**value;
13316 
13317 		if (NULL == host_inventory || inventory_value->hostid != host_inventory->hostid)
13318 		{
13319 			host_inventory = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories_auto, &inventory_value->hostid);
13320 
13321 			if (NULL == host_inventory)
13322 				continue;
13323 		}
13324 
13325 		value = &host_inventory->values[inventory_value->idx];
13326 
13327 		DCstrpool_replace((NULL != *value ? 1 : 0), value, inventory_value->value);
13328 	}
13329 
13330 	UNLOCK_CACHE;
13331 }
13332 
13333 /******************************************************************************
13334  *                                                                            *
13335  * Function: dc_get_host_inventory_value_by_hostid                            *
13336  *                                                                            *
13337  * Purpose: find inventory value in automatically populated cache, if not     *
13338  *          found then look in main inventory cache                           *
13339  *                                                                            *
13340  * Comments: This function must be called inside configuration cache read     *
13341  *           (or write) lock.                                                 *
13342  *                                                                            *
13343  ******************************************************************************/
dc_get_host_inventory_value_by_hostid(zbx_uint64_t hostid,char ** replace_to,int value_idx)13344 static int	dc_get_host_inventory_value_by_hostid(zbx_uint64_t hostid, char **replace_to, int value_idx)
13345 {
13346 	const ZBX_DC_HOST_INVENTORY	*dc_inventory;
13347 
13348 	if (NULL != (dc_inventory = (const ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories_auto,
13349 			&hostid)) && NULL != dc_inventory->values[value_idx])
13350 	{
13351 		*replace_to = zbx_strdup(*replace_to, dc_inventory->values[value_idx]);
13352 		return SUCCEED;
13353 	}
13354 
13355 	if (NULL != (dc_inventory = (const ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories,
13356 			&hostid)))
13357 	{
13358 		*replace_to = zbx_strdup(*replace_to, dc_inventory->values[value_idx]);
13359 		return SUCCEED;
13360 	}
13361 
13362 	return FAIL;
13363 }
13364 
13365 /******************************************************************************
13366  *                                                                            *
13367  * Function: DCget_host_inventory_value_by_itemid                             *
13368  *                                                                            *
13369  * Purpose: find inventory value in automatically populated cache, if not     *
13370  *          found then look in main inventory cache                           *
13371  *                                                                            *
13372  ******************************************************************************/
DCget_host_inventory_value_by_itemid(zbx_uint64_t itemid,char ** replace_to,int value_idx)13373 int	DCget_host_inventory_value_by_itemid(zbx_uint64_t itemid, char **replace_to, int value_idx)
13374 {
13375 	const ZBX_DC_ITEM	*dc_item;
13376 	int			ret = FAIL;
13377 
13378 	RDLOCK_CACHE;
13379 
13380 	if (NULL != (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
13381 		ret = dc_get_host_inventory_value_by_hostid(dc_item->hostid, replace_to, value_idx);
13382 
13383 	UNLOCK_CACHE;
13384 
13385 	return ret;
13386 }
13387 
13388 /******************************************************************************
13389  *                                                                            *
13390  * Function: DCget_host_inventory_value_by_hostid                             *
13391  *                                                                            *
13392  * Purpose: find inventory value in automatically populated cache, if not     *
13393  *          found then look in main inventory cache                           *
13394  *                                                                            *
13395  ******************************************************************************/
DCget_host_inventory_value_by_hostid(zbx_uint64_t hostid,char ** replace_to,int value_idx)13396 int	DCget_host_inventory_value_by_hostid(zbx_uint64_t hostid, char **replace_to, int value_idx)
13397 {
13398 	int	ret;
13399 
13400 	RDLOCK_CACHE;
13401 
13402 	ret = dc_get_host_inventory_value_by_hostid(hostid, replace_to, value_idx);
13403 
13404 	UNLOCK_CACHE;
13405 
13406 	return ret;
13407 }
13408 
13409 /******************************************************************************
13410  *                                                                            *
13411  * Function: zbx_dc_get_trigger_dependencies                                  *
13412  *                                                                            *
13413  * Purpose: checks/returns trigger dependencies for a set of triggers         *
13414  *                                                                            *
13415  * Parameter: triggerids  - [IN] the currently processing trigger ids         *
13416  *            deps        - [OUT] list of dependency check results for failed *
13417  *                                or unresolved dependencies                  *
13418  *                                                                            *
13419  * Comments: This function returns list of zbx_trigger_dep_t structures       *
13420  *           for failed or unresolved dependency checks.                      *
13421  *           Dependency check is failed if any of the master triggers that    *
13422  *           are not being processed in this batch (present in triggerids     *
13423  *           vector) has a problem value.                                     *
13424  *           Dependency check is unresolved if a master trigger is being      *
13425  *           processed in this batch (present in triggerids vector) and no    *
13426  *           other master triggers have problem value.                        *
13427  *           Dependency check is successful if all master triggers (if any)   *
13428  *           have OK value and are not being processed in this batch.         *
13429  *                                                                            *
13430  ******************************************************************************/
zbx_dc_get_trigger_dependencies(const zbx_vector_uint64_t * triggerids,zbx_vector_ptr_t * deps)13431 void	zbx_dc_get_trigger_dependencies(const zbx_vector_uint64_t *triggerids, zbx_vector_ptr_t *deps)
13432 {
13433 	int				i, ret;
13434 	const ZBX_DC_TRIGGER_DEPLIST	*trigdep;
13435 	zbx_vector_uint64_t		masterids;
13436 	zbx_trigger_dep_t		*dep;
13437 
13438 	zbx_vector_uint64_create(&masterids);
13439 	zbx_vector_uint64_reserve(&masterids, 64);
13440 
13441 	RDLOCK_CACHE;
13442 
13443 	for (i = 0; i < triggerids->values_num; i++)
13444 	{
13445 		if (NULL == (trigdep = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps, &triggerids->values[i])))
13446 			continue;
13447 
13448 		if (FAIL == (ret = DCconfig_check_trigger_dependencies_rec(trigdep, 0, triggerids, &masterids)) ||
13449 				0 != masterids.values_num)
13450 		{
13451 			dep = (zbx_trigger_dep_t *)zbx_malloc(NULL, sizeof(zbx_trigger_dep_t));
13452 			dep->triggerid = triggerids->values[i];
13453 			zbx_vector_uint64_create(&dep->masterids);
13454 
13455 			if (SUCCEED == ret)
13456 			{
13457 				dep->status = ZBX_TRIGGER_DEPENDENCY_UNRESOLVED;
13458 				zbx_vector_uint64_append_array(&dep->masterids, masterids.values, masterids.values_num);
13459 			}
13460 			else
13461 				dep->status = ZBX_TRIGGER_DEPENDENCY_FAIL;
13462 
13463 			zbx_vector_ptr_append(deps, dep);
13464 		}
13465 
13466 		zbx_vector_uint64_clear(&masterids);
13467 	}
13468 
13469 	UNLOCK_CACHE;
13470 
13471 	zbx_vector_uint64_destroy(&masterids);
13472 }
13473 
13474 /******************************************************************************
13475  *                                                                            *
13476  * Function: zbx_dc_reschedule_items                                          *
13477  *                                                                            *
13478  * Purpose: reschedules items that are processed by the target daemon         *
13479  *                                                                            *
13480  * Parameter: itemids       - [IN] the item identifiers                       *
13481  *            nextcheck     - [IN] the schedueld time                         *
13482  *            proxy_hostids - [OUT] the proxy_hostids of the given itemids    *
13483  *                                  (optional, can be NULL)                   *
13484  *                                                                            *
13485  * Comments: On server this function reschedules items monitored by server.   *
13486  *           On proxy only items monitored by the proxy is accessible, so     *
13487  *           all items can be safely rescheduled.                             *
13488  *                                                                            *
13489  ******************************************************************************/
zbx_dc_reschedule_items(const zbx_vector_uint64_t * itemids,int nextcheck,zbx_uint64_t * proxy_hostids)13490 void	zbx_dc_reschedule_items(const zbx_vector_uint64_t *itemids, int nextcheck, zbx_uint64_t *proxy_hostids)
13491 {
13492 	int		i;
13493 	ZBX_DC_ITEM	*dc_item;
13494 	ZBX_DC_HOST	*dc_host;
13495 	zbx_uint64_t	proxy_hostid;
13496 
13497 	WRLOCK_CACHE;
13498 
13499 	for (i = 0; i < itemids->values_num; i++)
13500 	{
13501 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids->values[i])) ||
13502 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
13503 		{
13504 			zabbix_log(LOG_LEVEL_WARNING, "cannot perform check now for itemid [" ZBX_FS_UI64 "]"
13505 					": item is not in cache", itemids->values[i]);
13506 
13507 			proxy_hostid = 0;
13508 		}
13509 		else if (0 == dc_item->schedulable)
13510 		{
13511 			zabbix_log(LOG_LEVEL_WARNING, "cannot perform check now for item \"%s\" on host \"%s\""
13512 					": item configuration error", dc_item->key, dc_host->host);
13513 
13514 			proxy_hostid = 0;
13515 		}
13516 		else if (0 == (proxy_hostid = dc_host->proxy_hostid) ||
13517 				SUCCEED == is_item_processed_by_server(dc_item->type, dc_item->key))
13518 		{
13519 			dc_requeue_item_at(dc_item, dc_host, nextcheck);
13520 			proxy_hostid = 0;
13521 		}
13522 
13523 		if (NULL != proxy_hostids)
13524 			proxy_hostids[i] = proxy_hostid;
13525 	}
13526 
13527 	UNLOCK_CACHE;
13528 }
13529 
13530 /******************************************************************************
13531  *                                                                            *
13532  * Function: zbx_dc_proxy_update_nodata                                       *
13533  *                                                                            *
13534  * Purpose: stop suppress mode of the nodata() trigger                        *
13535  *                                                                            *
13536  * Parameter: subscriptions - [IN] the array of trigger id and time of values *
13537  *                                                                            *
13538  ******************************************************************************/
zbx_dc_proxy_update_nodata(zbx_vector_uint64_pair_t * subscriptions)13539 void	zbx_dc_proxy_update_nodata(zbx_vector_uint64_pair_t *subscriptions)
13540 {
13541 	ZBX_DC_PROXY		*proxy = NULL;
13542 	int			i;
13543 	zbx_uint64_pair_t	p;
13544 
13545 	WRLOCK_CACHE;
13546 
13547 	for (i = 0; i < subscriptions->values_num; i++)
13548 	{
13549 		p = subscriptions->values[i];
13550 
13551 		if ((NULL == proxy || p.first != proxy->hostid) &&
13552 				NULL == (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &p.first)))
13553 		{
13554 			continue;
13555 		}
13556 
13557 		if (0 == (proxy->nodata_win.flags & ZBX_PROXY_SUPPRESS_ACTIVE))
13558 			continue;
13559 
13560 		if (0 != (proxy->nodata_win.flags & ZBX_PROXY_SUPPRESS_MORE) &&
13561 				(int)p.second > proxy->nodata_win.period_end)
13562 		{
13563 			continue;
13564 		}
13565 
13566 		proxy->nodata_win.values_num --;
13567 
13568 		if (0 < proxy->nodata_win.values_num || 0 != (proxy->nodata_win.flags & ZBX_PROXY_SUPPRESS_MORE))
13569 			continue;
13570 
13571 		proxy->nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
13572 		proxy->nodata_win.period_end = 0;
13573 		proxy->nodata_win.values_num = 0;
13574 	}
13575 
13576 	UNLOCK_CACHE;
13577 }
13578 
13579 /******************************************************************************
13580  *                                                                            *
13581  * Function: zbx_dc_update_proxy                                              *
13582  *                                                                            *
13583  * Purpose: updates changed proxy data in configuration cache and updates     *
13584  *          diff flags to reflect the updated data                            *
13585  *                                                                            *
13586  * Parameter: diff - [IN/OUT] the properties to update                        *
13587  *                                                                            *
13588  ******************************************************************************/
zbx_dc_update_proxy(zbx_proxy_diff_t * diff)13589 void	zbx_dc_update_proxy(zbx_proxy_diff_t *diff)
13590 {
13591 	ZBX_DC_PROXY	*proxy;
13592 
13593 	WRLOCK_CACHE;
13594 
13595 	if (diff->lastaccess < config->proxy_lastaccess_ts)
13596 		diff->lastaccess = config->proxy_lastaccess_ts;
13597 
13598 	if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &diff->hostid)))
13599 	{
13600 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTACCESS))
13601 		{
13602 			int	lost = 0;	/* communication lost */
13603 
13604 			if (0 != (diff->flags &
13605 					(ZBX_FLAGS_PROXY_DIFF_UPDATE_HEARTBEAT | ZBX_FLAGS_PROXY_DIFF_UPDATE_CONFIG)))
13606 			{
13607 				int	delay = diff->lastaccess - proxy->lastaccess;
13608 
13609 				if (NET_DELAY_MAX < delay)
13610 					lost = 1;
13611 			}
13612 
13613 			if (0 == lost && proxy->lastaccess != diff->lastaccess)
13614 				proxy->lastaccess = diff->lastaccess;
13615 
13616 			/* proxy last access in database is updated separately in  */
13617 			/* every ZBX_PROXY_LASTACCESS_UPDATE_FREQUENCY seconds     */
13618 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTACCESS);
13619 		}
13620 
13621 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_VERSION))
13622 		{
13623 			if (proxy->version != diff->version)
13624 				proxy->version = diff->version;
13625 			else
13626 				diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_VERSION);
13627 		}
13628 
13629 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_COMPRESS))
13630 		{
13631 			if (proxy->auto_compress == diff->compress)
13632 				diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_COMPRESS);
13633 			proxy->auto_compress = diff->compress;
13634 		}
13635 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTERROR))
13636 		{
13637 			proxy->last_version_error_time = diff->last_version_error_time;
13638 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTERROR);
13639 		}
13640 
13641 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_PROXYDELAY))
13642 		{
13643 			proxy->proxy_delay = diff->proxy_delay;
13644 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_PROXYDELAY);
13645 		}
13646 
13647 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_SUPPRESS_WIN))
13648 		{
13649 			zbx_proxy_suppress_t	*ps_win = &proxy->nodata_win, *ds_win = &diff->nodata_win;
13650 
13651 			if ((ps_win->flags & ZBX_PROXY_SUPPRESS_ACTIVE) != (ds_win->flags & ZBX_PROXY_SUPPRESS_ACTIVE))
13652 			{
13653 				ps_win->period_end = ds_win->period_end;
13654 			}
13655 
13656 			if (ps_win->flags != ds_win->flags)
13657 				ps_win->flags = ds_win->flags;
13658 
13659 			if (0 > ps_win->values_num)	/* some new values was processed faster than old */
13660 				ps_win->values_num = 0;	/* we will suppress more                         */
13661 
13662 			ps_win->values_num += ds_win->values_num;
13663 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_SUPPRESS_WIN);
13664 		}
13665 	}
13666 
13667 	UNLOCK_CACHE;
13668 }
13669 
13670 /******************************************************************************
13671  *                                                                            *
13672  * Function: zbx_dc_get_proxy_lastaccess                                      *
13673  *                                                                            *
13674  * Purpose: returns proxy lastaccess changes since last lastaccess request    *
13675  *                                                                            *
13676  * Parameter: lastaccess - [OUT] last access updates for proxies that need    *
13677  *                               to be synced with database, sorted by        *
13678  *                               hostid                                       *
13679  *                                                                            *
13680  ******************************************************************************/
zbx_dc_get_proxy_lastaccess(zbx_vector_uint64_pair_t * lastaccess)13681 void	zbx_dc_get_proxy_lastaccess(zbx_vector_uint64_pair_t *lastaccess)
13682 {
13683 	ZBX_DC_PROXY	*proxy;
13684 	int		now;
13685 
13686 	if (ZBX_PROXY_LASTACCESS_UPDATE_FREQUENCY < (now = time(NULL)) - config->proxy_lastaccess_ts)
13687 	{
13688 		zbx_hashset_iter_t	iter;
13689 
13690 		WRLOCK_CACHE;
13691 
13692 		zbx_hashset_iter_reset(&config->proxies, &iter);
13693 
13694 		while (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_iter_next(&iter)))
13695 		{
13696 			if (proxy->lastaccess >= config->proxy_lastaccess_ts)
13697 			{
13698 				zbx_uint64_pair_t	pair = {proxy->hostid, proxy->lastaccess};
13699 
13700 				zbx_vector_uint64_pair_append(lastaccess, pair);
13701 			}
13702 		}
13703 
13704 		config->proxy_lastaccess_ts = now;
13705 
13706 		UNLOCK_CACHE;
13707 
13708 		zbx_vector_uint64_pair_sort(lastaccess, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
13709 	}
13710 }
13711 
13712 /******************************************************************************
13713  *                                                                            *
13714  * Function: zbx_dc_get_session_token                                         *
13715  *                                                                            *
13716  * Purpose: returns session token                                             *
13717  *                                                                            *
13718  * Return value: pointer to session token (NULL for server).                  *
13719  *                                                                            *
13720  * Comments: The session token is generated during configuration cache        *
13721  *           initialization and is not changed later. Therefore no locking    *
13722  *           is required.                                                     *
13723  *                                                                            *
13724  ******************************************************************************/
zbx_dc_get_session_token(void)13725 const char	*zbx_dc_get_session_token(void)
13726 {
13727 	return config->session_token;
13728 }
13729 
13730 /******************************************************************************
13731  *                                                                            *
13732  * Function: zbx_dc_get_or_create_data_session                                *
13733  *                                                                            *
13734  * Purpose: returns data session, creates a new session if none found         *
13735  *                                                                            *
13736  * Parameter: hostid - [IN] the host (proxy) identifier                       *
13737  *            token  - [IN] the session token (not NULL)                      *
13738  *                                                                            *
13739  * Return value: pointer to data session.                                     *
13740  *                                                                            *
13741  * Comments: The last_valueid property of the returned session object can be  *
13742  *           updated directly without locking cache because only one data     *
13743  *           session is updated at the same time and after retrieving the     *
13744  *           session object will not be deleted for 24 hours.                 *
13745  *                                                                            *
13746  ******************************************************************************/
zbx_dc_get_or_create_data_session(zbx_uint64_t hostid,const char * token)13747 zbx_data_session_t	*zbx_dc_get_or_create_data_session(zbx_uint64_t hostid, const char *token)
13748 {
13749 	zbx_data_session_t	*session, session_local;
13750 	time_t			now;
13751 
13752 	now = time(NULL);
13753 	session_local.hostid = hostid;
13754 	session_local.token = token;
13755 
13756 	RDLOCK_CACHE;
13757 	session = (zbx_data_session_t *)zbx_hashset_search(&config->data_sessions, &session_local);
13758 	UNLOCK_CACHE;
13759 
13760 	if (NULL == session)
13761 	{
13762 		WRLOCK_CACHE;
13763 		session = (zbx_data_session_t *)zbx_hashset_insert(&config->data_sessions, &session_local,
13764 				sizeof(session_local));
13765 		session->token = dc_strdup(token);
13766 		UNLOCK_CACHE;
13767 
13768 		session->last_valueid = 0;
13769 	}
13770 
13771 	session->lastaccess = now;
13772 
13773 	return session;
13774 }
13775 
13776 /******************************************************************************
13777  *                                                                            *
13778  * Function: zbx_dc_cleanup_data_sessions                                     *
13779  *                                                                            *
13780  * Purpose: removes data sessions not accessed for 24 hours                   *
13781  *                                                                            *
13782  ******************************************************************************/
zbx_dc_cleanup_data_sessions(void)13783 void	zbx_dc_cleanup_data_sessions(void)
13784 {
13785 	zbx_data_session_t	*session;
13786 	zbx_hashset_iter_t	iter;
13787 	time_t			now;
13788 
13789 	now = time(NULL);
13790 
13791 	WRLOCK_CACHE;
13792 
13793 	zbx_hashset_iter_reset(&config->data_sessions, &iter);
13794 	while (NULL != (session = (zbx_data_session_t *)zbx_hashset_iter_next(&iter)))
13795 	{
13796 		if (session->lastaccess + SEC_PER_DAY <= now)
13797 		{
13798 			__config_mem_free_func((char *)session->token);
13799 			zbx_hashset_iter_remove(&iter);
13800 		}
13801 	}
13802 
13803 	UNLOCK_CACHE;
13804 }
13805 
zbx_gather_item_tags(ZBX_DC_ITEM * item,zbx_vector_ptr_t * item_tags)13806 static void	zbx_gather_item_tags(ZBX_DC_ITEM *item, zbx_vector_ptr_t *item_tags)
13807 {
13808 	zbx_dc_item_tag_t	*dc_tag;
13809 	zbx_item_tag_t		*tag;
13810 	int			i;
13811 
13812 	for (i = 0; i < item->tags.values_num; i++)
13813 	{
13814 		dc_tag = (zbx_dc_item_tag_t *)item->tags.values[i];
13815 		tag = (zbx_item_tag_t *) zbx_malloc(NULL, sizeof(zbx_item_tag_t));
13816 		tag->tag.tag = zbx_strdup(NULL, dc_tag->tag);
13817 		tag->tag.value = zbx_strdup(NULL, dc_tag->value);
13818 		zbx_vector_ptr_append(item_tags, tag);
13819 	}
13820 }
13821 
zbx_gather_tags_from_host(zbx_uint64_t hostid,zbx_vector_ptr_t * item_tags)13822 static void	zbx_gather_tags_from_host(zbx_uint64_t hostid, zbx_vector_ptr_t *item_tags)
13823 {
13824 	zbx_dc_host_tag_index_t 	*dc_tag_index;
13825 	zbx_dc_host_tag_t		*dc_tag;
13826 	zbx_item_tag_t			*tag;
13827 	int				i;
13828 
13829 	if (NULL != (dc_tag_index = zbx_hashset_search(&config->host_tags_index, &hostid)))
13830 	{
13831 		for (i = 0; i < dc_tag_index->tags.values_num; i++)
13832 		{
13833 			dc_tag = (zbx_dc_host_tag_t *)dc_tag_index->tags.values[i];
13834 			tag = (zbx_item_tag_t *) zbx_malloc(NULL, sizeof(zbx_item_tag_t));
13835 			tag->tag.tag = zbx_strdup(NULL, dc_tag->tag);
13836 			tag->tag.value = zbx_strdup(NULL, dc_tag->value);
13837 			zbx_vector_ptr_append(item_tags, tag);
13838 		}
13839 	}
13840 }
13841 
zbx_gather_tags_from_template_chain(zbx_uint64_t itemid,zbx_vector_ptr_t * item_tags)13842 static void	zbx_gather_tags_from_template_chain(zbx_uint64_t itemid, zbx_vector_ptr_t *item_tags)
13843 {
13844 	ZBX_DC_TEMPLATE_ITEM	*item;
13845 
13846 	if (NULL != (item = (ZBX_DC_TEMPLATE_ITEM *)zbx_hashset_search(&config->template_items, &itemid)))
13847 	{
13848 		zbx_gather_tags_from_host(item->hostid, item_tags);
13849 
13850 		if (0 != item->templateid)
13851 			zbx_gather_tags_from_template_chain(item->templateid, item_tags);
13852 	}
13853 }
13854 
zbx_get_item_tags(zbx_uint64_t itemid,zbx_vector_ptr_t * item_tags)13855 static void	zbx_get_item_tags(zbx_uint64_t itemid, zbx_vector_ptr_t *item_tags)
13856 {
13857 	ZBX_DC_ITEM		*item;
13858 	ZBX_DC_PROTOTYPE_ITEM	*lld_item;
13859 	zbx_item_tag_t		*tag;
13860 	int			n, i;
13861 
13862 	if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
13863 		return;
13864 
13865 	n = item_tags->values_num;
13866 
13867 	zbx_gather_item_tags(item, item_tags);
13868 
13869 	zbx_gather_tags_from_host(item->hostid, item_tags);
13870 
13871 	if (0 != item->templateid)
13872 		zbx_gather_tags_from_template_chain(item->templateid, item_tags);
13873 
13874 	/* check for discovered item */
13875 	if (0 != item->parent_itemid && 4 == item->flags)
13876 	{
13877 		if (NULL != (lld_item = (ZBX_DC_PROTOTYPE_ITEM *)zbx_hashset_search(&config->prototype_items,
13878 				&item->parent_itemid)))
13879 		{
13880 			if (0 != lld_item->templateid)
13881 				zbx_gather_tags_from_template_chain(lld_item->templateid, item_tags);
13882 		}
13883 	}
13884 
13885 	/* assign hostid and itemid values to newly gathered tags */
13886 	for (i = n; i < item_tags->values_num; i++)
13887 	{
13888 		tag = (zbx_item_tag_t *)item_tags->values[i];
13889 		tag->hostid = item->hostid;
13890 		tag->itemid = item->itemid;
13891 	}
13892 }
13893 
zbx_dc_get_item_tags(zbx_uint64_t itemid,zbx_vector_ptr_t * item_tags)13894 void	zbx_dc_get_item_tags(zbx_uint64_t itemid, zbx_vector_ptr_t *item_tags)
13895 {
13896 	RDLOCK_CACHE;
13897 
13898 	zbx_get_item_tags(itemid, item_tags);
13899 
13900 	UNLOCK_CACHE;
13901 }
13902 
zbx_dc_get_item_tags_by_functionids(const zbx_uint64_t * functionids,size_t functionids_num,zbx_vector_ptr_t * item_tags)13903 void	zbx_dc_get_item_tags_by_functionids(const zbx_uint64_t *functionids, size_t functionids_num,
13904 		zbx_vector_ptr_t *item_tags)
13905 {
13906 	const ZBX_DC_FUNCTION	*dc_function;
13907 	size_t			i;
13908 
13909 	RDLOCK_CACHE;
13910 
13911 	for (i = 0; i < functionids_num; i++)
13912 	{
13913 		if (NULL == (dc_function = (const ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions,
13914 				&functionids[i])))
13915 		{
13916 			continue;
13917 		}
13918 
13919 		zbx_get_item_tags(dc_function->itemid, item_tags);
13920 	}
13921 
13922 	UNLOCK_CACHE;
13923 }
13924 
13925 /******************************************************************************
13926  *                                                                            *
13927  * Function: DCget_proxy_nodata_win                                           *
13928  *                                                                            *
13929  * Purpose: retrieves proxy suppress window data from the cache               *
13930  *                                                                            *
13931  * Parameters: hostid     - [IN] proxy host id                                *
13932  *             nodata_win - [OUT] suppress window data                        *
13933  *             lastaccess - [OUT] proxy last access time                      *
13934  *                                                                            *
13935  * Return value: SUCCEED - the data is retrieved                              *
13936  *               FAIL    - the data cannot be retrieved, proxy not found in   *
13937  *                         configuration cache                                *
13938  *                                                                            *
13939  ******************************************************************************/
DCget_proxy_nodata_win(zbx_uint64_t hostid,zbx_proxy_suppress_t * nodata_win,int * lastaccess)13940 int	DCget_proxy_nodata_win(zbx_uint64_t hostid, zbx_proxy_suppress_t *nodata_win, int *lastaccess)
13941 {
13942 	const ZBX_DC_PROXY	*dc_proxy;
13943 	int			ret;
13944 
13945 	RDLOCK_CACHE;
13946 
13947 	if (NULL != (dc_proxy = (const ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
13948 	{
13949 		const zbx_proxy_suppress_t	*proxy_nodata_win = &dc_proxy->nodata_win;
13950 
13951 		nodata_win->period_end = proxy_nodata_win->period_end;
13952 		nodata_win->values_num = proxy_nodata_win->values_num;
13953 		nodata_win->flags = proxy_nodata_win->flags;
13954 		*lastaccess = dc_proxy->lastaccess;
13955 		ret = SUCCEED;
13956 	}
13957 	else
13958 		ret = FAIL;
13959 
13960 	UNLOCK_CACHE;
13961 
13962 	return ret;
13963 }
13964 
13965 /******************************************************************************
13966  *                                                                            *
13967  * Function: DCget_proxy_delay                                                *
13968  *                                                                            *
13969  * Purpose: retrieves proxy delay from the cache                              *
13970  *                                                                            *
13971  * Parameters: hostid - [IN] proxy host id                                    *
13972  *             delay  - [OUT] proxy delay                                     *
13973  *                                                                            *
13974  * Return value: SUCCEED - the delay is retrieved                             *
13975  *               FAIL    - the delay cannot be retrieved, proxy not found in  *
13976  *                         configuration cache                                *
13977  *                                                                            *
13978  ******************************************************************************/
DCget_proxy_delay(zbx_uint64_t hostid,int * delay)13979 int	DCget_proxy_delay(zbx_uint64_t hostid, int *delay)
13980 {
13981 	const ZBX_DC_PROXY	*dc_proxy;
13982 	int			ret;
13983 
13984 	RDLOCK_CACHE;
13985 
13986 	if (NULL != (dc_proxy = (const ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
13987 	{
13988 		*delay = dc_proxy->proxy_delay;
13989 		ret = SUCCEED;
13990 	}
13991 	else
13992 		ret = FAIL;
13993 
13994 	UNLOCK_CACHE;
13995 
13996 	return ret;
13997 }
13998 
13999 /******************************************************************************
14000  *                                                                            *
14001  * Function: DCget_proxy_delay_by_name                                        *
14002  *                                                                            *
14003  * Purpose: retrieves proxy delay from the cache                              *
14004  *                                                                            *
14005  * Parameters: name  - [IN] proxy host name                                   *
14006  *             delay - [OUT] proxy delay                                      *
14007  *             error - [OUT] error                                            *
14008  *                                                                            *
14009  * Return value: SUCCEED - proxy delay is retrieved                           *
14010  *               FAIL    - proxy delay cannot be retrieved                    *
14011  *                                                                            *
14012  ******************************************************************************/
DCget_proxy_delay_by_name(const char * name,int * delay,char ** error)14013 int	DCget_proxy_delay_by_name(const char *name, int *delay, char **error)
14014 {
14015 	const ZBX_DC_HOST	*dc_host;
14016 
14017 	RDLOCK_CACHE;
14018 	dc_host = DCfind_proxy(name);
14019 	UNLOCK_CACHE;
14020 
14021 	if (NULL == dc_host)
14022 	{
14023 		*error = zbx_dsprintf(*error, "Proxy \"%s\" not found.", name);
14024 		return FAIL;
14025 	}
14026 
14027 	if (SUCCEED != DCget_proxy_delay(dc_host->hostid, delay))
14028 	{
14029 		*error = zbx_dsprintf(*error, "Proxy \"%s\" not found in configuration cache.", name);
14030 		return FAIL;
14031 	}
14032 
14033 	return SUCCEED;
14034 }
14035 
14036 /******************************************************************************
14037  *                                                                            *
14038  * Function: zbx_dc_set_macro_env                                             *
14039  *                                                                            *
14040  * Purpose: sets user macro environment security level                        *
14041  *                                                                            *
14042  * Parameter: env - [IN] the security level (see ZBX_MACRO_ENV_* defines)     *
14043  *                                                                            *
14044  * Comments: The security level affects how the secret macros are resolved -  *
14045  *           as they values or '******'.                                      *
14046  *                                                                            *
14047  ******************************************************************************/
zbx_dc_set_macro_env(unsigned char env)14048 unsigned char	zbx_dc_set_macro_env(unsigned char env)
14049 {
14050 	unsigned char	old_env = macro_env;
14051 	macro_env = env;
14052 	return old_env;
14053 }
14054 
14055 /******************************************************************************
14056  *                                                                            *
14057  * Function: zbx_dc_get_instanceid                                            *
14058  *                                                                            *
14059  * Purpose: returns server/proxy instance id                                  *
14060  *                                                                            *
14061  * Return value: the instance id                                              *
14062  *                                                                            *
14063  ******************************************************************************/
zbx_dc_get_instanceid(void)14064 const char	*zbx_dc_get_instanceid(void)
14065 {
14066 	/* instanceid is initialized during the first configuration cache synchronization */
14067 	/* and is never updated - so it can be accessed without locking cache             */
14068 	return config->config->instanceid;
14069 }
14070 
14071 /******************************************************************************
14072  *                                                                            *
14073  * Function: dc_expand_user_macros_in_func_params                             *
14074  *                                                                            *
14075  * Purpose: expand user macros in trigger function parameters                 *
14076  *                                                                            *
14077  * Parameters: params - [IN] the function parameters                          *
14078  *             hostid - [IN] host of the item used in function                *
14079  *                                                                            *
14080  * Return value: The function parameters with expanded user macros.           *
14081  *                                                                            *
14082  ******************************************************************************/
dc_expand_user_macros_in_func_params(const char * params,zbx_uint64_t hostid)14083 char	*dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid)
14084 {
14085 	const char	*ptr;
14086 	size_t		params_len;
14087 	char		*buf;
14088 	size_t		buf_alloc, buf_offset = 0, sep_pos;
14089 
14090 	if ('\0' == *params)
14091 		return zbx_strdup(NULL, params);
14092 
14093 	buf_alloc = params_len = strlen(params);
14094 	buf = zbx_malloc(NULL, buf_alloc);
14095 
14096 	for (ptr = params; ptr < params + params_len; ptr += sep_pos + 1)
14097 	{
14098 		size_t	param_pos, param_len;
14099 		int	quoted;
14100 		char	*param, *resolved_param;
14101 
14102 		zbx_function_param_parse(ptr, &param_pos, &param_len, &sep_pos);
14103 
14104 		param = zbx_function_param_unquote_dyn(ptr + param_pos, param_len, &quoted);
14105 		resolved_param = dc_expand_user_macros(param, &hostid, 1);
14106 
14107 		if (SUCCEED == zbx_function_param_quote(&resolved_param, quoted))
14108 			zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, resolved_param);
14109 		else
14110 			zbx_strncpy_alloc(&buf, &buf_alloc, &buf_offset, ptr + param_pos, param_len);
14111 
14112 		if (',' == ptr[sep_pos])
14113 			zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, ',');
14114 
14115 		zbx_free(resolved_param);
14116 		zbx_free(param);
14117 	}
14118 
14119 	return buf;
14120 }
14121 
zbx_dc_expand_user_macros_in_func_params(const char * params,zbx_uint64_t hostid)14122 char	*zbx_dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid)
14123 {
14124 	char	*resolved_params;
14125 
14126 	RDLOCK_CACHE;
14127 	resolved_params = dc_expand_user_macros_in_func_params(params, hostid);
14128 	UNLOCK_CACHE;
14129 
14130 	return resolved_params;
14131 }
14132 
14133 /*********************************************************************************
14134  *                                                                               *
14135  * Function: zbx_get_host_interfaces_availability                                *
14136  *                                                                               *
14137  * Purpose: get host interfaces availability                                     *
14138  *                                                                               *
14139  * Parameters: hostid               - [IN] the host id                           *
14140  *             agents               - [OUT] Zabbix agent availability            *
14141  *                                                                               *
14142  ********************************************************************************/
zbx_get_host_interfaces_availability(zbx_uint64_t hostid,zbx_agent_availability_t * agents)14143 void	zbx_get_host_interfaces_availability(zbx_uint64_t hostid, zbx_agent_availability_t *agents)
14144 {
14145 	const ZBX_DC_INTERFACE		*interface;
14146 	zbx_hashset_iter_t		iter;
14147 	int				i;
14148 
14149 	for (i = 0; i < ZBX_AGENT_MAX; i++)
14150 		zbx_agent_availability_init(&agents[i], INTERFACE_AVAILABLE_UNKNOWN, "", 0, 0);
14151 
14152 	RDLOCK_CACHE;
14153 
14154 	zbx_hashset_iter_reset(&config->interfaces, &iter);
14155 
14156 	while (NULL != (interface = (const ZBX_DC_INTERFACE *)zbx_hashset_iter_next(&iter)))
14157 	{
14158 		if (1 != interface->main)
14159 			continue;
14160 
14161 		if (hostid != interface->hostid)
14162 			continue;
14163 
14164 		i = ZBX_AGENT_UNKNOWN;
14165 
14166 		if (INTERFACE_TYPE_AGENT == interface->type)
14167 			i = ZBX_AGENT_ZABBIX;
14168 		else if (INTERFACE_TYPE_IPMI == interface->type)
14169 			i = ZBX_AGENT_IPMI;
14170 		else if (INTERFACE_TYPE_JMX == interface->type)
14171 			i = ZBX_AGENT_JMX;
14172 		else if (INTERFACE_TYPE_SNMP == interface->type)
14173 			i = ZBX_AGENT_SNMP;
14174 
14175 		if (ZBX_AGENT_UNKNOWN != i)
14176 			DCinterface_get_agent_availability(interface, &agents[i]);
14177 	}
14178 
14179 	UNLOCK_CACHE;
14180 
14181 }
14182 
14183 /*********************************************************************************
14184  *                                                                               *
14185  * Function: zbx_dc_eval_expand_user_macros                                      *
14186  *                                                                               *
14187  * Purpose: resolve user macros in parsed expression                             *
14188  *                                                                               *
14189  * Parameters: ctx - [IN] the expression evaluation context                      *
14190  *                                                                               *
14191  ********************************************************************************/
zbx_dc_eval_expand_user_macros(zbx_eval_context_t * ctx)14192 void	zbx_dc_eval_expand_user_macros(zbx_eval_context_t *ctx)
14193 {
14194 	zbx_vector_uint64_t	hostids, functionids;
14195 
14196 	zbx_vector_uint64_create(&hostids);
14197 	zbx_vector_uint64_create(&functionids);
14198 
14199 	zbx_eval_get_functionids(ctx, &functionids);
14200 	zbx_vector_uint64_sort(&functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
14201 	zbx_vector_uint64_uniq(&functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
14202 
14203 	RDLOCK_CACHE;
14204 
14205 	dc_get_hostids_by_functionids(functionids.values, functionids.values_num, &hostids);
14206 	(void)zbx_eval_expand_user_macros(ctx, hostids.values, hostids.values_num, dc_expand_user_macros_len, NULL);
14207 
14208 	UNLOCK_CACHE;
14209 
14210 	zbx_vector_uint64_destroy(&functionids);
14211 	zbx_vector_uint64_destroy(&hostids);
14212 }
14213 
zbx_dc_maintenance_has_tags(void)14214 int	zbx_dc_maintenance_has_tags(void)
14215 {
14216 	int	ret;
14217 
14218 	RDLOCK_CACHE;
14219 	ret = config->maintenance_tags.num_data != 0 ? SUCCEED : FAIL;
14220 	UNLOCK_CACHE;
14221 
14222 	return ret;
14223 }
14224 
14225 #ifdef HAVE_TESTS
14226 #	include "../../../tests/libs/zbxdbcache/dc_item_poller_type_update_test.c"
14227 #	include "../../../tests/libs/zbxdbcache/dc_function_calculate_nextcheck_test.c"
14228 #endif
14229