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 
36 #define ZBX_DBCONFIG_IMPL
37 #include "dbconfig.h"
38 #include "dbsync.h"
39 #include "proxy.h"
40 #include "actions.h"
41 
42 int	sync_in_progress = 0;
43 
44 #define START_SYNC	WRLOCK_CACHE; sync_in_progress = 1
45 #define FINISH_SYNC	sync_in_progress = 0; UNLOCK_CACHE
46 
47 #define ZBX_LOC_NOWHERE	0
48 #define ZBX_LOC_QUEUE	1
49 #define ZBX_LOC_POLLER	2
50 
51 #define ZBX_SNMP_OID_TYPE_NORMAL	0
52 #define ZBX_SNMP_OID_TYPE_DYNAMIC	1
53 #define ZBX_SNMP_OID_TYPE_MACRO		2
54 
55 /* trigger is functional unless its expression contains disabled or not monitored items */
56 #define TRIGGER_FUNCTIONAL_TRUE		0
57 #define TRIGGER_FUNCTIONAL_FALSE	1
58 
59 /* trigger contains time functions and is also scheduled by timer queue */
60 #define ZBX_TRIGGER_TIMER_UNKNOWN	0
61 #define ZBX_TRIGGER_TIMER_QUEUE		1
62 
63 /* item priority in poller queue */
64 #define ZBX_QUEUE_PRIORITY_HIGH		0
65 #define ZBX_QUEUE_PRIORITY_NORMAL	1
66 #define ZBX_QUEUE_PRIORITY_LOW		2
67 
68 /* shorthand macro for calling in_maintenance_without_data_collection() */
69 #define DCin_maintenance_without_data_collection(dc_host, dc_item)			\
70 		in_maintenance_without_data_collection(dc_host->maintenance_status,	\
71 				dc_host->maintenance_type, dc_item->type)
72 
73 /******************************************************************************
74  *                                                                            *
75  * Function: zbx_value_validator_func_t                                       *
76  *                                                                            *
77  * Purpose: validate macro value when expanding user macros                   *
78  *                                                                            *
79  * Parameters: macro   - [IN] the user macro                                  *
80  *             value   - [IN] the macro value                                 *
81  *             error   - [OUT] the error message                              *
82  *                                                                            *
83  * Return value: SUCCEED - the value is valid                                 *
84  *               FAIL    - otherwise                                          *
85  *                                                                            *
86  ******************************************************************************/
87 typedef int (*zbx_value_validator_func_t)(const char *macro, const char *value, char **error);
88 
89 ZBX_DC_CONFIG	*config = NULL;
90 zbx_rwlock_t	config_lock = ZBX_RWLOCK_NULL;
91 static zbx_mem_info_t	*config_mem;
92 
93 extern unsigned char	program_type;
94 extern int		CONFIG_TIMER_FORKS;
95 
96 ZBX_MEM_FUNC_IMPL(__config, config_mem)
97 
98 static void	dc_maintenance_precache_nested_groups(void);
99 
100 /* by default the macro environment is non-secure and all secret macros are masked with ****** */
101 static unsigned char	macro_env = ZBX_MACRO_ENV_NONSECURE;
102 
103 /******************************************************************************
104  *                                                                            *
105  * Function: dc_strdup                                                        *
106  *                                                                            *
107  * Purpose: copies string into configuration cache shared memory              *
108  *                                                                            *
109  ******************************************************************************/
dc_strdup(const char * source)110 static char	*dc_strdup(const char *source)
111 {
112 	char	*dst;
113 	size_t	len;
114 
115 	len = strlen(source) + 1;
116 	dst = (char *)__config_mem_malloc_func(NULL, len);
117 	memcpy(dst, source, len);
118 	return dst;
119 }
120 
121 /******************************************************************************
122  *                                                                            *
123  * Function: is_item_processed_by_server                                      *
124  *                                                                            *
125  * Parameters: type - [IN] item type [ITEM_TYPE_* flag]                       *
126  *             key  - [IN] item key                                           *
127  *                                                                            *
128  * Return value: SUCCEED when an item should be processed by server           *
129  *               FAIL otherwise                                               *
130  *                                                                            *
131  * Comments: list of the items, always processed by server                    *
132  *           ,------------------+--------------------------------------,      *
133  *           | type             | key                                  |      *
134  *           +------------------+--------------------------------------+      *
135  *           | Zabbix internal  | zabbix[host,,items]                  |      *
136  *           | Zabbix internal  | zabbix[host,,items_unsupported]      |      *
137  *           | Zabbix internal  | zabbix[host,discovery,interfaces]    |      *
138  *           | Zabbix internal  | zabbix[host,,maintenance]            |      *
139  *           | Zabbix internal  | zabbix[proxy,<proxyname>,lastaccess] |      *
140  *           | Zabbix internal  | zabbix[proxy,<proxyname>,delay]      |      *
141  *           | Zabbix aggregate | *                                    |      *
142  *           | Calculated       | *                                    |      *
143  *           '------------------+--------------------------------------'      *
144  *                                                                            *
145  ******************************************************************************/
is_item_processed_by_server(unsigned char type,const char * key)146 int	is_item_processed_by_server(unsigned char type, const char *key)
147 {
148 	int	ret = FAIL;
149 
150 	switch (type)
151 	{
152 		case ITEM_TYPE_AGGREGATE:
153 		case ITEM_TYPE_CALCULATED:
154 			ret = SUCCEED;
155 			break;
156 
157 		case ITEM_TYPE_INTERNAL:
158 			if (0 == strncmp(key, "zabbix[", 7))
159 			{
160 				AGENT_REQUEST	request;
161 				char		*arg1, *arg2, *arg3;
162 
163 				init_request(&request);
164 
165 				if (SUCCEED != parse_item_key(key, &request) || 3 != request.nparam)
166 					goto clean;
167 
168 				arg1 = get_rparam(&request, 0);
169 				arg2 = get_rparam(&request, 1);
170 				arg3 = get_rparam(&request, 2);
171 
172 				if (0 == strcmp(arg1, "host"))
173 				{
174 					if ('\0' == *arg2)
175 					{
176 						if (0 == strcmp(arg3, "maintenance") || 0 == strcmp(arg3, "items") ||
177 								0 == strcmp(arg3, "items_unsupported"))
178 						{
179 							ret = SUCCEED;
180 						}
181 					}
182 					else if (0 == strcmp(arg2, "discovery") && 0 == strcmp(arg3, "interfaces"))
183 						ret = SUCCEED;
184 				}
185 				else if (0 == strcmp(arg1, "proxy") &&
186 						(0 == strcmp(arg3, "lastaccess") || 0 == strcmp(arg3, "delay")))
187 					ret = SUCCEED;
188 clean:
189 				free_request(&request);
190 			}
191 			break;
192 	}
193 
194 	return ret;
195 }
196 
poller_by_item(unsigned char type,const char * key)197 static unsigned char	poller_by_item(unsigned char type, const char *key)
198 {
199 	switch (type)
200 	{
201 		case ITEM_TYPE_SIMPLE:
202 			if (SUCCEED == cmp_key_id(key, SERVER_ICMPPING_KEY) ||
203 					SUCCEED == cmp_key_id(key, SERVER_ICMPPINGSEC_KEY) ||
204 					SUCCEED == cmp_key_id(key, SERVER_ICMPPINGLOSS_KEY))
205 			{
206 				if (0 == CONFIG_PINGER_FORKS)
207 					break;
208 
209 				return ZBX_POLLER_TYPE_PINGER;
210 			}
211 			ZBX_FALLTHROUGH;
212 		case ITEM_TYPE_ZABBIX:
213 		case ITEM_TYPE_SNMP:
214 		case ITEM_TYPE_INTERNAL:
215 		case ITEM_TYPE_AGGREGATE:
216 		case ITEM_TYPE_EXTERNAL:
217 		case ITEM_TYPE_DB_MONITOR:
218 		case ITEM_TYPE_SSH:
219 		case ITEM_TYPE_TELNET:
220 		case ITEM_TYPE_CALCULATED:
221 		case ITEM_TYPE_HTTPAGENT:
222 			if (0 == CONFIG_POLLER_FORKS)
223 				break;
224 
225 			return ZBX_POLLER_TYPE_NORMAL;
226 		case ITEM_TYPE_IPMI:
227 			if (0 == CONFIG_IPMIPOLLER_FORKS)
228 				break;
229 
230 			return ZBX_POLLER_TYPE_IPMI;
231 		case ITEM_TYPE_JMX:
232 			if (0 == CONFIG_JAVAPOLLER_FORKS)
233 				break;
234 
235 			return ZBX_POLLER_TYPE_JAVA;
236 	}
237 
238 	return ZBX_NO_POLLER;
239 }
240 
241 /******************************************************************************
242  *                                                                            *
243  * Function: zbx_is_counted_in_item_queue                                     *
244  *                                                                            *
245  * Purpose: determine whether the given item type is counted in item queue    *
246  *                                                                            *
247  * Return value: SUCCEED if item is counted in the queue, FAIL otherwise      *
248  *                                                                            *
249  ******************************************************************************/
zbx_is_counted_in_item_queue(unsigned char type,const char * key)250 int	zbx_is_counted_in_item_queue(unsigned char type, const char *key)
251 {
252 	switch (type)
253 	{
254 		case ITEM_TYPE_ZABBIX_ACTIVE:
255 			if (0 == strncmp(key, "log[", 4) ||
256 					0 == strncmp(key, "logrt[", 6) ||
257 					0 == strncmp(key, "eventlog[", 9))
258 			{
259 				return FAIL;
260 			}
261 			break;
262 		case ITEM_TYPE_TRAPPER:
263 		case ITEM_TYPE_DEPENDENT:
264 		case ITEM_TYPE_HTTPTEST:
265 		case ITEM_TYPE_SNMPTRAP:
266 			return FAIL;
267 	}
268 
269 	return SUCCEED;
270 }
271 
272 /******************************************************************************
273  *                                                                            *
274  * Function: get_item_nextcheck_seed                                          *
275  *                                                                            *
276  * Purpose: get the seed value to be used for item nextcheck calculations     *
277  *                                                                            *
278  * Return value: the seed for nextcheck calculations                          *
279  *                                                                            *
280  * Comments: The seed value is used to spread multiple item nextchecks over   *
281  *           the item delay period to even the system load.                   *
282  *           Items with the same delay period and seed value will have the    *
283  *           same nextcheck values.                                           *
284  *                                                                            *
285  ******************************************************************************/
get_item_nextcheck_seed(zbx_uint64_t itemid,zbx_uint64_t interfaceid,unsigned char type,const char * key)286 static zbx_uint64_t	get_item_nextcheck_seed(zbx_uint64_t itemid, zbx_uint64_t interfaceid, unsigned char type,
287 		const char *key)
288 {
289 	if (ITEM_TYPE_JMX == type)
290 		return interfaceid;
291 
292 	if (ITEM_TYPE_SNMP == type)
293 	{
294 		ZBX_DC_SNMPINTERFACE	*snmp;
295 
296 		if (NULL == (snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid))
297 				|| SNMP_BULK_ENABLED != snmp->bulk)
298 		{
299 			return itemid;
300 		}
301 
302 		return interfaceid;
303 	}
304 
305 	if (ITEM_TYPE_SIMPLE == type)
306 	{
307 		if (SUCCEED == cmp_key_id(key, SERVER_ICMPPING_KEY) ||
308 				SUCCEED == cmp_key_id(key, SERVER_ICMPPINGSEC_KEY) ||
309 				SUCCEED == cmp_key_id(key, SERVER_ICMPPINGLOSS_KEY))
310 		{
311 			return interfaceid;
312 		}
313 	}
314 
315 	return itemid;
316 }
317 
318 static int	DCget_disable_until(const ZBX_DC_ITEM *item, const ZBX_DC_HOST *host);
319 
320 #define ZBX_ITEM_COLLECTED		0x01	/* force item rescheduling after new value collection */
321 #define ZBX_HOST_UNREACHABLE		0x02
322 #define ZBX_ITEM_KEY_CHANGED		0x04
323 #define ZBX_ITEM_TYPE_CHANGED		0x08
324 #define ZBX_ITEM_DELAY_CHANGED		0x10
325 #define ZBX_REFRESH_UNSUPPORTED_CHANGED	0x20
326 
DCitem_nextcheck_update(ZBX_DC_ITEM * item,const ZBX_DC_HOST * host,unsigned char new_state,int flags,int now,char ** error)327 static int	DCitem_nextcheck_update(ZBX_DC_ITEM *item, const ZBX_DC_HOST *host, unsigned char new_state,
328 		int flags, int now, char **error)
329 {
330 	zbx_uint64_t	seed;
331 
332 	if (0 == (flags & ZBX_ITEM_COLLECTED) && 0 != item->nextcheck &&
333 			0 == (flags & ZBX_ITEM_KEY_CHANGED) && 0 == (flags & ZBX_ITEM_TYPE_CHANGED) &&
334 			((ITEM_STATE_NORMAL == new_state && 0 == (flags & ZBX_ITEM_DELAY_CHANGED)) ||
335 			(ITEM_STATE_NOTSUPPORTED == new_state && 0 == (flags & (0 == item->schedulable ?
336 					ZBX_ITEM_DELAY_CHANGED : ZBX_REFRESH_UNSUPPORTED_CHANGED)))))
337 	{
338 		return SUCCEED;	/* avoid unnecessary nextcheck updates when syncing items in cache */
339 	}
340 
341 	seed = get_item_nextcheck_seed(item->itemid, item->interfaceid, item->type, item->key);
342 
343 	/* for new items, supported items and items that are notsupported due to invalid update interval try to parse */
344 	/* interval first and then decide whether it should become/remain supported/notsupported */
345 	if (0 == item->nextcheck || ITEM_STATE_NORMAL == new_state || 0 == item->schedulable)
346 	{
347 		int			simple_interval;
348 		zbx_custom_interval_t	*custom_intervals;
349 
350 		if (SUCCEED != zbx_interval_preproc(item->delay, &simple_interval, &custom_intervals, error))
351 		{
352 			/* Polling items with invalid update intervals repeatedly does not make sense because they */
353 			/* can only be healed by editing configuration (either update interval or macros involved) */
354 			/* and such changes will be detected during configuration synchronization. DCsync_items()  */
355 			/* detects item configuration changes affecting check scheduling and passes them in flags. */
356 
357 			item->nextcheck = ZBX_JAN_2038;
358 			item->schedulable = 0;
359 			return FAIL;
360 		}
361 
362 		if (ITEM_STATE_NORMAL == new_state || 0 == item->schedulable)
363 		{
364 			int	disable_until;
365 
366 			if (0 != (flags & ZBX_HOST_UNREACHABLE) && 0 != (disable_until =
367 					DCget_disable_until(item, host)))
368 			{
369 				item->nextcheck = calculate_item_nextcheck_unreachable(simple_interval,
370 						custom_intervals, disable_until);
371 			}
372 			else
373 			{
374 				/* supported items and items that could not have been scheduled previously, but had */
375 				/* their update interval fixed, should be scheduled using their update intervals */
376 				item->nextcheck = calculate_item_nextcheck(seed, item->type, simple_interval,
377 						custom_intervals, now);
378 			}
379 		}
380 		else
381 		{
382 			/* use refresh_unsupported interval for new items that have a valid update interval of their */
383 			/* own, but were synced from the database in ITEM_STATE_NOTSUPPORTED state */
384 			item->nextcheck = calculate_item_nextcheck(seed, item->type, config->config->refresh_unsupported,
385 					NULL, now);
386 		}
387 
388 		zbx_custom_interval_free(custom_intervals);
389 	}
390 	else	/* for items notsupported for other reasons use refresh_unsupported interval */
391 	{
392 		item->nextcheck = calculate_item_nextcheck(seed, item->type, config->config->refresh_unsupported, NULL,
393 				now);
394 	}
395 
396 	item->schedulable = 1;
397 
398 	return SUCCEED;
399 }
400 
DCitem_poller_type_update(ZBX_DC_ITEM * dc_item,const ZBX_DC_HOST * dc_host,int flags)401 static void	DCitem_poller_type_update(ZBX_DC_ITEM *dc_item, const ZBX_DC_HOST *dc_host, int flags)
402 {
403 	unsigned char	poller_type;
404 
405 	if (0 != dc_host->proxy_hostid && SUCCEED != is_item_processed_by_server(dc_item->type, dc_item->key))
406 	{
407 		dc_item->poller_type = ZBX_NO_POLLER;
408 		return;
409 	}
410 
411 	poller_type = poller_by_item(dc_item->type, dc_item->key);
412 
413 	if (0 != (flags & ZBX_HOST_UNREACHABLE))
414 	{
415 		if (ZBX_POLLER_TYPE_NORMAL == poller_type || ZBX_POLLER_TYPE_JAVA == poller_type)
416 			poller_type = ZBX_POLLER_TYPE_UNREACHABLE;
417 
418 		dc_item->poller_type = poller_type;
419 		return;
420 	}
421 
422 	if (0 != (flags & ZBX_ITEM_COLLECTED))
423 	{
424 		dc_item->poller_type = poller_type;
425 		return;
426 	}
427 
428 	if (ZBX_POLLER_TYPE_UNREACHABLE != dc_item->poller_type ||
429 			(ZBX_POLLER_TYPE_NORMAL != poller_type && ZBX_POLLER_TYPE_JAVA != poller_type))
430 	{
431 		dc_item->poller_type = poller_type;
432 	}
433 }
434 
DCget_disable_until(const ZBX_DC_ITEM * item,const ZBX_DC_HOST * host)435 static int	DCget_disable_until(const ZBX_DC_ITEM *item, const ZBX_DC_HOST *host)
436 {
437 	switch (item->type)
438 	{
439 		case ITEM_TYPE_ZABBIX:
440 			if (0 != host->errors_from)
441 				return host->disable_until;
442 			break;
443 		case ITEM_TYPE_SNMP:
444 			if (0 != host->snmp_errors_from)
445 				return host->snmp_disable_until;
446 			break;
447 		case ITEM_TYPE_IPMI:
448 			if (0 != host->ipmi_errors_from)
449 				return host->ipmi_disable_until;
450 			break;
451 		case ITEM_TYPE_JMX:
452 			if (0 != host->jmx_errors_from)
453 				return host->jmx_disable_until;
454 			break;
455 		default:
456 			/* nothing to do */;
457 	}
458 
459 	return 0;
460 }
461 
DCincrease_disable_until(const ZBX_DC_ITEM * item,ZBX_DC_HOST * host,int now)462 static void	DCincrease_disable_until(const ZBX_DC_ITEM *item, ZBX_DC_HOST *host, int now)
463 {
464 	switch (item->type)
465 	{
466 		case ITEM_TYPE_ZABBIX:
467 			if (0 != host->errors_from)
468 				host->disable_until = now + CONFIG_TIMEOUT;
469 			break;
470 		case ITEM_TYPE_SNMP:
471 			if (0 != host->snmp_errors_from)
472 				host->snmp_disable_until = now + CONFIG_TIMEOUT;
473 			break;
474 		case ITEM_TYPE_IPMI:
475 			if (0 != host->ipmi_errors_from)
476 				host->ipmi_disable_until = now + CONFIG_TIMEOUT;
477 			break;
478 		case ITEM_TYPE_JMX:
479 			if (0 != host->jmx_errors_from)
480 				host->jmx_disable_until = now + CONFIG_TIMEOUT;
481 			break;
482 		default:
483 			/* nothing to do */;
484 	}
485 }
486 
487 /******************************************************************************
488  *                                                                            *
489  * Function: DCfind_id                                                        *
490  *                                                                            *
491  * Purpose: Find an element in a hashset by its 'id' or create the element if *
492  *          it does not exist                                                 *
493  *                                                                            *
494  * Parameters:                                                                *
495  *     hashset - [IN] hashset to search                                       *
496  *     id      - [IN] id of element to search for                             *
497  *     size    - [IN] size of element to search for                           *
498  *     found   - [OUT flag. 0 - element did not exist, it was created.        *
499  *                          1 - existing element was found.                   *
500  *                                                                            *
501  * Return value: pointer to the found or created element                      *
502  *                                                                            *
503  ******************************************************************************/
DCfind_id(zbx_hashset_t * hashset,zbx_uint64_t id,size_t size,int * found)504 void	*DCfind_id(zbx_hashset_t *hashset, zbx_uint64_t id, size_t size, int *found)
505 {
506 	void		*ptr;
507 	zbx_uint64_t	buffer[1024];	/* adjust buffer size to accommodate any type DCfind_id() can be called for */
508 
509 	if (NULL == (ptr = zbx_hashset_search(hashset, &id)))
510 	{
511 		*found = 0;
512 
513 		buffer[0] = id;
514 		ptr = zbx_hashset_insert(hashset, &buffer[0], size);
515 	}
516 	else
517 	{
518 		*found = 1;
519 	}
520 
521 	return ptr;
522 }
523 
DCfind_item(zbx_uint64_t hostid,const char * key)524 static ZBX_DC_ITEM	*DCfind_item(zbx_uint64_t hostid, const char *key)
525 {
526 	ZBX_DC_ITEM_HK	*item_hk, item_hk_local;
527 
528 	item_hk_local.hostid = hostid;
529 	item_hk_local.key = key;
530 
531 	if (NULL == (item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk, &item_hk_local)))
532 		return NULL;
533 	else
534 		return item_hk->item_ptr;
535 }
536 
DCfind_host(const char * host)537 static ZBX_DC_HOST	*DCfind_host(const char *host)
538 {
539 	ZBX_DC_HOST_H	*host_h, host_h_local;
540 
541 	host_h_local.host = host;
542 
543 	if (NULL == (host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local)))
544 		return NULL;
545 	else
546 		return host_h->host_ptr;
547 }
548 
549 /******************************************************************************
550  *                                                                            *
551  * Function: DCfind_proxy                                                     *
552  *                                                                            *
553  * Purpose: Find a record with proxy details in configuration cache using the *
554  *          proxy name                                                        *
555  *                                                                            *
556  * Parameters: host - [IN] proxy name                                         *
557  *                                                                            *
558  * Return value: pointer to record if found or NULL otherwise                 *
559  *                                                                            *
560  ******************************************************************************/
DCfind_proxy(const char * host)561 static ZBX_DC_HOST	*DCfind_proxy(const char *host)
562 {
563 	ZBX_DC_HOST_H	*host_p, host_p_local;
564 
565 	host_p_local.host = host;
566 
567 	if (NULL == (host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local)))
568 		return NULL;
569 	else
570 		return host_p->host_ptr;
571 }
572 
573 /* private strpool functions */
574 
575 #define	REFCOUNT_FIELD_SIZE	sizeof(zbx_uint32_t)
576 
__config_strpool_hash(const void * data)577 static zbx_hash_t	__config_strpool_hash(const void *data)
578 {
579 	return ZBX_DEFAULT_STRING_HASH_FUNC((char *)data + REFCOUNT_FIELD_SIZE);
580 }
581 
__config_strpool_compare(const void * d1,const void * d2)582 static int	__config_strpool_compare(const void *d1, const void *d2)
583 {
584 	return strcmp((char *)d1 + REFCOUNT_FIELD_SIZE, (char *)d2 + REFCOUNT_FIELD_SIZE);
585 }
586 
zbx_strpool_intern(const char * str)587 static const char	*zbx_strpool_intern(const char *str)
588 {
589 	void		*record;
590 	zbx_uint32_t	*refcount;
591 
592 	record = zbx_hashset_search(&config->strpool, str - REFCOUNT_FIELD_SIZE);
593 
594 	if (NULL == record)
595 	{
596 		record = zbx_hashset_insert_ext(&config->strpool, str - REFCOUNT_FIELD_SIZE,
597 				REFCOUNT_FIELD_SIZE + strlen(str) + 1, REFCOUNT_FIELD_SIZE);
598 		*(zbx_uint32_t *)record = 0;
599 	}
600 
601 	refcount = (zbx_uint32_t *)record;
602 	(*refcount)++;
603 
604 	return (char *)record + REFCOUNT_FIELD_SIZE;
605 }
606 
zbx_strpool_release(const char * str)607 void	zbx_strpool_release(const char *str)
608 {
609 	zbx_uint32_t	*refcount;
610 
611 	refcount = (zbx_uint32_t *)(str - REFCOUNT_FIELD_SIZE);
612 	if (0 == --(*refcount))
613 		zbx_hashset_remove(&config->strpool, str - REFCOUNT_FIELD_SIZE);
614 }
615 
zbx_strpool_acquire(const char * str)616 static const char	*zbx_strpool_acquire(const char *str)
617 {
618 	zbx_uint32_t	*refcount;
619 
620 	refcount = (zbx_uint32_t *)(str - REFCOUNT_FIELD_SIZE);
621 	(*refcount)++;
622 
623 	return str;
624 }
625 
DCstrpool_replace(int found,const char ** curr,const char * new_str)626 int	DCstrpool_replace(int found, const char **curr, const char *new_str)
627 {
628 	if (1 == found)
629 	{
630 		if (0 == strcmp(*curr, new_str))
631 			return FAIL;
632 
633 		zbx_strpool_release(*curr);
634 	}
635 
636 	*curr = zbx_strpool_intern(new_str);
637 
638 	return SUCCEED;	/* indicate that the string has been replaced */
639 }
640 
DCupdate_item_queue(ZBX_DC_ITEM * item,unsigned char old_poller_type,int old_nextcheck)641 static void	DCupdate_item_queue(ZBX_DC_ITEM *item, unsigned char old_poller_type, int old_nextcheck)
642 {
643 	zbx_binary_heap_elem_t	elem;
644 
645 	if (ZBX_LOC_POLLER == item->location)
646 		return;
647 
648 	if (ZBX_LOC_QUEUE == item->location && old_poller_type != item->poller_type)
649 	{
650 		item->location = ZBX_LOC_NOWHERE;
651 		zbx_binary_heap_remove_direct(&config->queues[old_poller_type], item->itemid);
652 	}
653 
654 	if (item->poller_type == ZBX_NO_POLLER)
655 		return;
656 
657 	if (ZBX_LOC_QUEUE == item->location && old_nextcheck == item->nextcheck)
658 		return;
659 
660 	elem.key = item->itemid;
661 	elem.data = (const void *)item;
662 
663 	if (ZBX_LOC_QUEUE != item->location)
664 	{
665 		item->location = ZBX_LOC_QUEUE;
666 		zbx_binary_heap_insert(&config->queues[item->poller_type], &elem);
667 	}
668 	else
669 		zbx_binary_heap_update_direct(&config->queues[item->poller_type], &elem);
670 }
671 
DCupdate_proxy_queue(ZBX_DC_PROXY * proxy)672 static void	DCupdate_proxy_queue(ZBX_DC_PROXY *proxy)
673 {
674 	zbx_binary_heap_elem_t	elem;
675 
676 	if (ZBX_LOC_POLLER == proxy->location)
677 		return;
678 
679 	proxy->nextcheck = proxy->proxy_tasks_nextcheck;
680 	if (proxy->proxy_data_nextcheck < proxy->nextcheck)
681 		proxy->nextcheck = proxy->proxy_data_nextcheck;
682 	if (proxy->proxy_config_nextcheck < proxy->nextcheck)
683 		proxy->nextcheck = proxy->proxy_config_nextcheck;
684 
685 	elem.key = proxy->hostid;
686 	elem.data = (const void *)proxy;
687 
688 	if (ZBX_LOC_QUEUE != proxy->location)
689 	{
690 		proxy->location = ZBX_LOC_QUEUE;
691 		zbx_binary_heap_insert(&config->pqueue, &elem);
692 	}
693 	else
694 		zbx_binary_heap_update_direct(&config->pqueue, &elem);
695 }
696 
697 /******************************************************************************
698  *                                                                            *
699  * Function: config_gmacro_add_index                                          *
700  *                                                                            *
701  * Purpose: adds global macro index                                           *
702  *                                                                            *
703  * Parameters: gmacro_index - [IN/OUT] a global macro index hashset           *
704  *             gmacro       - [IN] the macro to index                         *
705  *                                                                            *
706  * Return value: The macro index record.                                      *
707  *                                                                            *
708  ******************************************************************************/
config_gmacro_add_index(zbx_hashset_t * gmacro_index,ZBX_DC_GMACRO * gmacro)709 static ZBX_DC_GMACRO_M	*config_gmacro_add_index(zbx_hashset_t *gmacro_index, ZBX_DC_GMACRO *gmacro)
710 {
711 	ZBX_DC_GMACRO_M	*gmacro_m, gmacro_m_local;
712 
713 	gmacro_m_local.macro = gmacro->macro;
714 
715 	if (NULL == (gmacro_m = (ZBX_DC_GMACRO_M *)zbx_hashset_search(gmacro_index, &gmacro_m_local)))
716 	{
717 		gmacro_m_local.macro = zbx_strpool_acquire(gmacro->macro);
718 		zbx_vector_ptr_create_ext(&gmacro_m_local.gmacros, __config_mem_malloc_func, __config_mem_realloc_func,
719 				__config_mem_free_func);
720 
721 		gmacro_m = (ZBX_DC_GMACRO_M *)zbx_hashset_insert(gmacro_index, &gmacro_m_local, sizeof(ZBX_DC_GMACRO_M));
722 	}
723 
724 	zbx_vector_ptr_append(&gmacro_m->gmacros, gmacro);
725 	return gmacro_m;
726 }
727 
728 /******************************************************************************
729  *                                                                            *
730  * Function: config_gmacro_remove_index                                       *
731  *                                                                            *
732  * Purpose: removes global macro index                                        *
733  *                                                                            *
734  * Parameters: gmacro_index - [IN/OUT] a global macro index hashset           *
735  *             gmacro       - [IN] the macro to remove                        *
736  *                                                                            *
737  ******************************************************************************/
config_gmacro_remove_index(zbx_hashset_t * gmacro_index,ZBX_DC_GMACRO * gmacro)738 static ZBX_DC_GMACRO_M	*config_gmacro_remove_index(zbx_hashset_t *gmacro_index, ZBX_DC_GMACRO *gmacro)
739 {
740 	ZBX_DC_GMACRO_M	*gmacro_m, gmacro_m_local;
741 	int		index;
742 
743 	gmacro_m_local.macro = gmacro->macro;
744 
745 	if (NULL != (gmacro_m = (ZBX_DC_GMACRO_M *)zbx_hashset_search(gmacro_index, &gmacro_m_local)))
746 	{
747 		if (FAIL != (index = zbx_vector_ptr_search(&gmacro_m->gmacros, gmacro, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
748 			zbx_vector_ptr_remove(&gmacro_m->gmacros, index);
749 	}
750 	return gmacro_m;
751 }
752 
753 /******************************************************************************
754  *                                                                            *
755  * Function: config_gmacro_context_compare                                    *
756  *                                                                            *
757  * Purpose: comparison function to sort global macro vector by context        *
758  *          operator, value and macro name                                    *
759  *                                                                            *
760  ******************************************************************************/
config_gmacro_context_compare(const void * d1,const void * d2)761 static int	config_gmacro_context_compare(const void *d1, const void *d2)
762 {
763 	const ZBX_DC_GMACRO	*m1 = *(const ZBX_DC_GMACRO **)d1;
764 	const ZBX_DC_GMACRO	*m2 = *(const ZBX_DC_GMACRO **)d2;
765 
766 	/* macros without context have higher priority than macros with */
767 	if (NULL == m1->context)
768 		return NULL == m2->context ? 0 : -1;
769 
770 	if (NULL == m2->context)
771 		return 1;
772 
773 	/* CONDITION_OPERATOR_EQUAL (0) has higher priority than CONDITION_OPERATOR_REGEXP (8) */
774 	ZBX_RETURN_IF_NOT_EQUAL(m1->context_op, m2->context_op);
775 
776 	return strcmp(m1->context, m2->context);
777 }
778 
779 /******************************************************************************
780  *                                                                            *
781  * Function: config_hmacro_add_index                                          *
782  *                                                                            *
783  * Purpose: adds host macro index                                             *
784  *                                                                            *
785  * Parameters: hmacro_index - [IN/OUT] a host macro index hashset             *
786  *             hmacro       - [IN] the macro to index                         *
787  *                                                                            *
788  ******************************************************************************/
config_hmacro_add_index(zbx_hashset_t * hmacro_index,ZBX_DC_HMACRO * hmacro)789 static ZBX_DC_HMACRO_HM	*config_hmacro_add_index(zbx_hashset_t *hmacro_index, ZBX_DC_HMACRO *hmacro)
790 {
791 	ZBX_DC_HMACRO_HM	*hmacro_hm, hmacro_hm_local;
792 
793 	hmacro_hm_local.hostid = hmacro->hostid;
794 	hmacro_hm_local.macro = hmacro->macro;
795 
796 	if (NULL == (hmacro_hm = (ZBX_DC_HMACRO_HM *)zbx_hashset_search(hmacro_index, &hmacro_hm_local)))
797 	{
798 		hmacro_hm_local.macro = zbx_strpool_acquire(hmacro->macro);
799 		zbx_vector_ptr_create_ext(&hmacro_hm_local.hmacros, __config_mem_malloc_func, __config_mem_realloc_func,
800 				__config_mem_free_func);
801 
802 		hmacro_hm = (ZBX_DC_HMACRO_HM *)zbx_hashset_insert(hmacro_index, &hmacro_hm_local, sizeof(ZBX_DC_HMACRO_HM));
803 	}
804 
805 	zbx_vector_ptr_append(&hmacro_hm->hmacros, hmacro);
806 	return hmacro_hm;
807 }
808 
809 /******************************************************************************
810  *                                                                            *
811  * Function: config_hmacro_remove_index                                       *
812  *                                                                            *
813  * Purpose: removes host macro index                                          *
814  *                                                                            *
815  * Parameters: hmacro_index - [IN/OUT] a host macro index hashset             *
816  *             hmacro       - [IN] the macro name to remove                   *
817  *                                                                            *
818  ******************************************************************************/
config_hmacro_remove_index(zbx_hashset_t * hmacro_index,ZBX_DC_HMACRO * hmacro)819 static ZBX_DC_HMACRO_HM	*config_hmacro_remove_index(zbx_hashset_t *hmacro_index, ZBX_DC_HMACRO *hmacro)
820 {
821 	ZBX_DC_HMACRO_HM	*hmacro_hm, hmacro_hm_local;
822 	int			index;
823 
824 	hmacro_hm_local.hostid = hmacro->hostid;
825 	hmacro_hm_local.macro = hmacro->macro;
826 
827 	if (NULL != (hmacro_hm = (ZBX_DC_HMACRO_HM *)zbx_hashset_search(hmacro_index, &hmacro_hm_local)))
828 	{
829 		if (FAIL != (index = zbx_vector_ptr_search(&hmacro_hm->hmacros, hmacro, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
830 			zbx_vector_ptr_remove(&hmacro_hm->hmacros, index);
831 	}
832 	return hmacro_hm;
833 }
834 
835 /******************************************************************************
836  *                                                                            *
837  * Function: config_hmacro_context_compare                                    *
838  *                                                                            *
839  * Purpose: comparison function to sort host macro vector by context          *
840  *          operator, value and macro name                                    *
841  *                                                                            *
842  ******************************************************************************/
config_hmacro_context_compare(const void * d1,const void * d2)843 static int	config_hmacro_context_compare(const void *d1, const void *d2)
844 {
845 	const ZBX_DC_HMACRO	*m1 = *(const ZBX_DC_HMACRO **)d1;
846 	const ZBX_DC_HMACRO	*m2 = *(const ZBX_DC_HMACRO **)d2;
847 
848 	/* macros without context have higher priority than macros with */
849 	if (NULL == m1->context)
850 		return NULL == m2->context ? 0 : -1;
851 
852 	if (NULL == m2->context)
853 		return 1;
854 
855 	/* CONDITION_OPERATOR_EQUAL (0) has higher priority than CONDITION_OPERATOR_REGEXP (8) */
856 	ZBX_RETURN_IF_NOT_EQUAL(m1->context_op, m2->context_op);
857 
858 	return strcmp(m1->context, m2->context);
859 }
860 
861 /******************************************************************************
862  *                                                                            *
863  * Function: set_hk_opt                                                       *
864  *                                                                            *
865  * Purpose: sets and validates global housekeeping option                     *
866  *                                                                            *
867  * Parameters: value     - [OUT] housekeeping setting                         *
868  *             non_zero  - [IN] 0 if value is allowed to be zero, 1 otherwise *
869  *             value_min - [IN] minimal acceptable setting value              *
870  *             value_raw - [IN] setting value to validate                     *
871  *                                                                            *
872  ******************************************************************************/
set_hk_opt(int * value,int non_zero,int value_min,const char * value_raw)873 static int	set_hk_opt(int *value, int non_zero, int value_min, const char *value_raw)
874 {
875 	if (SUCCEED != is_time_suffix(value_raw, value, ZBX_LENGTH_UNLIMITED))
876 		return FAIL;
877 
878 	if (0 != non_zero && 0 == *value)
879 		return FAIL;
880 
881 	if (0 != *value && (value_min > *value || ZBX_HK_PERIOD_MAX < *value))
882 		return FAIL;
883 
884 	return SUCCEED;
885 }
886 
DCsync_config(zbx_dbsync_t * sync,int * flags)887 static int	DCsync_config(zbx_dbsync_t *sync, int *flags)
888 {
889 	const ZBX_TABLE	*config_table;
890 
891 	const char	*selected_fields[] = {"refresh_unsupported", "discovery_groupid", "snmptrap_logging",
892 					"severity_name_0", "severity_name_1", "severity_name_2", "severity_name_3",
893 					"severity_name_4", "severity_name_5", "hk_events_mode", "hk_events_trigger",
894 					"hk_events_internal", "hk_events_discovery", "hk_events_autoreg",
895 					"hk_services_mode", "hk_services", "hk_audit_mode", "hk_audit",
896 					"hk_sessions_mode", "hk_sessions", "hk_history_mode", "hk_history_global",
897 					"hk_history", "hk_trends_mode", "hk_trends_global", "hk_trends",
898 					"default_inventory_mode", "db_extension", "autoreg_tls_accept",
899 					"compression_status", "compression_availability", "compress_older",
900 					"instanceid"};	/* sync with zbx_dbsync_compare_config() */
901 	const char	*row[ARRSIZE(selected_fields)];
902 	size_t		i;
903 	int		j, found = 1, refresh_unsupported, ret;
904 	char		**db_row;
905 	zbx_uint64_t	rowid;
906 	unsigned char	tag;
907 
908 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
909 
910 	*flags = 0;
911 
912 	if (NULL == config->config)
913 	{
914 		found = 0;
915 		config->config = (ZBX_DC_CONFIG_TABLE *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_CONFIG_TABLE));
916 	}
917 
918 	if (SUCCEED != (ret = zbx_dbsync_next(sync, &rowid, &db_row, &tag)))
919 	{
920 		/* load default config data */
921 
922 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
923 			zabbix_log(LOG_LEVEL_ERR, "no records in table 'config'");
924 
925 		config_table = DBget_table("config");
926 
927 		for (i = 0; i < ARRSIZE(selected_fields); i++)
928 			row[i] = DBget_field(config_table, selected_fields[i])->default_value;
929 	}
930 	else
931 	{
932 		for (i = 0; i < ARRSIZE(selected_fields); i++)
933 			row[i] = db_row[i];
934 	}
935 
936 	/* store the config data */
937 
938 	if (SUCCEED != is_time_suffix(row[0], &refresh_unsupported, ZBX_LENGTH_UNLIMITED))
939 	{
940 		zabbix_log(LOG_LEVEL_WARNING, "invalid unsupported item refresh interval, restoring default");
941 
942 		config_table = DBget_table("config");
943 
944 		if (SUCCEED != is_time_suffix(DBget_field(config_table, "refresh_unsupported")->default_value,
945 				&refresh_unsupported, ZBX_LENGTH_UNLIMITED))
946 		{
947 			THIS_SHOULD_NEVER_HAPPEN;
948 			refresh_unsupported = 0;
949 		}
950 	}
951 
952 	if (0 == found || config->config->refresh_unsupported != refresh_unsupported)
953 		*flags |= ZBX_REFRESH_UNSUPPORTED_CHANGED;
954 
955 	config->config->refresh_unsupported = refresh_unsupported;
956 
957 	if (NULL != row[1])
958 		ZBX_STR2UINT64(config->config->discovery_groupid, row[1]);
959 	else
960 		config->config->discovery_groupid = ZBX_DISCOVERY_GROUPID_UNDEFINED;
961 
962 	ZBX_STR2UCHAR(config->config->snmptrap_logging, row[2]);
963 	config->config->default_inventory_mode = atoi(row[26]);
964 	DCstrpool_replace(found, (const char **)&config->config->db.extension, row[27]);
965 	ZBX_STR2UCHAR(config->config->autoreg_tls_accept, row[28]);
966 	ZBX_STR2UCHAR(config->config->db.history_compression_status, row[29]);
967 	ZBX_STR2UCHAR(config->config->db.history_compression_availability, row[30]);
968 
969 	if (SUCCEED != is_time_suffix(row[31], &config->config->db.history_compress_older, ZBX_LENGTH_UNLIMITED))
970 	{
971 		zabbix_log(LOG_LEVEL_WARNING, "invalid history compression age: %s", row[31]);
972 		config->config->db.history_compress_older = 0;
973 	}
974 
975 	for (j = 0; TRIGGER_SEVERITY_COUNT > j; j++)
976 		DCstrpool_replace(found, &config->config->severity_name[j], row[3 + j]);
977 
978 	/* instance id cannot be changed - update it only at first sync to avoid read locks later */
979 	if (0 == found)
980 		DCstrpool_replace(found, &config->config->instanceid, row[32]);
981 
982 #if TRIGGER_SEVERITY_COUNT != 6
983 #	error "row indexes below are based on assumption of six trigger severity levels"
984 #endif
985 
986 	/* read housekeeper configuration */
987 
988 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.events_mode = atoi(row[9])) &&
989 			(SUCCEED != set_hk_opt(&config->config->hk.events_trigger, 1, SEC_PER_DAY, row[10]) ||
990 			SUCCEED != set_hk_opt(&config->config->hk.events_internal, 1, SEC_PER_DAY, row[11]) ||
991 			SUCCEED != set_hk_opt(&config->config->hk.events_discovery, 1, SEC_PER_DAY, row[12]) ||
992 			SUCCEED != set_hk_opt(&config->config->hk.events_autoreg, 1, SEC_PER_DAY, row[13])))
993 	{
994 		zabbix_log(LOG_LEVEL_WARNING, "trigger, internal, network discovery and auto-registration data"
995 				" housekeeping will be disabled due to invalid settings");
996 		config->config->hk.events_mode = ZBX_HK_OPTION_DISABLED;
997 	}
998 
999 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.services_mode = atoi(row[14])) &&
1000 			SUCCEED != set_hk_opt(&config->config->hk.services, 1, SEC_PER_DAY, row[15]))
1001 	{
1002 		zabbix_log(LOG_LEVEL_WARNING, "IT services data housekeeping will be disabled due to invalid"
1003 				" settings");
1004 		config->config->hk.services_mode = ZBX_HK_OPTION_DISABLED;
1005 	}
1006 
1007 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.audit_mode = atoi(row[16])) &&
1008 			SUCCEED != set_hk_opt(&config->config->hk.audit, 1, SEC_PER_DAY, row[17]))
1009 	{
1010 		zabbix_log(LOG_LEVEL_WARNING, "audit data housekeeping will be disabled due to invalid"
1011 				" settings");
1012 		config->config->hk.audit_mode = ZBX_HK_OPTION_DISABLED;
1013 	}
1014 
1015 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.sessions_mode = atoi(row[18])) &&
1016 			SUCCEED != set_hk_opt(&config->config->hk.sessions, 1, SEC_PER_DAY, row[19]))
1017 	{
1018 		zabbix_log(LOG_LEVEL_WARNING, "user sessions data housekeeping will be disabled due to invalid"
1019 				" settings");
1020 		config->config->hk.sessions_mode = ZBX_HK_OPTION_DISABLED;
1021 	}
1022 
1023 	config->config->hk.history_mode = atoi(row[20]);
1024 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.history_global = atoi(row[21])) &&
1025 			SUCCEED != set_hk_opt(&config->config->hk.history, 0, ZBX_HK_HISTORY_MIN, row[22]))
1026 	{
1027 		zabbix_log(LOG_LEVEL_WARNING, "history data housekeeping will be disabled and all items will"
1028 				" store their history due to invalid global override settings");
1029 		config->config->hk.history_mode = ZBX_HK_MODE_DISABLED;
1030 		config->config->hk.history = 1;	/* just enough to make 0 == items[i].history condition fail */
1031 	}
1032 
1033 #ifdef HAVE_POSTGRESQL
1034 	if (ZBX_HK_MODE_DISABLED != config->config->hk.history_mode &&
1035 			ZBX_HK_OPTION_ENABLED == config->config->hk.history_global &&
1036 			0 == zbx_strcmp_null(config->config->db.extension, ZBX_CONFIG_DB_EXTENSION_TIMESCALE))
1037 	{
1038 		config->config->hk.history_mode = ZBX_HK_MODE_PARTITION;
1039 	}
1040 #endif
1041 
1042 	config->config->hk.trends_mode = atoi(row[23]);
1043 	if (ZBX_HK_OPTION_ENABLED == (config->config->hk.trends_global = atoi(row[24])) &&
1044 			SUCCEED != set_hk_opt(&config->config->hk.trends, 0, ZBX_HK_TRENDS_MIN, row[25]))
1045 	{
1046 		zabbix_log(LOG_LEVEL_WARNING, "trends data housekeeping will be disabled and all numeric items"
1047 				" will store their history due to invalid global override settings");
1048 		config->config->hk.trends_mode = ZBX_HK_MODE_DISABLED;
1049 		config->config->hk.trends = 1;	/* just enough to make 0 == items[i].trends condition fail */
1050 	}
1051 
1052 #ifdef HAVE_POSTGRESQL
1053 	if (ZBX_HK_MODE_DISABLED != config->config->hk.trends_mode &&
1054 			ZBX_HK_OPTION_ENABLED == config->config->hk.trends_global &&
1055 			0 == zbx_strcmp_null(config->config->db.extension, ZBX_CONFIG_DB_EXTENSION_TIMESCALE))
1056 	{
1057 		config->config->hk.trends_mode = ZBX_HK_MODE_PARTITION;
1058 	}
1059 #endif
1060 
1061 	if (SUCCEED == ret && SUCCEED == zbx_dbsync_next(sync, &rowid, &db_row, &tag))	/* table must have */
1062 		zabbix_log(LOG_LEVEL_ERR, "table 'config' has multiple records");	/* only one record */
1063 
1064 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1065 
1066 	return SUCCEED;
1067 }
1068 
DCsync_autoreg_config(zbx_dbsync_t * sync)1069 static void	DCsync_autoreg_config(zbx_dbsync_t *sync)
1070 {
1071 	/* sync this function with zbx_dbsync_compare_autoreg_psk() */
1072 	char		**db_row;
1073 	zbx_uint64_t	rowid;
1074 	unsigned char	tag;
1075 
1076 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1077 
1078 	if (SUCCEED == zbx_dbsync_next(sync, &rowid, &db_row, &tag))
1079 	{
1080 		switch (tag)
1081 		{
1082 			case ZBX_DBSYNC_ROW_ADD:
1083 			case ZBX_DBSYNC_ROW_UPDATE:
1084 				zbx_strlcpy(config->autoreg_psk_identity, db_row[0],
1085 						sizeof(config->autoreg_psk_identity));
1086 				zbx_strlcpy(config->autoreg_psk, db_row[1], sizeof(config->autoreg_psk));
1087 				break;
1088 			case ZBX_DBSYNC_ROW_REMOVE:
1089 				config->autoreg_psk_identity[0] = '\0';
1090 				zbx_guaranteed_memset(config->autoreg_psk, 0, sizeof(config->autoreg_psk));
1091 				break;
1092 			default:
1093 				THIS_SHOULD_NEVER_HAPPEN;
1094 		}
1095 	}
1096 
1097 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1098 }
1099 
DCsync_proxy_remove(ZBX_DC_PROXY * proxy)1100 static void	DCsync_proxy_remove(ZBX_DC_PROXY *proxy)
1101 {
1102 	if (ZBX_LOC_QUEUE == proxy->location)
1103 	{
1104 		zbx_binary_heap_remove_direct(&config->pqueue, proxy->hostid);
1105 		proxy->location = ZBX_LOC_NOWHERE;
1106 	}
1107 
1108 	zbx_strpool_release(proxy->proxy_address);
1109 	zbx_hashset_remove_direct(&config->proxies, proxy);
1110 }
1111 
DCsync_hosts(zbx_dbsync_t * sync)1112 static void	DCsync_hosts(zbx_dbsync_t *sync)
1113 {
1114 	char		**row;
1115 	zbx_uint64_t	rowid;
1116 	unsigned char	tag;
1117 
1118 	ZBX_DC_HOST	*host;
1119 	ZBX_DC_IPMIHOST	*ipmihost;
1120 	ZBX_DC_PROXY	*proxy;
1121 	ZBX_DC_HOST_H	*host_h, host_h_local, *host_p, host_p_local;
1122 
1123 	int		found;
1124 	int		update_index_h, update_index_p, ret;
1125 	zbx_uint64_t	hostid, proxy_hostid;
1126 	unsigned char	status;
1127 	time_t		now;
1128 	signed char	ipmi_authtype;
1129 	unsigned char	ipmi_privilege;
1130 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1131 	ZBX_DC_PSK	*psk_i, psk_i_local;
1132 	zbx_ptr_pair_t	*psk_owner, psk_owner_local;
1133 	zbx_hashset_t	psk_owners;
1134 #endif
1135 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1136 
1137 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1138 	zbx_hashset_create(&psk_owners, 0, ZBX_DEFAULT_PTR_HASH_FUNC, ZBX_DEFAULT_PTR_COMPARE_FUNC);
1139 #endif
1140 	now = time(NULL);
1141 
1142 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1143 	{
1144 		/* removed rows will be always added at the end */
1145 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1146 			break;
1147 
1148 		ZBX_STR2UINT64(hostid, row[0]);
1149 		ZBX_DBROW2UINT64(proxy_hostid, row[1]);
1150 		ZBX_STR2UCHAR(status, row[22]);
1151 
1152 		host = (ZBX_DC_HOST *)DCfind_id(&config->hosts, hostid, sizeof(ZBX_DC_HOST), &found);
1153 
1154 		/* see whether we should and can update 'hosts_h' and 'hosts_p' indexes at this point */
1155 
1156 		update_index_h = 0;
1157 		update_index_p = 0;
1158 
1159 		if ((HOST_STATUS_MONITORED == status || HOST_STATUS_NOT_MONITORED == status) &&
1160 				(0 == found || 0 != strcmp(host->host, row[2])))
1161 		{
1162 			if (1 == found)
1163 			{
1164 				host_h_local.host = host->host;
1165 				host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local);
1166 
1167 				if (NULL != host_h && host == host_h->host_ptr)	/* see ZBX-4045 for NULL check */
1168 				{
1169 					zbx_strpool_release(host_h->host);
1170 					zbx_hashset_remove_direct(&config->hosts_h, host_h);
1171 				}
1172 			}
1173 
1174 			host_h_local.host = row[2];
1175 			host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local);
1176 
1177 			if (NULL != host_h)
1178 				host_h->host_ptr = host;
1179 			else
1180 				update_index_h = 1;
1181 		}
1182 		else if ((HOST_STATUS_PROXY_ACTIVE == status || HOST_STATUS_PROXY_PASSIVE == status) &&
1183 				(0 == found || 0 != strcmp(host->host, row[2])))
1184 		{
1185 			if (1 == found)
1186 			{
1187 				host_p_local.host = host->host;
1188 				host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local);
1189 
1190 				if (NULL != host_p && host == host_p->host_ptr)
1191 				{
1192 					zbx_strpool_release(host_p->host);
1193 					zbx_hashset_remove_direct(&config->hosts_p, host_p);
1194 				}
1195 			}
1196 
1197 			host_p_local.host = row[2];
1198 			host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local);
1199 
1200 			if (NULL != host_p)
1201 				host_p->host_ptr = host;
1202 			else
1203 				update_index_p = 1;
1204 		}
1205 
1206 		/* store new information in host structure */
1207 
1208 		DCstrpool_replace(found, &host->host, row[2]);
1209 		DCstrpool_replace(found, &host->name, row[23]);
1210 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1211 		DCstrpool_replace(found, &host->tls_issuer, row[31]);
1212 		DCstrpool_replace(found, &host->tls_subject, row[32]);
1213 
1214 		/* maintain 'config->psks' in configuration cache */
1215 
1216 		/*****************************************************************************/
1217 		/*                                                                           */
1218 		/* cases to cover (PSKid means PSK identity):                                */
1219 		/*                                                                           */
1220 		/*                                  Incoming data record                     */
1221 		/*                                  /                   \                    */
1222 		/*                                new                   new                  */
1223 		/*                               PSKid                 PSKid                 */
1224 		/*                             non-empty               empty                 */
1225 		/*                             /      \                /    \                */
1226 		/*                            /        \              /      \               */
1227 		/*                       'host'        'host'      'host'    'host'          */
1228 		/*                       record        record      record    record          */
1229 		/*                        has           has         has       has            */
1230 		/*                     non-empty       empty     non-empty  empty PSK        */
1231 		/*                        PSK           PSK         PSK      |     \         */
1232 		/*                       /   \           |           |       |      \        */
1233 		/*                      /     \          |           |       |       \       */
1234 		/*                     /       \         |           |       |        \      */
1235 		/*            new PSKid       new PSKid  |           |   existing     new    */
1236 		/*             same as         differs   |           |    record     record  */
1237 		/*            old PSKid         from     |           |      |          |     */
1238 		/*           /    |           old PSKid  |           |     done        |     */
1239 		/*          /     |              |       |           |                 |     */
1240 		/*   new PSK    new PSK        delete    |        delete               |     */
1241 		/*    value      value        old PSKid  |       old PSKid             |     */
1242 		/*   same as    differs       and value  |       and value             |     */
1243 		/*     old       from         from psks  |       from psks             |     */
1244 		/*      |        old          hashset    |        hashset              |     */
1245 		/*     done       /           (if ref    |        (if ref              |     */
1246 		/*               /            count=0)   |        count=0)             |     */
1247 		/*              /              /     \  /|           \                /      */
1248 		/*             /              /--------- |            \              /       */
1249 		/*            /              /         \ |             \            /        */
1250 		/*       delete          new PSKid   new PSKid         set pointer in        */
1251 		/*       old PSK          already     not in           'hosts' record        */
1252 		/*        value           in psks      psks             to NULL PSK          */
1253 		/*        from            hashset     hashset                |               */
1254 		/*       string            /   \          \                 done             */
1255 		/*        pool            /     \          \                                 */
1256 		/*         |             /       \          \                                */
1257 		/*       change    PSK value   PSK value    insert                           */
1258 		/*      PSK value  in hashset  in hashset  new PSKid                         */
1259 		/*      for this    same as     differs    and value                         */
1260 		/*       PSKid      new PSK     from new   into psks                         */
1261 		/*         |        value      PSK value    hashset                          */
1262 		/*        done        \           |            /                             */
1263 		/*                     \       replace        /                              */
1264 		/*                      \      PSK value     /                               */
1265 		/*                       \     in hashset   /                                */
1266 		/*                        \    with new    /                                 */
1267 		/*                         \   PSK value  /                                  */
1268 		/*                          \     |      /                                   */
1269 		/*                           \    |     /                                    */
1270 		/*                            set pointer                                    */
1271 		/*                            in 'host'                                      */
1272 		/*                            record to                                      */
1273 		/*                            new PSKid                                      */
1274 		/*                                |                                          */
1275 		/*                               done                                        */
1276 		/*                                                                           */
1277 		/*****************************************************************************/
1278 
1279 		psk_owner = NULL;
1280 
1281 		if ('\0' == *row[33] || '\0' == *row[34])	/* new PSKid or value empty */
1282 		{
1283 			/* In case of "impossible" errors ("PSK value without identity" or "PSK identity without */
1284 			/* value") assume empty PSK identity and value. These errors should have been prevented */
1285 			/* by validation in frontend/API. Be prepared when making a connection requiring PSK - */
1286 			/* the PSK might not be available. */
1287 
1288 			if (1 == found)
1289 			{
1290 				if (NULL == host->tls_dc_psk)	/* 'host' record has empty PSK */
1291 					goto done;
1292 
1293 				/* 'host' record has non-empty PSK. Unlink and delete PSK. */
1294 
1295 				psk_i_local.tls_psk_identity = host->tls_dc_psk->tls_psk_identity;
1296 
1297 				if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)) &&
1298 						0 == --(psk_i->refcount))
1299 				{
1300 					zbx_strpool_release(psk_i->tls_psk_identity);
1301 					zbx_strpool_release(psk_i->tls_psk);
1302 					zbx_hashset_remove_direct(&config->psks, psk_i);
1303 				}
1304 			}
1305 
1306 			host->tls_dc_psk = NULL;
1307 			goto done;
1308 		}
1309 
1310 		/* new PSKid and value non-empty */
1311 
1312 		zbx_strlower(row[34]);
1313 
1314 		if (1 == found && NULL != host->tls_dc_psk)	/* 'host' record has non-empty PSK */
1315 		{
1316 			if (0 == strcmp(host->tls_dc_psk->tls_psk_identity, row[33]))	/* new PSKid same as */
1317 											/* old PSKid */
1318 			{
1319 				if (0 != strcmp(host->tls_dc_psk->tls_psk, row[34]))	/* new PSK value */
1320 											/* differs from old */
1321 				{
1322 					if (NULL == (psk_owner = (zbx_ptr_pair_t *)zbx_hashset_search(&psk_owners,
1323 							&host->tls_dc_psk->tls_psk_identity)))
1324 					{
1325 						/* change underlying PSK value and 'config->psks' is updated, too */
1326 						DCstrpool_replace(1, &host->tls_dc_psk->tls_psk, row[34]);
1327 					}
1328 					else
1329 					{
1330 						zabbix_log(LOG_LEVEL_WARNING, "conflicting PSK values for PSK identity"
1331 								" \"%s\" on hosts \"%s\" and \"%s\" (and maybe others)",
1332 								(char *)psk_owner->first, (char *)psk_owner->second,
1333 								host->host);
1334 					}
1335 				}
1336 
1337 				goto done;
1338 			}
1339 
1340 			/* New PSKid differs from old PSKid. Unlink and delete old PSK. */
1341 
1342 			psk_i_local.tls_psk_identity = host->tls_dc_psk->tls_psk_identity;
1343 
1344 			if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)) &&
1345 					0 == --(psk_i->refcount))
1346 			{
1347 				zbx_strpool_release(psk_i->tls_psk_identity);
1348 				zbx_strpool_release(psk_i->tls_psk);
1349 				zbx_hashset_remove_direct(&config->psks, psk_i);
1350 			}
1351 
1352 			host->tls_dc_psk = NULL;
1353 		}
1354 
1355 		/* new PSK identity already stored? */
1356 
1357 		psk_i_local.tls_psk_identity = row[33];
1358 
1359 		if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)))
1360 		{
1361 			/* new PSKid already in psks hashset */
1362 
1363 			if (0 != strcmp(psk_i->tls_psk, row[34]))	/* PSKid stored but PSK value is different */
1364 			{
1365 				if (NULL == (psk_owner = (zbx_ptr_pair_t *)zbx_hashset_search(&psk_owners, &psk_i->tls_psk_identity)))
1366 				{
1367 					DCstrpool_replace(1, &psk_i->tls_psk, row[34]);
1368 				}
1369 				else
1370 				{
1371 					zabbix_log(LOG_LEVEL_WARNING, "conflicting PSK values for PSK identity"
1372 							" \"%s\" on hosts \"%s\" and \"%s\" (and maybe others)",
1373 							(char *)psk_owner->first, (char *)psk_owner->second,
1374 							host->host);
1375 				}
1376 			}
1377 
1378 			host->tls_dc_psk = psk_i;
1379 			psk_i->refcount++;
1380 			goto done;
1381 		}
1382 
1383 		/* insert new PSKid and value into psks hashset */
1384 
1385 		DCstrpool_replace(0, &psk_i_local.tls_psk_identity, row[33]);
1386 		DCstrpool_replace(0, &psk_i_local.tls_psk, row[34]);
1387 		psk_i_local.refcount = 1;
1388 		host->tls_dc_psk = zbx_hashset_insert(&config->psks, &psk_i_local, sizeof(ZBX_DC_PSK));
1389 done:
1390 		if (NULL != host->tls_dc_psk && NULL == psk_owner)
1391 		{
1392 			if (NULL == zbx_hashset_search(&psk_owners, &host->tls_dc_psk->tls_psk_identity))
1393 			{
1394 				/* register this host as the PSK identity owner, against which to report conflicts */
1395 
1396 				psk_owner_local.first = (char *)host->tls_dc_psk->tls_psk_identity;
1397 				psk_owner_local.second = (char *)host->host;
1398 
1399 				zbx_hashset_insert(&psk_owners, &psk_owner_local, sizeof(psk_owner_local));
1400 			}
1401 		}
1402 #endif
1403 		ZBX_STR2UCHAR(host->tls_connect, row[29]);
1404 		ZBX_STR2UCHAR(host->tls_accept, row[30]);
1405 
1406 		if (0 == found)
1407 		{
1408 			ZBX_DBROW2UINT64(host->maintenanceid, row[33 + ZBX_HOST_TLS_OFFSET]);
1409 			host->maintenance_status = (unsigned char)atoi(row[7]);
1410 			host->maintenance_type = (unsigned char)atoi(row[8]);
1411 			host->maintenance_from = atoi(row[9]);
1412 			host->data_expected_from = now;
1413 			host->update_items = 0;
1414 
1415 			host->errors_from = atoi(row[10]);
1416 			host->available = (unsigned char)atoi(row[11]);
1417 			host->disable_until = atoi(row[12]);
1418 			host->snmp_errors_from = atoi(row[13]);
1419 			host->snmp_available = (unsigned char)atoi(row[14]);
1420 			host->snmp_disable_until = atoi(row[15]);
1421 			host->ipmi_errors_from = atoi(row[16]);
1422 			host->ipmi_available = (unsigned char)atoi(row[17]);
1423 			host->ipmi_disable_until = atoi(row[18]);
1424 			host->jmx_errors_from = atoi(row[19]);
1425 			host->jmx_available = (unsigned char)atoi(row[20]);
1426 			host->jmx_disable_until = atoi(row[21]);
1427 			host->availability_ts = now;
1428 
1429 			DCstrpool_replace(0, &host->error, row[25]);
1430 			DCstrpool_replace(0, &host->snmp_error, row[26]);
1431 			DCstrpool_replace(0, &host->ipmi_error, row[27]);
1432 			DCstrpool_replace(0, &host->jmx_error, row[28]);
1433 
1434 			host->items_num = 0;
1435 			host->snmp_items_num = 0;
1436 			host->ipmi_items_num = 0;
1437 			host->jmx_items_num = 0;
1438 
1439 			host->reset_availability = 0;
1440 
1441 			zbx_vector_ptr_create_ext(&host->interfaces_v, __config_mem_malloc_func,
1442 					__config_mem_realloc_func, __config_mem_free_func);
1443 		}
1444 		else
1445 		{
1446 			if (HOST_STATUS_MONITORED == status && HOST_STATUS_MONITORED != host->status)
1447 				host->data_expected_from = now;
1448 
1449 			/* reset host status if host status has been changed (e.g., if host has been disabled) */
1450 			if (status != host->status)
1451 				host->reset_availability = 1;
1452 
1453 			/* reset host status if host proxy assignment has been changed */
1454 			if (proxy_hostid != host->proxy_hostid)
1455 				host->reset_availability = 1;
1456 		}
1457 
1458 		host->proxy_hostid = proxy_hostid;
1459 
1460 		/* update 'hosts_h' and 'hosts_p' indexes using new data, if not done already */
1461 
1462 		if (1 == update_index_h)
1463 		{
1464 			host_h_local.host = zbx_strpool_acquire(host->host);
1465 			host_h_local.host_ptr = host;
1466 			zbx_hashset_insert(&config->hosts_h, &host_h_local, sizeof(ZBX_DC_HOST_H));
1467 		}
1468 
1469 		if (1 == update_index_p)
1470 		{
1471 			host_p_local.host = zbx_strpool_acquire(host->host);
1472 			host_p_local.host_ptr = host;
1473 			zbx_hashset_insert(&config->hosts_p, &host_p_local, sizeof(ZBX_DC_HOST_H));
1474 		}
1475 
1476 		/* IPMI hosts */
1477 
1478 		ipmi_authtype = (signed char)atoi(row[3]);
1479 		ipmi_privilege = (unsigned char)atoi(row[4]);
1480 
1481 		if (ZBX_IPMI_DEFAULT_AUTHTYPE != ipmi_authtype || ZBX_IPMI_DEFAULT_PRIVILEGE != ipmi_privilege ||
1482 				'\0' != *row[5] || '\0' != *row[6])	/* useipmi */
1483 		{
1484 			ipmihost = (ZBX_DC_IPMIHOST *)DCfind_id(&config->ipmihosts, hostid, sizeof(ZBX_DC_IPMIHOST), &found);
1485 
1486 			ipmihost->ipmi_authtype = ipmi_authtype;
1487 			ipmihost->ipmi_privilege = ipmi_privilege;
1488 			DCstrpool_replace(found, &ipmihost->ipmi_username, row[5]);
1489 			DCstrpool_replace(found, &ipmihost->ipmi_password, row[6]);
1490 		}
1491 		else if (NULL != (ipmihost = (ZBX_DC_IPMIHOST *)zbx_hashset_search(&config->ipmihosts, &hostid)))
1492 		{
1493 			/* remove IPMI connection parameters for hosts without IPMI */
1494 
1495 			zbx_strpool_release(ipmihost->ipmi_username);
1496 			zbx_strpool_release(ipmihost->ipmi_password);
1497 
1498 			zbx_hashset_remove_direct(&config->ipmihosts, ipmihost);
1499 		}
1500 
1501 		/* proxies */
1502 
1503 		if (HOST_STATUS_PROXY_ACTIVE == status || HOST_STATUS_PROXY_PASSIVE == status)
1504 		{
1505 			proxy = (ZBX_DC_PROXY *)DCfind_id(&config->proxies, hostid, sizeof(ZBX_DC_PROXY), &found);
1506 
1507 			if (0 == found)
1508 			{
1509 				proxy->location = ZBX_LOC_NOWHERE;
1510 				proxy->version = 0;
1511 				proxy->lastaccess = atoi(row[24]);
1512 				proxy->last_cfg_error_time = 0;
1513 				proxy->proxy_delay = 0;
1514 				proxy->nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
1515 				proxy->nodata_win.values_num = 0;
1516 				proxy->nodata_win.period_end = 0;
1517 			}
1518 
1519 			proxy->auto_compress = atoi(row[32 + ZBX_HOST_TLS_OFFSET]);
1520 			DCstrpool_replace(found, &proxy->proxy_address, row[31 + ZBX_HOST_TLS_OFFSET]);
1521 
1522 			if (HOST_STATUS_PROXY_PASSIVE == status && (0 == found || status != host->status))
1523 			{
1524 				proxy->proxy_config_nextcheck = (int)calculate_proxy_nextcheck(
1525 						hostid, CONFIG_PROXYCONFIG_FREQUENCY, now);
1526 				proxy->proxy_data_nextcheck = (int)calculate_proxy_nextcheck(
1527 						hostid, CONFIG_PROXYDATA_FREQUENCY, now);
1528 				proxy->proxy_tasks_nextcheck = (int)calculate_proxy_nextcheck(
1529 						hostid, ZBX_TASK_UPDATE_FREQUENCY, now);
1530 
1531 				DCupdate_proxy_queue(proxy);
1532 			}
1533 			else if (HOST_STATUS_PROXY_ACTIVE == status && ZBX_LOC_QUEUE == proxy->location)
1534 			{
1535 				zbx_binary_heap_remove_direct(&config->pqueue, proxy->hostid);
1536 				proxy->location = ZBX_LOC_NOWHERE;
1537 			}
1538 			proxy->last_version_error_time = time(NULL);
1539 		}
1540 		else if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
1541 			DCsync_proxy_remove(proxy);
1542 
1543 		host->status = status;
1544 	}
1545 
1546 	/* remove deleted hosts from buffer */
1547 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1548 	{
1549 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &rowid)))
1550 			continue;
1551 
1552 		hostid = host->hostid;
1553 
1554 		/* IPMI hosts */
1555 
1556 		if (NULL != (ipmihost = (ZBX_DC_IPMIHOST *)zbx_hashset_search(&config->ipmihosts, &hostid)))
1557 		{
1558 			zbx_strpool_release(ipmihost->ipmi_username);
1559 			zbx_strpool_release(ipmihost->ipmi_password);
1560 
1561 			zbx_hashset_remove_direct(&config->ipmihosts, ipmihost);
1562 		}
1563 
1564 		/* proxies */
1565 
1566 		if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
1567 			DCsync_proxy_remove(proxy);
1568 
1569 		/* hosts */
1570 
1571 		if (HOST_STATUS_MONITORED == host->status || HOST_STATUS_NOT_MONITORED == host->status)
1572 		{
1573 			host_h_local.host = host->host;
1574 			host_h = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_h, &host_h_local);
1575 
1576 			if (NULL != host_h && host == host_h->host_ptr)	/* see ZBX-4045 for NULL check */
1577 			{
1578 				zbx_strpool_release(host_h->host);
1579 				zbx_hashset_remove_direct(&config->hosts_h, host_h);
1580 			}
1581 		}
1582 		else if (HOST_STATUS_PROXY_ACTIVE == host->status || HOST_STATUS_PROXY_PASSIVE == host->status)
1583 		{
1584 			host_p_local.host = host->host;
1585 			host_p = (ZBX_DC_HOST_H *)zbx_hashset_search(&config->hosts_p, &host_p_local);
1586 
1587 			if (NULL != host_p && host == host_p->host_ptr)
1588 			{
1589 				zbx_strpool_release(host_p->host);
1590 				zbx_hashset_remove_direct(&config->hosts_p, host_p);
1591 			}
1592 		}
1593 
1594 		zbx_strpool_release(host->host);
1595 		zbx_strpool_release(host->name);
1596 
1597 		zbx_strpool_release(host->error);
1598 		zbx_strpool_release(host->snmp_error);
1599 		zbx_strpool_release(host->ipmi_error);
1600 		zbx_strpool_release(host->jmx_error);
1601 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1602 		zbx_strpool_release(host->tls_issuer);
1603 		zbx_strpool_release(host->tls_subject);
1604 
1605 		/* Maintain 'psks' index. Unlink and delete the PSK identity. */
1606 		if (NULL != host->tls_dc_psk)
1607 		{
1608 			psk_i_local.tls_psk_identity = host->tls_dc_psk->tls_psk_identity;
1609 
1610 			if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)) &&
1611 					0 == --(psk_i->refcount))
1612 			{
1613 				zbx_strpool_release(psk_i->tls_psk_identity);
1614 				zbx_strpool_release(psk_i->tls_psk);
1615 				zbx_hashset_remove_direct(&config->psks, psk_i);
1616 			}
1617 		}
1618 #endif
1619 		zbx_vector_ptr_destroy(&host->interfaces_v);
1620 		zbx_hashset_remove_direct(&config->hosts, host);
1621 	}
1622 
1623 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1624 	zbx_hashset_destroy(&psk_owners);
1625 #endif
1626 
1627 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1628 }
1629 
DCsync_host_inventory(zbx_dbsync_t * sync)1630 static void	DCsync_host_inventory(zbx_dbsync_t *sync)
1631 {
1632 	ZBX_DC_HOST_INVENTORY	*host_inventory, *host_inventory_auto;
1633 	zbx_uint64_t		rowid, hostid;
1634 	int			found, ret, i;
1635 	char			**row;
1636 	unsigned char		tag;
1637 
1638 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1639 
1640 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1641 	{
1642 		/* removed rows will be always added at the end */
1643 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1644 			break;
1645 
1646 		ZBX_STR2UINT64(hostid, row[0]);
1647 
1648 		host_inventory = (ZBX_DC_HOST_INVENTORY *)DCfind_id(&config->host_inventories, hostid, sizeof(ZBX_DC_HOST_INVENTORY), &found);
1649 
1650 		ZBX_STR2UCHAR(host_inventory->inventory_mode, row[1]);
1651 
1652 		/* store new information in host_inventory structure */
1653 		for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1654 			DCstrpool_replace(found, &(host_inventory->values[i]), row[i + 2]);
1655 
1656 		host_inventory_auto = (ZBX_DC_HOST_INVENTORY *)DCfind_id(&config->host_inventories_auto, hostid, sizeof(ZBX_DC_HOST_INVENTORY),
1657 				&found);
1658 
1659 		host_inventory_auto->inventory_mode = host_inventory->inventory_mode;
1660 
1661 		if (1 == found)
1662 		{
1663 			for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1664 			{
1665 				if (NULL == host_inventory_auto->values[i])
1666 					continue;
1667 
1668 				zbx_strpool_release(host_inventory_auto->values[i]);
1669 				host_inventory_auto->values[i] = NULL;
1670 			}
1671 		}
1672 		else
1673 		{
1674 			for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1675 				host_inventory_auto->values[i] = NULL;
1676 		}
1677 	}
1678 
1679 	/* remove deleted host inventory from cache */
1680 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1681 	{
1682 		if (NULL == (host_inventory = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories, &rowid)))
1683 			continue;
1684 
1685 		for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1686 			zbx_strpool_release(host_inventory->values[i]);
1687 
1688 		zbx_hashset_remove_direct(&config->host_inventories, host_inventory);
1689 
1690 		if (NULL == (host_inventory_auto = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories_auto, &rowid)))
1691 		{
1692 			THIS_SHOULD_NEVER_HAPPEN;
1693 			continue;
1694 		}
1695 
1696 		for (i = 0; i < HOST_INVENTORY_FIELD_COUNT; i++)
1697 		{
1698 			if (NULL != host_inventory_auto->values[i])
1699 				zbx_strpool_release(host_inventory_auto->values[i]);
1700 		}
1701 
1702 		zbx_hashset_remove_direct(&config->host_inventories_auto, host_inventory_auto);
1703 	}
1704 
1705 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1706 }
1707 
DCsync_htmpls(zbx_dbsync_t * sync)1708 static void	DCsync_htmpls(zbx_dbsync_t *sync)
1709 {
1710 	char			**row;
1711 	zbx_uint64_t		rowid;
1712 	unsigned char		tag;
1713 
1714 	ZBX_DC_HTMPL		*htmpl = NULL;
1715 
1716 	int			found, i, index, ret;
1717 	zbx_uint64_t		_hostid = 0, hostid, templateid;
1718 	zbx_vector_ptr_t	sort;
1719 
1720 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1721 
1722 	zbx_vector_ptr_create(&sort);
1723 
1724 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1725 	{
1726 		/* removed rows will be always added at the end */
1727 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1728 			break;
1729 
1730 		ZBX_STR2UINT64(hostid, row[0]);
1731 		ZBX_STR2UINT64(templateid, row[1]);
1732 
1733 		if (_hostid != hostid || 0 == _hostid)
1734 		{
1735 			_hostid = hostid;
1736 
1737 			htmpl = (ZBX_DC_HTMPL *)DCfind_id(&config->htmpls, hostid, sizeof(ZBX_DC_HTMPL), &found);
1738 
1739 			if (0 == found)
1740 			{
1741 				zbx_vector_uint64_create_ext(&htmpl->templateids,
1742 						__config_mem_malloc_func,
1743 						__config_mem_realloc_func,
1744 						__config_mem_free_func);
1745 				zbx_vector_uint64_reserve(&htmpl->templateids, 1);
1746 			}
1747 
1748 			zbx_vector_ptr_append(&sort, htmpl);
1749 		}
1750 
1751 		zbx_vector_uint64_append(&htmpl->templateids, templateid);
1752 	}
1753 
1754 	/* remove deleted host templates from cache */
1755 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1756 	{
1757 		ZBX_STR2UINT64(hostid, row[0]);
1758 
1759 		if (NULL == (htmpl = (ZBX_DC_HTMPL *)zbx_hashset_search(&config->htmpls, &hostid)))
1760 			continue;
1761 
1762 		ZBX_STR2UINT64(templateid, row[1]);
1763 
1764 		if (-1 == (index = zbx_vector_uint64_search(&htmpl->templateids, templateid,
1765 				ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
1766 		{
1767 			continue;
1768 		}
1769 
1770 		if (1 == htmpl->templateids.values_num)
1771 		{
1772 			zbx_vector_uint64_destroy(&htmpl->templateids);
1773 			zbx_hashset_remove_direct(&config->htmpls, htmpl);
1774 		}
1775 		else
1776 		{
1777 			zbx_vector_uint64_remove_noorder(&htmpl->templateids, index);
1778 			zbx_vector_ptr_append(&sort, htmpl);
1779 		}
1780 	}
1781 
1782 	/* sort the changed template lists */
1783 
1784 	zbx_vector_ptr_sort(&sort, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1785 	zbx_vector_ptr_uniq(&sort, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
1786 
1787 	for (i = 0; i < sort.values_num; i++)
1788 	{
1789 		htmpl = (ZBX_DC_HTMPL *)sort.values[i];
1790 		zbx_vector_uint64_sort(&htmpl->templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1791 	}
1792 
1793 	zbx_vector_ptr_destroy(&sort);
1794 
1795 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1796 }
1797 
DCsync_gmacros(zbx_dbsync_t * sync)1798 static void	DCsync_gmacros(zbx_dbsync_t *sync)
1799 {
1800 	char			**row;
1801 	zbx_uint64_t		rowid;
1802 	unsigned char		tag, context_op;
1803 	ZBX_DC_GMACRO		*gmacro;
1804 	int			found, context_existed, update_index, ret, i;
1805 	zbx_uint64_t		globalmacroid;
1806 	char			*macro = NULL, *context = NULL;
1807 	zbx_vector_ptr_t	indexes;
1808 	ZBX_DC_GMACRO_M		*gmacro_m;
1809 
1810 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1811 
1812 	zbx_vector_ptr_create(&indexes);
1813 
1814 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1815 	{
1816 		/* removed rows will be always added at the end */
1817 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1818 			break;
1819 
1820 		ZBX_STR2UINT64(globalmacroid, row[0]);
1821 
1822 		if (SUCCEED != zbx_user_macro_parse_dyn(row[1], &macro, &context, NULL, &context_op))
1823 		{
1824 			zabbix_log(LOG_LEVEL_WARNING, "cannot parse user macro \"%s\"", row[1]);
1825 			continue;
1826 		}
1827 
1828 		gmacro = (ZBX_DC_GMACRO *)DCfind_id(&config->gmacros, globalmacroid, sizeof(ZBX_DC_GMACRO), &found);
1829 
1830 		/* see whether we should and can update gmacros_m index at this point */
1831 		update_index = 0;
1832 
1833 		if (0 == found || 0 != strcmp(gmacro->macro, macro) || 0 != zbx_strcmp_null(gmacro->context, context) ||
1834 				gmacro->context_op != context_op)
1835 		{
1836 			if (1 == found)
1837 			{
1838 				gmacro_m = config_gmacro_remove_index(&config->gmacros_m, gmacro);
1839 				zbx_vector_ptr_append(&indexes, gmacro_m);
1840 			}
1841 
1842 			update_index = 1;
1843 		}
1844 
1845 		/* store new information in macro structure */
1846 		ZBX_STR2UCHAR(gmacro->type, row[3]);
1847 		gmacro->context_op = context_op;
1848 		DCstrpool_replace(found, &gmacro->macro, macro);
1849 		DCstrpool_replace(found, &gmacro->value, row[2]);
1850 
1851 		context_existed = (1 == found && NULL != gmacro->context);
1852 
1853 		if (NULL == context)
1854 		{
1855 			/* release the context if it was removed from the macro */
1856 			if (1 == context_existed)
1857 				zbx_strpool_release(gmacro->context);
1858 
1859 			gmacro->context = NULL;
1860 		}
1861 		else
1862 		{
1863 			/* replace the existing context (1) or add context to macro (0) */
1864 			DCstrpool_replace(context_existed, &gmacro->context, context);
1865 		}
1866 
1867 		/* update gmacros_m index using new data */
1868 		if (1 == update_index)
1869 		{
1870 			gmacro_m = config_gmacro_add_index(&config->gmacros_m, gmacro);
1871 			zbx_vector_ptr_append(&indexes, gmacro_m);
1872 		}
1873 	}
1874 
1875 	/* remove deleted global macros from cache */
1876 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1877 	{
1878 		if (NULL == (gmacro = (ZBX_DC_GMACRO *)zbx_hashset_search(&config->gmacros, &rowid)))
1879 			continue;
1880 
1881 		gmacro_m = config_gmacro_remove_index(&config->gmacros_m, gmacro);
1882 		zbx_vector_ptr_append(&indexes, gmacro_m);
1883 
1884 		zbx_strpool_release(gmacro->macro);
1885 		zbx_strpool_release(gmacro->value);
1886 
1887 		if (NULL != gmacro->context)
1888 			zbx_strpool_release(gmacro->context);
1889 
1890 		zbx_hashset_remove_direct(&config->gmacros, gmacro);
1891 	}
1892 
1893 	zbx_vector_ptr_sort(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
1894 	zbx_vector_ptr_uniq(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
1895 
1896 	for (i = 0; i < indexes.values_num; i++)
1897 	{
1898 		gmacro_m = (ZBX_DC_GMACRO_M *)indexes.values[i];
1899 		if (0 == gmacro_m->gmacros.values_num)
1900 		{
1901 			zbx_strpool_release(gmacro_m->macro);
1902 			zbx_vector_ptr_destroy(&gmacro_m->gmacros);
1903 			zbx_hashset_remove_direct(&config->gmacros_m, gmacro_m);
1904 		}
1905 		else
1906 			zbx_vector_ptr_sort(&gmacro_m->gmacros, config_gmacro_context_compare);
1907 	}
1908 
1909 	zbx_free(context);
1910 	zbx_free(macro);
1911 	zbx_vector_ptr_destroy(&indexes);
1912 
1913 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1914 }
1915 
DCsync_hmacros(zbx_dbsync_t * sync)1916 static void	DCsync_hmacros(zbx_dbsync_t *sync)
1917 {
1918 	char			**row;
1919 	zbx_uint64_t		rowid;
1920 	unsigned char		tag, context_op;
1921 	ZBX_DC_HMACRO		*hmacro;
1922 	int			found, context_existed, update_index, ret, i;
1923 	zbx_uint64_t		hostmacroid, hostid;
1924 	char			*macro = NULL, *context = NULL;
1925 	zbx_vector_ptr_t	indexes;
1926 	ZBX_DC_HMACRO_HM	*hmacro_hm;
1927 
1928 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1929 
1930 	zbx_vector_ptr_create(&indexes);
1931 
1932 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
1933 	{
1934 		/* removed rows will be always added at the end */
1935 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
1936 			break;
1937 
1938 		ZBX_STR2UINT64(hostmacroid, row[0]);
1939 		ZBX_STR2UINT64(hostid, row[1]);
1940 
1941 		if (SUCCEED != zbx_user_macro_parse_dyn(row[2], &macro, &context, NULL, &context_op))
1942 		{
1943 			zabbix_log(LOG_LEVEL_WARNING, "cannot parse host \"%s\" macro \"%s\"", row[1], row[2]);
1944 			continue;
1945 		}
1946 
1947 		hmacro = (ZBX_DC_HMACRO *)DCfind_id(&config->hmacros, hostmacroid, sizeof(ZBX_DC_HMACRO), &found);
1948 
1949 		/* see whether we should and can update hmacros_hm index at this point */
1950 		update_index = 0;
1951 
1952 		if (0 == found || hmacro->hostid != hostid || 0 != strcmp(hmacro->macro, macro) ||
1953 				0 != zbx_strcmp_null(hmacro->context, context) || hmacro->context_op != context_op)
1954 		{
1955 			if (1 == found)
1956 			{
1957 				hmacro_hm = config_hmacro_remove_index(&config->hmacros_hm, hmacro);
1958 				zbx_vector_ptr_append(&indexes, hmacro_hm);
1959 			}
1960 
1961 			update_index = 1;
1962 		}
1963 
1964 		/* store new information in macro structure */
1965 		hmacro->hostid = hostid;
1966 		ZBX_STR2UCHAR(hmacro->type, row[4]);
1967 		hmacro->context_op = context_op;
1968 		DCstrpool_replace(found, &hmacro->macro, macro);
1969 		DCstrpool_replace(found, &hmacro->value, row[3]);
1970 
1971 		context_existed = (1 == found && NULL != hmacro->context);
1972 
1973 		if (NULL == context)
1974 		{
1975 			/* release the context if it was removed from the macro */
1976 			if (1 == context_existed)
1977 				zbx_strpool_release(hmacro->context);
1978 
1979 			hmacro->context = NULL;
1980 		}
1981 		else
1982 		{
1983 			/* replace the existing context (1) or add context to macro (0) */
1984 			DCstrpool_replace(context_existed, &hmacro->context, context);
1985 		}
1986 
1987 		/* update hmacros_hm index using new data */
1988 		if (1 == update_index)
1989 		{
1990 			hmacro_hm = config_hmacro_add_index(&config->hmacros_hm, hmacro);
1991 			zbx_vector_ptr_append(&indexes, hmacro_hm);
1992 		}
1993 	}
1994 
1995 	/* remove deleted host macros from buffer */
1996 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
1997 	{
1998 		if (NULL == (hmacro = (ZBX_DC_HMACRO *)zbx_hashset_search(&config->hmacros, &rowid)))
1999 			continue;
2000 
2001 		hmacro_hm = config_hmacro_remove_index(&config->hmacros_hm, hmacro);
2002 		zbx_vector_ptr_append(&indexes, hmacro_hm);
2003 
2004 		zbx_strpool_release(hmacro->macro);
2005 		zbx_strpool_release(hmacro->value);
2006 
2007 		if (NULL != hmacro->context)
2008 			zbx_strpool_release(hmacro->context);
2009 
2010 		zbx_hashset_remove_direct(&config->hmacros, hmacro);
2011 	}
2012 
2013 	zbx_vector_ptr_sort(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
2014 	zbx_vector_ptr_uniq(&indexes, ZBX_DEFAULT_PTR_COMPARE_FUNC);
2015 
2016 	for (i = 0; i < indexes.values_num; i++)
2017 	{
2018 		hmacro_hm = (ZBX_DC_HMACRO_HM *)indexes.values[i];
2019 		if (0 == hmacro_hm->hmacros.values_num)
2020 		{
2021 			zbx_strpool_release(hmacro_hm->macro);
2022 			zbx_vector_ptr_destroy(&hmacro_hm->hmacros);
2023 			zbx_hashset_remove_direct(&config->hmacros_hm, hmacro_hm);
2024 		}
2025 		else
2026 			zbx_vector_ptr_sort(&hmacro_hm->hmacros, config_hmacro_context_compare);
2027 	}
2028 
2029 	zbx_free(context);
2030 	zbx_free(macro);
2031 	zbx_vector_ptr_destroy(&indexes);
2032 
2033 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2034 }
2035 
2036 /******************************************************************************
2037  *                                                                            *
2038  * Function: substitute_host_interface_macros                                 *
2039  *                                                                            *
2040  * Purpose: trying to resolve the macros in host interface                    *
2041  *                                                                            *
2042  ******************************************************************************/
substitute_host_interface_macros(ZBX_DC_INTERFACE * interface)2043 static void	substitute_host_interface_macros(ZBX_DC_INTERFACE *interface)
2044 {
2045 	int	macros;
2046 	char	*addr;
2047 	DC_HOST	host;
2048 
2049 	macros = STR_CONTAINS_MACROS(interface->ip) ? 0x01 : 0;
2050 	macros |= STR_CONTAINS_MACROS(interface->dns) ? 0x02 : 0;
2051 
2052 	if (0 != macros)
2053 	{
2054 		DCget_host_by_hostid(&host, interface->hostid);
2055 
2056 		if (0 != (macros & 0x01))
2057 		{
2058 			addr = zbx_strdup(NULL, interface->ip);
2059 			substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL, NULL,
2060 					&addr, MACRO_TYPE_INTERFACE_ADDR, NULL, 0);
2061 			if (SUCCEED == is_ip(addr) || SUCCEED == zbx_validate_hostname(addr))
2062 				DCstrpool_replace(1, &interface->ip, addr);
2063 			zbx_free(addr);
2064 		}
2065 
2066 		if (0 != (macros & 0x02))
2067 		{
2068 			addr = zbx_strdup(NULL, interface->dns);
2069 			substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &host, NULL, NULL, NULL,
2070 					&addr, MACRO_TYPE_INTERFACE_ADDR, NULL, 0);
2071 			if (SUCCEED == is_ip(addr) || SUCCEED == zbx_validate_hostname(addr))
2072 				DCstrpool_replace(1, &interface->dns, addr);
2073 			zbx_free(addr);
2074 		}
2075 	}
2076 }
2077 
2078 /******************************************************************************
2079  *                                                                            *
2080  * Function: dc_interface_snmpaddrs_remove                                    *
2081  *                                                                            *
2082  * Purpose: remove interface from SNMP address -> interfaceid index           *
2083  *                                                                            *
2084  * Parameters: interface - [IN] the interface                                 *
2085  *                                                                            *
2086  ******************************************************************************/
dc_interface_snmpaddrs_remove(ZBX_DC_INTERFACE * interface)2087 static void	dc_interface_snmpaddrs_remove(ZBX_DC_INTERFACE *interface)
2088 {
2089 	ZBX_DC_INTERFACE_ADDR	*ifaddr, ifaddr_local;
2090 	int			index;
2091 
2092 	ifaddr_local.addr = (0 != interface->useip ? interface->ip : interface->dns);
2093 
2094 	if ('\0' == *ifaddr_local.addr)
2095 		return;
2096 
2097 	if (NULL == (ifaddr = (ZBX_DC_INTERFACE_ADDR *)zbx_hashset_search(&config->interface_snmpaddrs, &ifaddr_local)))
2098 		return;
2099 
2100 	if (FAIL == (index = zbx_vector_uint64_search(&ifaddr->interfaceids, interface->interfaceid,
2101 			ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2102 	{
2103 		return;
2104 	}
2105 
2106 	zbx_vector_uint64_remove_noorder(&ifaddr->interfaceids, index);
2107 
2108 	if (0 == ifaddr->interfaceids.values_num)
2109 	{
2110 		zbx_strpool_release(ifaddr->addr);
2111 		zbx_vector_uint64_destroy(&ifaddr->interfaceids);
2112 		zbx_hashset_remove_direct(&config->interface_snmpaddrs, ifaddr);
2113 	}
2114 }
2115 
2116 /******************************************************************************
2117  *                                                                            *
2118  * Function: dc_interface_snmp_set                                            *
2119  *                                                                            *
2120  * Purpose: setup SNMP attributes for interface with interfaceid index        *
2121  *                                                                            *
2122  * Parameters: interface - [IN] the interface                                 *
2123  *             row       - [IN] the row data from DB                          *
2124  *
2125  *                                                                            *
2126  ******************************************************************************/
dc_interface_snmp_set(zbx_uint64_t interfaceid,const char ** row,unsigned char * bulk_changed)2127 static ZBX_DC_SNMPINTERFACE	*dc_interface_snmp_set(zbx_uint64_t interfaceid, const char **row,
2128 		unsigned char *bulk_changed)
2129 {
2130 	int			found;
2131 	ZBX_DC_SNMPINTERFACE	*snmp;
2132 	unsigned char		bulk;
2133 
2134 	snmp = (ZBX_DC_SNMPINTERFACE *)DCfind_id(&config->interfaces_snmp, interfaceid, sizeof(ZBX_DC_SNMPINTERFACE),
2135 			&found);
2136 
2137 	ZBX_STR2UCHAR(bulk, row[9]);
2138 
2139 	if (0 == found)
2140 		*bulk_changed = 1;
2141 	else if (snmp->bulk != bulk)
2142 		*bulk_changed = 1;
2143 	else
2144 		*bulk_changed = 0;
2145 
2146 	if (0 != *bulk_changed)
2147 		snmp->bulk = bulk;
2148 
2149 	ZBX_STR2UCHAR(snmp->version, row[8]);
2150 	DCstrpool_replace(found, &snmp->community, row[10]);
2151 	DCstrpool_replace(found, &snmp->securityname, row[11]);
2152 	ZBX_STR2UCHAR(snmp->securitylevel, row[12]);
2153 	DCstrpool_replace(found, &snmp->authpassphrase, row[13]);
2154 	DCstrpool_replace(found, &snmp->privpassphrase, row[14]);
2155 	ZBX_STR2UCHAR(snmp->authprotocol, row[15]);
2156 	ZBX_STR2UCHAR(snmp->privprotocol, row[16]);
2157 	DCstrpool_replace(found, &snmp->contextname, row[17]);
2158 
2159 	return snmp;
2160 }
2161 
2162 /******************************************************************************
2163  *                                                                            *
2164  * Function: dc_interface_snmp_remove                                    *
2165  *                                                                            *
2166  * Purpose: remove interface from SNMP address -> interfaceid index           *
2167  *                                                                            *
2168  * Parameters: interface - [IN] the interface                                 *
2169  *                                                                            *
2170  ******************************************************************************/
dc_interface_snmp_remove(zbx_uint64_t interfaceid)2171 static void	dc_interface_snmp_remove(zbx_uint64_t interfaceid)
2172 {
2173 	ZBX_DC_SNMPINTERFACE	*snmp;
2174 
2175 	if (NULL == (snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid)))
2176 		return;
2177 
2178 	zbx_strpool_release(snmp->community);
2179 	zbx_strpool_release(snmp->securityname);
2180 	zbx_strpool_release(snmp->authpassphrase);
2181 	zbx_strpool_release(snmp->privpassphrase);
2182 	zbx_strpool_release(snmp->contextname);
2183 
2184 	zbx_hashset_remove_direct(&config->interfaces_snmp, snmp);
2185 
2186 	return;
2187 }
2188 
DCsync_interfaces(zbx_dbsync_t * sync)2189 static void	DCsync_interfaces(zbx_dbsync_t *sync)
2190 {
2191 	char			**row;
2192 	zbx_uint64_t		rowid;
2193 	unsigned char		tag;
2194 
2195 	ZBX_DC_INTERFACE	*interface;
2196 	ZBX_DC_INTERFACE_HT	*interface_ht, interface_ht_local;
2197 	ZBX_DC_INTERFACE_ADDR	*interface_snmpaddr, interface_snmpaddr_local;
2198 	ZBX_DC_HOST		*host;
2199 
2200 	int			found, update_index, ret, i;
2201 	zbx_uint64_t		interfaceid, hostid;
2202 	unsigned char		type, main_, useip;
2203 	unsigned char		reset_snmp_stats;
2204 	zbx_vector_ptr_t	interfaces;
2205 
2206 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2207 
2208 	zbx_vector_ptr_create(&interfaces);
2209 
2210 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
2211 	{
2212 		/* removed rows will be always added at the end */
2213 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
2214 			break;
2215 
2216 		ZBX_STR2UINT64(interfaceid, row[0]);
2217 		ZBX_STR2UINT64(hostid, row[1]);
2218 		ZBX_STR2UCHAR(type, row[2]);
2219 		ZBX_STR2UCHAR(main_, row[3]);
2220 		ZBX_STR2UCHAR(useip, row[4]);
2221 
2222 		/* If there is no host for this interface, skip it. */
2223 		/* This may be possible if the host was added after we synced config for hosts. */
2224 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
2225 			continue;
2226 
2227 		interface = (ZBX_DC_INTERFACE *)DCfind_id(&config->interfaces, interfaceid, sizeof(ZBX_DC_INTERFACE), &found);
2228 		zbx_vector_ptr_append(&interfaces, interface);
2229 
2230 		/* remove old address->interfaceid index */
2231 		if (0 != found && INTERFACE_TYPE_SNMP == interface->type)
2232 			dc_interface_snmpaddrs_remove(interface);
2233 
2234 		/* see whether we should and can update interfaces_ht index at this point */
2235 
2236 		update_index = 0;
2237 
2238 		if (0 == found || interface->hostid != hostid || interface->type != type || interface->main != main_)
2239 		{
2240 			if (1 == found && 1 == interface->main)
2241 			{
2242 				interface_ht_local.hostid = interface->hostid;
2243 				interface_ht_local.type = interface->type;
2244 				interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local);
2245 
2246 				if (NULL != interface_ht && interface == interface_ht->interface_ptr)
2247 				{
2248 					/* see ZBX-4045 for NULL check in the conditional */
2249 					zbx_hashset_remove(&config->interfaces_ht, &interface_ht_local);
2250 				}
2251 			}
2252 
2253 			if (1 == main_)
2254 			{
2255 				interface_ht_local.hostid = hostid;
2256 				interface_ht_local.type = type;
2257 				interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local);
2258 
2259 				if (NULL != interface_ht)
2260 					interface_ht->interface_ptr = interface;
2261 				else
2262 					update_index = 1;
2263 			}
2264 		}
2265 
2266 		/* store new information in interface structure */
2267 
2268 		reset_snmp_stats = (0 == found || interface->hostid != hostid || interface->type != type ||
2269 				interface->useip != useip);
2270 
2271 		interface->hostid = hostid;
2272 		interface->type = type;
2273 		interface->main = main_;
2274 		interface->useip = useip;
2275 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->ip, row[5]));
2276 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->dns, row[6]));
2277 		reset_snmp_stats |= (SUCCEED == DCstrpool_replace(found, &interface->port, row[7]));
2278 
2279 		/* update interfaces_ht index using new data, if not done already */
2280 
2281 		if (1 == update_index)
2282 		{
2283 			interface_ht_local.hostid = interface->hostid;
2284 			interface_ht_local.type = interface->type;
2285 			interface_ht_local.interface_ptr = interface;
2286 			zbx_hashset_insert(&config->interfaces_ht, &interface_ht_local, sizeof(ZBX_DC_INTERFACE_HT));
2287 		}
2288 
2289 		/* update interface_snmpaddrs for SNMP traps or reset bulk request statistics */
2290 
2291 		if (INTERFACE_TYPE_SNMP == interface->type)
2292 		{
2293 			ZBX_DC_SNMPINTERFACE	*snmp;
2294 			unsigned char		bulk_changed;
2295 
2296 			interface_snmpaddr_local.addr = (0 != interface->useip ? interface->ip : interface->dns);
2297 
2298 			if ('\0' != *interface_snmpaddr_local.addr)
2299 			{
2300 				if (NULL == (interface_snmpaddr = (ZBX_DC_INTERFACE_ADDR *)zbx_hashset_search(&config->interface_snmpaddrs,
2301 						&interface_snmpaddr_local)))
2302 				{
2303 					zbx_strpool_acquire(interface_snmpaddr_local.addr);
2304 
2305 					interface_snmpaddr = (ZBX_DC_INTERFACE_ADDR *)zbx_hashset_insert(&config->interface_snmpaddrs,
2306 							&interface_snmpaddr_local, sizeof(ZBX_DC_INTERFACE_ADDR));
2307 					zbx_vector_uint64_create_ext(&interface_snmpaddr->interfaceids,
2308 							__config_mem_malloc_func,
2309 							__config_mem_realloc_func,
2310 							__config_mem_free_func);
2311 				}
2312 
2313 				zbx_vector_uint64_append(&interface_snmpaddr->interfaceids, interfaceid);
2314 			}
2315 
2316 			if (FAIL == DBis_null(row[8]))
2317 			{
2318 				snmp = dc_interface_snmp_set(interfaceid, (const char **)row, &bulk_changed);
2319 
2320 				if (1 == reset_snmp_stats || 0 != bulk_changed)
2321 				{
2322 					snmp->max_succeed = 0;
2323 					snmp->min_fail = MAX_SNMP_ITEMS + 1;
2324 				}
2325 			}
2326 			else
2327 				THIS_SHOULD_NEVER_HAPPEN;
2328 		}
2329 
2330 		/* first resolve macros for ip and dns fields in main agent interface  */
2331 		/* because other interfaces might reference main interfaces ip and dns */
2332 		/* with {HOST.IP} and {HOST.DNS} macros                                */
2333 		if (1 == interface->main && INTERFACE_TYPE_AGENT == interface->type)
2334 			substitute_host_interface_macros(interface);
2335 
2336 		if (0 == found)
2337 		{
2338 			/* new interface - add it to a list of host interfaces in 'config->hosts' hashset */
2339 
2340 			int	exists = 0;
2341 
2342 			/* It is an error if the pointer is already in the list. Detect it. */
2343 
2344 			for (i = 0; i < host->interfaces_v.values_num; i++)
2345 			{
2346 				if (interface == host->interfaces_v.values[i])
2347 				{
2348 					exists = 1;
2349 					break;
2350 				}
2351 			}
2352 
2353 			if (0 == exists)
2354 				zbx_vector_ptr_append(&host->interfaces_v, interface);
2355 			else
2356 				THIS_SHOULD_NEVER_HAPPEN;
2357 		}
2358 	}
2359 
2360 	/* resolve macros in other interfaces */
2361 
2362 	for (i = 0; i < interfaces.values_num; i++)
2363 	{
2364 		interface = (ZBX_DC_INTERFACE *)interfaces.values[i];
2365 
2366 		if (1 != interface->main || INTERFACE_TYPE_AGENT != interface->type)
2367 			substitute_host_interface_macros(interface);
2368 	}
2369 
2370 	/* remove deleted interfaces from buffer */
2371 
2372 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
2373 	{
2374 		if (NULL == (interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &rowid)))
2375 			continue;
2376 
2377 		/* remove interface from the list of host interfaces in 'config->hosts' hashset */
2378 
2379 		if (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &interface->hostid)))
2380 		{
2381 			for (i = 0; i < host->interfaces_v.values_num; i++)
2382 			{
2383 				if (interface == host->interfaces_v.values[i])
2384 				{
2385 					zbx_vector_ptr_remove(&host->interfaces_v, i);
2386 					break;
2387 				}
2388 			}
2389 		}
2390 
2391 		if (INTERFACE_TYPE_SNMP == interface->type)
2392 		{
2393 			dc_interface_snmpaddrs_remove(interface);
2394 			dc_interface_snmp_remove(interface->interfaceid);
2395 		}
2396 
2397 		if (1 == interface->main)
2398 		{
2399 			interface_ht_local.hostid = interface->hostid;
2400 			interface_ht_local.type = interface->type;
2401 			interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local);
2402 
2403 			if (NULL != interface_ht && interface == interface_ht->interface_ptr)
2404 			{
2405 				/* see ZBX-4045 for NULL check in the conditional */
2406 				zbx_hashset_remove(&config->interfaces_ht, &interface_ht_local);
2407 			}
2408 		}
2409 
2410 		zbx_strpool_release(interface->ip);
2411 		zbx_strpool_release(interface->dns);
2412 		zbx_strpool_release(interface->port);
2413 
2414 		zbx_hashset_remove_direct(&config->interfaces, interface);
2415 	}
2416 
2417 	zbx_vector_ptr_destroy(&interfaces);
2418 
2419 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2420 }
2421 
2422 /******************************************************************************
2423  *                                                                            *
2424  * Function: dc_interface_snmpitems_remove                                    *
2425  *                                                                            *
2426  * Purpose: remove item from interfaceid -> itemid index                      *
2427  *                                                                            *
2428  * Parameters: interface - [IN] the item                                      *
2429  *                                                                            *
2430  ******************************************************************************/
dc_interface_snmpitems_remove(ZBX_DC_ITEM * item)2431 static void	dc_interface_snmpitems_remove(ZBX_DC_ITEM *item)
2432 {
2433 	ZBX_DC_INTERFACE_ITEM	*ifitem;
2434 	int			index;
2435 	zbx_uint64_t		interfaceid;
2436 
2437 	if (0 == (interfaceid = item->interfaceid))
2438 		return;
2439 
2440 	if (NULL == (ifitem = (ZBX_DC_INTERFACE_ITEM *)zbx_hashset_search(&config->interface_snmpitems, &interfaceid)))
2441 		return;
2442 
2443 	if (FAIL == (index = zbx_vector_uint64_search(&ifitem->itemids, item->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2444 		return;
2445 
2446 	zbx_vector_uint64_remove_noorder(&ifitem->itemids, index);
2447 
2448 	if (0 == ifitem->itemids.values_num)
2449 	{
2450 		zbx_vector_uint64_destroy(&ifitem->itemids);
2451 		zbx_hashset_remove_direct(&config->interface_snmpitems, ifitem);
2452 	}
2453 }
2454 
2455 /******************************************************************************
2456  *                                                                            *
2457  * Function: dc_masteritem_remove_depitem                                     *
2458  *                                                                            *
2459  * Purpose: remove itemid from master item dependent itemid vector            *
2460  *                                                                            *
2461  * Parameters: master_itemid - [IN] the master item identifier                *
2462  *             dep_itemid    - [IN] the dependent item identifier             *
2463  *                                                                            *
2464  ******************************************************************************/
dc_masteritem_remove_depitem(zbx_uint64_t master_itemid,zbx_uint64_t dep_itemid)2465 static void	dc_masteritem_remove_depitem(zbx_uint64_t master_itemid, zbx_uint64_t dep_itemid)
2466 {
2467 	ZBX_DC_MASTERITEM	*masteritem;
2468 	int			index;
2469 	zbx_uint64_pair_t	pair;
2470 
2471 	if (NULL == (masteritem = (ZBX_DC_MASTERITEM *)zbx_hashset_search(&config->masteritems, &master_itemid)))
2472 		return;
2473 
2474 	pair.first = dep_itemid;
2475 	if (FAIL == (index = zbx_vector_uint64_pair_search(&masteritem->dep_itemids, pair,
2476 			ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
2477 	{
2478 		return;
2479 	}
2480 
2481 	zbx_vector_uint64_pair_remove_noorder(&masteritem->dep_itemids, index);
2482 
2483 	if (0 == masteritem->dep_itemids.values_num)
2484 	{
2485 		zbx_vector_uint64_pair_destroy(&masteritem->dep_itemids);
2486 		zbx_hashset_remove_direct(&config->masteritems, masteritem);
2487 	}
2488 }
2489 
2490 /******************************************************************************
2491  *                                                                            *
2492  * Function: dc_host_update_agent_stats                                       *
2493  *                                                                            *
2494  * Purpose: update number of items per agent statistics                       *
2495  *                                                                            *
2496  * Parameters: host - [IN] the host                                           *
2497  *             type - [IN] the item type (ITEM_TYPE_*)                        *
2498  *             num  - [IN] the number of items (+) added, (-) removed         *
2499  *                                                                            *
2500  ******************************************************************************/
dc_host_update_agent_stats(ZBX_DC_HOST * host,unsigned char type,int num)2501 static void	dc_host_update_agent_stats(ZBX_DC_HOST *host, unsigned char type, int num)
2502 {
2503 	switch (type)
2504 	{
2505 		case ITEM_TYPE_ZABBIX:
2506 			host->items_num += num;
2507 			break;
2508 		case ITEM_TYPE_SNMP:
2509 			host->snmp_items_num += num;
2510 			break;
2511 		case ITEM_TYPE_IPMI:
2512 			host->ipmi_items_num += num;
2513 			break;
2514 		case ITEM_TYPE_JMX:
2515 			host->jmx_items_num += num;
2516 	}
2517 }
2518 
DCsync_items(zbx_dbsync_t * sync,int flags)2519 static void	DCsync_items(zbx_dbsync_t *sync, int flags)
2520 {
2521 	char			**row;
2522 	zbx_uint64_t		rowid;
2523 	unsigned char		tag;
2524 
2525 	ZBX_DC_HOST		*host;
2526 
2527 	ZBX_DC_ITEM		*item;
2528 	ZBX_DC_NUMITEM		*numitem;
2529 	ZBX_DC_SNMPITEM		*snmpitem;
2530 	ZBX_DC_IPMIITEM		*ipmiitem;
2531 	ZBX_DC_TRAPITEM		*trapitem;
2532 	ZBX_DC_DEPENDENTITEM	*depitem;
2533 	ZBX_DC_LOGITEM		*logitem;
2534 	ZBX_DC_DBITEM		*dbitem;
2535 	ZBX_DC_SSHITEM		*sshitem;
2536 	ZBX_DC_TELNETITEM	*telnetitem;
2537 	ZBX_DC_SIMPLEITEM	*simpleitem;
2538 	ZBX_DC_JMXITEM		*jmxitem;
2539 	ZBX_DC_CALCITEM		*calcitem;
2540 	ZBX_DC_INTERFACE_ITEM	*interface_snmpitem;
2541 	ZBX_DC_MASTERITEM	*master;
2542 	ZBX_DC_PREPROCITEM	*preprocitem;
2543 	ZBX_DC_HTTPITEM		*httpitem;
2544 	ZBX_DC_ITEM_HK		*item_hk, item_hk_local;
2545 
2546 	time_t			now;
2547 	unsigned char		status, type, value_type, old_poller_type;
2548 	int			found, update_index, ret, i,  old_nextcheck;
2549 	zbx_uint64_t		itemid, hostid;
2550 	zbx_vector_ptr_t	dep_items;
2551 
2552 	zbx_vector_ptr_create(&dep_items);
2553 
2554 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2555 
2556 	now = time(NULL);
2557 
2558 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
2559 	{
2560 		/* removed rows will be always added at the end */
2561 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
2562 			break;
2563 
2564 		flags &= ZBX_REFRESH_UNSUPPORTED_CHANGED;
2565 
2566 		ZBX_STR2UINT64(itemid, row[0]);
2567 		ZBX_STR2UINT64(hostid, row[1]);
2568 		ZBX_STR2UCHAR(status, row[2]);
2569 		ZBX_STR2UCHAR(type, row[3]);
2570 
2571 		if (NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
2572 			continue;
2573 
2574 		item = (ZBX_DC_ITEM *)DCfind_id(&config->items, itemid, sizeof(ZBX_DC_ITEM), &found);
2575 
2576 		/* template item */
2577 		ZBX_DBROW2UINT64(item->templateid, row[48]);
2578 
2579 		/* LLD item prototype */
2580 		ZBX_DBROW2UINT64(item->parent_itemid, row[49]);
2581 
2582 		if (0 != found && ITEM_TYPE_SNMPTRAP == item->type)
2583 			dc_interface_snmpitems_remove(item);
2584 
2585 		/* see whether we should and can update items_hk index at this point */
2586 
2587 		update_index = 0;
2588 
2589 		if (0 == found || item->hostid != hostid || 0 != strcmp(item->key, row[5]))
2590 		{
2591 			if (1 == found)
2592 			{
2593 				item_hk_local.hostid = item->hostid;
2594 				item_hk_local.key = item->key;
2595 
2596 				if (NULL == (item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk,
2597 						&item_hk_local)))
2598 				{
2599 					/* item keys should be unique for items within a host, otherwise items with  */
2600 					/* same key share index and removal of last added item already cleared index */
2601 					THIS_SHOULD_NEVER_HAPPEN;
2602 				}
2603 				else if (item == item_hk->item_ptr)
2604 				{
2605 					zbx_strpool_release(item_hk->key);
2606 					zbx_hashset_remove_direct(&config->items_hk, item_hk);
2607 				}
2608 			}
2609 
2610 			item_hk_local.hostid = hostid;
2611 			item_hk_local.key = row[5];
2612 			item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk, &item_hk_local);
2613 
2614 			if (NULL != item_hk)
2615 				item_hk->item_ptr = item;
2616 			else
2617 				update_index = 1;
2618 		}
2619 
2620 		/* store new information in item structure */
2621 
2622 		item->hostid = hostid;
2623 		item->flags = (unsigned char)atoi(row[18]);
2624 		ZBX_DBROW2UINT64(item->interfaceid, row[19]);
2625 
2626 		if (SUCCEED != is_time_suffix(row[22], &item->history_sec, ZBX_LENGTH_UNLIMITED))
2627 			item->history_sec = ZBX_HK_PERIOD_MAX;
2628 
2629 		if (0 != item->history_sec && ZBX_HK_OPTION_ENABLED == config->config->hk.history_global)
2630 			item->history_sec = config->config->hk.history;
2631 
2632 		item->history = (0 != item->history_sec);
2633 
2634 		ZBX_STR2UCHAR(item->inventory_link, row[24]);
2635 		ZBX_DBROW2UINT64(item->valuemapid, row[25]);
2636 
2637 		if (0 != (ZBX_FLAG_DISCOVERY_RULE & item->flags))
2638 			value_type = ITEM_VALUE_TYPE_TEXT;
2639 		else
2640 			ZBX_STR2UCHAR(value_type, row[4]);
2641 
2642 		if (SUCCEED == DCstrpool_replace(found, &item->key, row[5]))
2643 			flags |= ZBX_ITEM_KEY_CHANGED;
2644 
2645 		if (0 == found)
2646 		{
2647 			item->triggers = NULL;
2648 			item->update_triggers = 0;
2649 			item->nextcheck = 0;
2650 			item->lastclock = 0;
2651 			item->state = (unsigned char)atoi(row[12]);
2652 			ZBX_STR2UINT64(item->lastlogsize, row[20]);
2653 			item->mtime = atoi(row[21]);
2654 			DCstrpool_replace(found, &item->error, row[27]);
2655 			item->data_expected_from = now;
2656 			item->location = ZBX_LOC_NOWHERE;
2657 			item->poller_type = ZBX_NO_POLLER;
2658 			item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
2659 			item->schedulable = 1;
2660 		}
2661 		else
2662 		{
2663 			if (item->type != type)
2664 				flags |= ZBX_ITEM_TYPE_CHANGED;
2665 
2666 			if (ITEM_STATUS_ACTIVE == status && ITEM_STATUS_ACTIVE != item->status)
2667 				item->data_expected_from = now;
2668 
2669 			if (ITEM_STATUS_ACTIVE == item->status)
2670 				dc_host_update_agent_stats(host, item->type, -1);
2671 		}
2672 
2673 		if (ITEM_STATUS_ACTIVE == status)
2674 			dc_host_update_agent_stats(host, type, 1);
2675 
2676 		item->type = type;
2677 		item->status = status;
2678 		item->value_type = value_type;
2679 
2680 		/* update items_hk index using new data, if not done already */
2681 
2682 		if (1 == update_index)
2683 		{
2684 			item_hk_local.hostid = item->hostid;
2685 			item_hk_local.key = zbx_strpool_acquire(item->key);
2686 			item_hk_local.item_ptr = item;
2687 			zbx_hashset_insert(&config->items_hk, &item_hk_local, sizeof(ZBX_DC_ITEM_HK));
2688 		}
2689 
2690 		/* process item intervals and update item nextcheck */
2691 
2692 		if (SUCCEED == DCstrpool_replace(found, &item->delay, row[8]))
2693 			flags |= ZBX_ITEM_DELAY_CHANGED;
2694 
2695 		/* numeric items */
2696 
2697 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type || ITEM_VALUE_TYPE_UINT64 == item->value_type)
2698 		{
2699 			int	trends_sec;
2700 
2701 			numitem = (ZBX_DC_NUMITEM *)DCfind_id(&config->numitems, itemid, sizeof(ZBX_DC_NUMITEM), &found);
2702 
2703 			if (SUCCEED != is_time_suffix(row[23], &trends_sec, ZBX_LENGTH_UNLIMITED))
2704 				trends_sec = ZBX_HK_PERIOD_MAX;
2705 
2706 			if (0 != trends_sec && ZBX_HK_OPTION_ENABLED == config->config->hk.trends_global)
2707 				trends_sec = config->config->hk.trends;
2708 
2709 			numitem->trends = (0 != trends_sec);
2710 			numitem->trends_sec = trends_sec;
2711 
2712 			DCstrpool_replace(found, &numitem->units, row[26]);
2713 		}
2714 		else if (NULL != (numitem = (ZBX_DC_NUMITEM *)zbx_hashset_search(&config->numitems, &itemid)))
2715 		{
2716 			/* remove parameters for non-numeric item */
2717 
2718 			zbx_strpool_release(numitem->units);
2719 
2720 			zbx_hashset_remove_direct(&config->numitems, numitem);
2721 		}
2722 
2723 		/* SNMP items */
2724 
2725 		if (ITEM_TYPE_SNMP == item->type)
2726 		{
2727 			snmpitem = (ZBX_DC_SNMPITEM *)DCfind_id(&config->snmpitems, itemid, sizeof(ZBX_DC_SNMPITEM), &found);
2728 
2729 			if (SUCCEED == DCstrpool_replace(found, &snmpitem->snmp_oid, row[6]))
2730 			{
2731 				if (NULL != strchr(snmpitem->snmp_oid, '{'))
2732 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_MACRO;
2733 				else if (NULL != strchr(snmpitem->snmp_oid, '['))
2734 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_DYNAMIC;
2735 				else
2736 					snmpitem->snmp_oid_type = ZBX_SNMP_OID_TYPE_NORMAL;
2737 			}
2738 		}
2739 		else if (NULL != (snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &itemid)))
2740 		{
2741 			/* remove SNMP parameters for non-SNMP item */
2742 
2743 			zbx_strpool_release(snmpitem->snmp_oid);
2744 			zbx_hashset_remove_direct(&config->snmpitems, snmpitem);
2745 		}
2746 
2747 		/* IPMI items */
2748 
2749 		if (ITEM_TYPE_IPMI == item->type)
2750 		{
2751 			ipmiitem = (ZBX_DC_IPMIITEM *)DCfind_id(&config->ipmiitems, itemid, sizeof(ZBX_DC_IPMIITEM), &found);
2752 
2753 			DCstrpool_replace(found, &ipmiitem->ipmi_sensor, row[7]);
2754 		}
2755 		else if (NULL != (ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &itemid)))
2756 		{
2757 			/* remove IPMI parameters for non-IPMI item */
2758 			zbx_strpool_release(ipmiitem->ipmi_sensor);
2759 			zbx_hashset_remove_direct(&config->ipmiitems, ipmiitem);
2760 		}
2761 
2762 		/* trapper items */
2763 
2764 		if (ITEM_TYPE_TRAPPER == item->type && '\0' != *row[9])
2765 		{
2766 			trapitem = (ZBX_DC_TRAPITEM *)DCfind_id(&config->trapitems, itemid, sizeof(ZBX_DC_TRAPITEM), &found);
2767 			DCstrpool_replace(found, &trapitem->trapper_hosts, row[9]);
2768 		}
2769 		else if (NULL != (trapitem = (ZBX_DC_TRAPITEM *)zbx_hashset_search(&config->trapitems, &itemid)))
2770 		{
2771 			/* remove trapper_hosts parameter */
2772 			zbx_strpool_release(trapitem->trapper_hosts);
2773 			zbx_hashset_remove_direct(&config->trapitems, trapitem);
2774 		}
2775 
2776 		/* dependent items */
2777 
2778 		if (ITEM_TYPE_DEPENDENT == item->type && SUCCEED != DBis_null(row[29]))
2779 		{
2780 			depitem = (ZBX_DC_DEPENDENTITEM *)DCfind_id(&config->dependentitems, itemid,
2781 					sizeof(ZBX_DC_DEPENDENTITEM), &found);
2782 
2783 			if (1 == found)
2784 				depitem->last_master_itemid = depitem->master_itemid;
2785 			else
2786 				depitem->last_master_itemid = 0;
2787 
2788 			depitem->flags = item->flags;
2789 			ZBX_STR2UINT64(depitem->master_itemid, row[29]);
2790 
2791 			if (depitem->last_master_itemid != depitem->master_itemid)
2792 				zbx_vector_ptr_append(&dep_items, depitem);
2793 		}
2794 		else if (NULL != (depitem = (ZBX_DC_DEPENDENTITEM *)zbx_hashset_search(&config->dependentitems, &itemid)))
2795 		{
2796 			dc_masteritem_remove_depitem(depitem->master_itemid, itemid);
2797 			zbx_hashset_remove_direct(&config->dependentitems, depitem);
2798 		}
2799 
2800 		/* log items */
2801 
2802 		if (ITEM_VALUE_TYPE_LOG == item->value_type && '\0' != *row[10])
2803 		{
2804 			logitem = (ZBX_DC_LOGITEM *)DCfind_id(&config->logitems, itemid, sizeof(ZBX_DC_LOGITEM), &found);
2805 
2806 			DCstrpool_replace(found, &logitem->logtimefmt, row[10]);
2807 		}
2808 		else if (NULL != (logitem = (ZBX_DC_LOGITEM *)zbx_hashset_search(&config->logitems, &itemid)))
2809 		{
2810 			/* remove logtimefmt parameter */
2811 			zbx_strpool_release(logitem->logtimefmt);
2812 			zbx_hashset_remove_direct(&config->logitems, logitem);
2813 		}
2814 
2815 		/* db items */
2816 
2817 		if (ITEM_TYPE_DB_MONITOR == item->type && '\0' != *row[11])
2818 		{
2819 			dbitem = (ZBX_DC_DBITEM *)DCfind_id(&config->dbitems, itemid, sizeof(ZBX_DC_DBITEM), &found);
2820 
2821 			DCstrpool_replace(found, &dbitem->params, row[11]);
2822 			DCstrpool_replace(found, &dbitem->username, row[14]);
2823 			DCstrpool_replace(found, &dbitem->password, row[15]);
2824 		}
2825 		else if (NULL != (dbitem = (ZBX_DC_DBITEM *)zbx_hashset_search(&config->dbitems, &itemid)))
2826 		{
2827 			/* remove db item parameters */
2828 			zbx_strpool_release(dbitem->params);
2829 			zbx_strpool_release(dbitem->username);
2830 			zbx_strpool_release(dbitem->password);
2831 
2832 			zbx_hashset_remove_direct(&config->dbitems, dbitem);
2833 		}
2834 
2835 		/* SSH items */
2836 
2837 		if (ITEM_TYPE_SSH == item->type)
2838 		{
2839 			sshitem = (ZBX_DC_SSHITEM *)DCfind_id(&config->sshitems, itemid, sizeof(ZBX_DC_SSHITEM), &found);
2840 
2841 			sshitem->authtype = (unsigned short)atoi(row[13]);
2842 			DCstrpool_replace(found, &sshitem->username, row[14]);
2843 			DCstrpool_replace(found, &sshitem->password, row[15]);
2844 			DCstrpool_replace(found, &sshitem->publickey, row[16]);
2845 			DCstrpool_replace(found, &sshitem->privatekey, row[17]);
2846 			DCstrpool_replace(found, &sshitem->params, row[11]);
2847 		}
2848 		else if (NULL != (sshitem = (ZBX_DC_SSHITEM *)zbx_hashset_search(&config->sshitems, &itemid)))
2849 		{
2850 			/* remove SSH item parameters */
2851 
2852 			zbx_strpool_release(sshitem->username);
2853 			zbx_strpool_release(sshitem->password);
2854 			zbx_strpool_release(sshitem->publickey);
2855 			zbx_strpool_release(sshitem->privatekey);
2856 			zbx_strpool_release(sshitem->params);
2857 
2858 			zbx_hashset_remove_direct(&config->sshitems, sshitem);
2859 		}
2860 
2861 		/* TELNET items */
2862 
2863 		if (ITEM_TYPE_TELNET == item->type)
2864 		{
2865 			telnetitem = (ZBX_DC_TELNETITEM *)DCfind_id(&config->telnetitems, itemid, sizeof(ZBX_DC_TELNETITEM), &found);
2866 
2867 			DCstrpool_replace(found, &telnetitem->username, row[14]);
2868 			DCstrpool_replace(found, &telnetitem->password, row[15]);
2869 			DCstrpool_replace(found, &telnetitem->params, row[11]);
2870 		}
2871 		else if (NULL != (telnetitem = (ZBX_DC_TELNETITEM *)zbx_hashset_search(&config->telnetitems, &itemid)))
2872 		{
2873 			/* remove TELNET item parameters */
2874 
2875 			zbx_strpool_release(telnetitem->username);
2876 			zbx_strpool_release(telnetitem->password);
2877 			zbx_strpool_release(telnetitem->params);
2878 
2879 			zbx_hashset_remove_direct(&config->telnetitems, telnetitem);
2880 		}
2881 
2882 		/* simple items */
2883 
2884 		if (ITEM_TYPE_SIMPLE == item->type)
2885 		{
2886 			simpleitem = (ZBX_DC_SIMPLEITEM *)DCfind_id(&config->simpleitems, itemid, sizeof(ZBX_DC_SIMPLEITEM), &found);
2887 
2888 			DCstrpool_replace(found, &simpleitem->username, row[14]);
2889 			DCstrpool_replace(found, &simpleitem->password, row[15]);
2890 		}
2891 		else if (NULL != (simpleitem = (ZBX_DC_SIMPLEITEM *)zbx_hashset_search(&config->simpleitems, &itemid)))
2892 		{
2893 			/* remove simple item parameters */
2894 
2895 			zbx_strpool_release(simpleitem->username);
2896 			zbx_strpool_release(simpleitem->password);
2897 
2898 			zbx_hashset_remove_direct(&config->simpleitems, simpleitem);
2899 		}
2900 
2901 		/* JMX items */
2902 
2903 		if (ITEM_TYPE_JMX == item->type)
2904 		{
2905 			jmxitem = (ZBX_DC_JMXITEM *)DCfind_id(&config->jmxitems, itemid, sizeof(ZBX_DC_JMXITEM), &found);
2906 
2907 			DCstrpool_replace(found, &jmxitem->username, row[14]);
2908 			DCstrpool_replace(found, &jmxitem->password, row[15]);
2909 			DCstrpool_replace(found, &jmxitem->jmx_endpoint, row[28]);
2910 		}
2911 		else if (NULL != (jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &itemid)))
2912 		{
2913 			/* remove JMX item parameters */
2914 
2915 			zbx_strpool_release(jmxitem->username);
2916 			zbx_strpool_release(jmxitem->password);
2917 			zbx_strpool_release(jmxitem->jmx_endpoint);
2918 
2919 			zbx_hashset_remove_direct(&config->jmxitems, jmxitem);
2920 		}
2921 
2922 		/* SNMP trap items for current server/proxy */
2923 
2924 		if (ITEM_TYPE_SNMPTRAP == item->type && 0 == host->proxy_hostid)
2925 		{
2926 			interface_snmpitem = (ZBX_DC_INTERFACE_ITEM *)DCfind_id(&config->interface_snmpitems,
2927 					item->interfaceid, sizeof(ZBX_DC_INTERFACE_ITEM), &found);
2928 
2929 			if (0 == found)
2930 			{
2931 				zbx_vector_uint64_create_ext(&interface_snmpitem->itemids,
2932 						__config_mem_malloc_func,
2933 						__config_mem_realloc_func,
2934 						__config_mem_free_func);
2935 			}
2936 
2937 			zbx_vector_uint64_append(&interface_snmpitem->itemids, itemid);
2938 		}
2939 
2940 		/* calculated items */
2941 
2942 		if (ITEM_TYPE_CALCULATED == item->type)
2943 		{
2944 			calcitem = (ZBX_DC_CALCITEM *)DCfind_id(&config->calcitems, itemid, sizeof(ZBX_DC_CALCITEM), &found);
2945 
2946 			DCstrpool_replace(found, &calcitem->params, row[11]);
2947 		}
2948 		else if (NULL != (calcitem = (ZBX_DC_CALCITEM *)zbx_hashset_search(&config->calcitems, &itemid)))
2949 		{
2950 			/* remove calculated item parameters */
2951 
2952 			zbx_strpool_release(calcitem->params);
2953 			zbx_hashset_remove_direct(&config->calcitems, calcitem);
2954 		}
2955 
2956 		/* HTTP agent items */
2957 
2958 		if (ITEM_TYPE_HTTPAGENT == item->type)
2959 		{
2960 			httpitem = (ZBX_DC_HTTPITEM *)DCfind_id(&config->httpitems, itemid, sizeof(ZBX_DC_HTTPITEM),
2961 					&found);
2962 
2963 			DCstrpool_replace(found, &httpitem->timeout, row[30]);
2964 			DCstrpool_replace(found, &httpitem->url, row[31]);
2965 			DCstrpool_replace(found, &httpitem->query_fields, row[32]);
2966 			DCstrpool_replace(found, &httpitem->posts, row[33]);
2967 			DCstrpool_replace(found, &httpitem->status_codes, row[34]);
2968 			httpitem->follow_redirects = (unsigned char)atoi(row[35]);
2969 			httpitem->post_type = (unsigned char)atoi(row[36]);
2970 			DCstrpool_replace(found, &httpitem->http_proxy, row[37]);
2971 			DCstrpool_replace(found, &httpitem->headers, row[38]);
2972 			httpitem->retrieve_mode = (unsigned char)atoi(row[39]);
2973 			httpitem->request_method = (unsigned char)atoi(row[40]);
2974 			httpitem->output_format = (unsigned char)atoi(row[41]);
2975 			DCstrpool_replace(found, &httpitem->ssl_cert_file, row[42]);
2976 			DCstrpool_replace(found, &httpitem->ssl_key_file, row[43]);
2977 			DCstrpool_replace(found, &httpitem->ssl_key_password, row[44]);
2978 			httpitem->verify_peer = (unsigned char)atoi(row[45]);
2979 			httpitem->verify_host = (unsigned char)atoi(row[46]);
2980 			httpitem->allow_traps = (unsigned char)atoi(row[47]);
2981 
2982 			httpitem->authtype = (unsigned char)atoi(row[13]);
2983 			DCstrpool_replace(found, &httpitem->username, row[14]);
2984 			DCstrpool_replace(found, &httpitem->password, row[15]);
2985 			DCstrpool_replace(found, &httpitem->trapper_hosts, row[9]);
2986 		}
2987 		else if (NULL != (httpitem = (ZBX_DC_HTTPITEM *)zbx_hashset_search(&config->httpitems, &itemid)))
2988 		{
2989 			zbx_strpool_release(httpitem->timeout);
2990 			zbx_strpool_release(httpitem->url);
2991 			zbx_strpool_release(httpitem->query_fields);
2992 			zbx_strpool_release(httpitem->posts);
2993 			zbx_strpool_release(httpitem->status_codes);
2994 			zbx_strpool_release(httpitem->http_proxy);
2995 			zbx_strpool_release(httpitem->headers);
2996 			zbx_strpool_release(httpitem->ssl_cert_file);
2997 			zbx_strpool_release(httpitem->ssl_key_file);
2998 			zbx_strpool_release(httpitem->ssl_key_password);
2999 			zbx_strpool_release(httpitem->username);
3000 			zbx_strpool_release(httpitem->password);
3001 			zbx_strpool_release(httpitem->trapper_hosts);
3002 
3003 			zbx_hashset_remove_direct(&config->httpitems, httpitem);
3004 		}
3005 
3006 		/* it is crucial to update type specific (config->snmpitems, config->ipmiitems, etc.) hashsets before */
3007 		/* attempting to requeue an item because type specific properties are used to arrange items in queues */
3008 
3009 		old_poller_type = item->poller_type;
3010 		old_nextcheck = item->nextcheck;
3011 
3012 		if (ITEM_STATUS_ACTIVE == item->status && HOST_STATUS_MONITORED == host->status)
3013 		{
3014 			DCitem_poller_type_update(item, host, flags);
3015 
3016 			if (SUCCEED == zbx_is_counted_in_item_queue(item->type, item->key))
3017 			{
3018 				char	*error = NULL;
3019 
3020 				if (FAIL == DCitem_nextcheck_update(item, host, item->state, flags, now, &error))
3021 				{
3022 					zbx_timespec_t	ts = {now, 0};
3023 
3024 					/* Usual way for an item to become not supported is to receive an error     */
3025 					/* instead of value. Item state and error will be updated by history syncer */
3026 					/* during history sync following a regular procedure with item update in    */
3027 					/* database and config cache, logging etc. There is no need to set          */
3028 					/* ITEM_STATE_NOTSUPPORTED here.                                            */
3029 
3030 					if (0 == host->proxy_hostid)
3031 					{
3032 						dc_add_history(item->itemid, item->value_type, 0, NULL, &ts,
3033 								ITEM_STATE_NOTSUPPORTED, error);
3034 					}
3035 					zbx_free(error);
3036 				}
3037 			}
3038 		}
3039 		else
3040 		{
3041 			item->nextcheck = 0;
3042 			item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
3043 			item->poller_type = ZBX_NO_POLLER;
3044 		}
3045 
3046 		DCupdate_item_queue(item, old_poller_type, old_nextcheck);
3047 	}
3048 
3049 	/* update dependent item vectors within master items */
3050 
3051 	for (i = 0; i < dep_items.values_num; i++)
3052 	{
3053 		zbx_uint64_pair_t	pair;
3054 
3055 		depitem = (ZBX_DC_DEPENDENTITEM *)dep_items.values[i];
3056 		dc_masteritem_remove_depitem(depitem->last_master_itemid, depitem->itemid);
3057 		pair.first = depitem->itemid;
3058 		pair.second = depitem->flags;
3059 
3060 		/* append item to dependent item vector of master item */
3061 		if (NULL == (master = (ZBX_DC_MASTERITEM *)zbx_hashset_search(&config->masteritems, &depitem->master_itemid)))
3062 		{
3063 			ZBX_DC_MASTERITEM	master_local;
3064 
3065 			master_local.itemid = depitem->master_itemid;
3066 			master = (ZBX_DC_MASTERITEM *)zbx_hashset_insert(&config->masteritems, &master_local, sizeof(master_local));
3067 
3068 			zbx_vector_uint64_pair_create_ext(&master->dep_itemids, __config_mem_malloc_func,
3069 					__config_mem_realloc_func, __config_mem_free_func);
3070 		}
3071 
3072 		zbx_vector_uint64_pair_append(&master->dep_itemids, pair);
3073 	}
3074 
3075 	zbx_vector_ptr_destroy(&dep_items);
3076 
3077 	/* remove deleted items from buffer */
3078 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3079 	{
3080 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &rowid)))
3081 			continue;
3082 
3083 		if (ITEM_STATUS_ACTIVE == item->status &&
3084 				NULL != (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->hostid)))
3085 		{
3086 			dc_host_update_agent_stats(host, item->type, -1);
3087 		}
3088 
3089 		itemid = item->itemid;
3090 
3091 		if (ITEM_TYPE_SNMPTRAP == item->type)
3092 			dc_interface_snmpitems_remove(item);
3093 
3094 		/* numeric items */
3095 
3096 		if (ITEM_VALUE_TYPE_FLOAT == item->value_type || ITEM_VALUE_TYPE_UINT64 == item->value_type)
3097 		{
3098 			numitem = (ZBX_DC_NUMITEM *)zbx_hashset_search(&config->numitems, &itemid);
3099 
3100 			zbx_strpool_release(numitem->units);
3101 
3102 			zbx_hashset_remove_direct(&config->numitems, numitem);
3103 		}
3104 
3105 		/* SNMP items */
3106 
3107 		if (ITEM_TYPE_SNMP == item->type)
3108 		{
3109 			snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &itemid);
3110 			zbx_strpool_release(snmpitem->snmp_oid);
3111 			zbx_hashset_remove_direct(&config->snmpitems, snmpitem);
3112 		}
3113 
3114 		/* IPMI items */
3115 
3116 		if (ITEM_TYPE_IPMI == item->type)
3117 		{
3118 			ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &itemid);
3119 			zbx_strpool_release(ipmiitem->ipmi_sensor);
3120 			zbx_hashset_remove_direct(&config->ipmiitems, ipmiitem);
3121 		}
3122 
3123 		/* trapper items */
3124 
3125 		if (ITEM_TYPE_TRAPPER == item->type &&
3126 				NULL != (trapitem = (ZBX_DC_TRAPITEM *)zbx_hashset_search(&config->trapitems, &itemid)))
3127 		{
3128 			zbx_strpool_release(trapitem->trapper_hosts);
3129 			zbx_hashset_remove_direct(&config->trapitems, trapitem);
3130 		}
3131 
3132 		/* dependent items */
3133 
3134 		if (NULL != (depitem = (ZBX_DC_DEPENDENTITEM *)zbx_hashset_search(&config->dependentitems, &itemid)))
3135 		{
3136 			dc_masteritem_remove_depitem(depitem->master_itemid, itemid);
3137 			zbx_hashset_remove_direct(&config->dependentitems, depitem);
3138 		}
3139 
3140 		/* log items */
3141 
3142 		if (ITEM_VALUE_TYPE_LOG == item->value_type &&
3143 				NULL != (logitem = (ZBX_DC_LOGITEM *)zbx_hashset_search(&config->logitems, &itemid)))
3144 		{
3145 			zbx_strpool_release(logitem->logtimefmt);
3146 			zbx_hashset_remove_direct(&config->logitems, logitem);
3147 		}
3148 
3149 		/* db items */
3150 
3151 		if (ITEM_TYPE_DB_MONITOR == item->type &&
3152 				NULL != (dbitem = (ZBX_DC_DBITEM *)zbx_hashset_search(&config->dbitems, &itemid)))
3153 		{
3154 			zbx_strpool_release(dbitem->params);
3155 			zbx_strpool_release(dbitem->username);
3156 			zbx_strpool_release(dbitem->password);
3157 
3158 			zbx_hashset_remove_direct(&config->dbitems, dbitem);
3159 		}
3160 
3161 		/* SSH items */
3162 
3163 		if (ITEM_TYPE_SSH == item->type)
3164 		{
3165 			sshitem = (ZBX_DC_SSHITEM *)zbx_hashset_search(&config->sshitems, &itemid);
3166 
3167 			zbx_strpool_release(sshitem->username);
3168 			zbx_strpool_release(sshitem->password);
3169 			zbx_strpool_release(sshitem->publickey);
3170 			zbx_strpool_release(sshitem->privatekey);
3171 			zbx_strpool_release(sshitem->params);
3172 
3173 			zbx_hashset_remove_direct(&config->sshitems, sshitem);
3174 		}
3175 
3176 		/* TELNET items */
3177 
3178 		if (ITEM_TYPE_TELNET == item->type)
3179 		{
3180 			telnetitem = (ZBX_DC_TELNETITEM *)zbx_hashset_search(&config->telnetitems, &itemid);
3181 
3182 			zbx_strpool_release(telnetitem->username);
3183 			zbx_strpool_release(telnetitem->password);
3184 			zbx_strpool_release(telnetitem->params);
3185 
3186 			zbx_hashset_remove_direct(&config->telnetitems, telnetitem);
3187 		}
3188 
3189 		/* simple items */
3190 
3191 		if (ITEM_TYPE_SIMPLE == item->type)
3192 		{
3193 			simpleitem = (ZBX_DC_SIMPLEITEM *)zbx_hashset_search(&config->simpleitems, &itemid);
3194 
3195 			zbx_strpool_release(simpleitem->username);
3196 			zbx_strpool_release(simpleitem->password);
3197 
3198 			zbx_hashset_remove_direct(&config->simpleitems, simpleitem);
3199 		}
3200 
3201 		/* JMX items */
3202 
3203 		if (ITEM_TYPE_JMX == item->type)
3204 		{
3205 			jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &itemid);
3206 
3207 			zbx_strpool_release(jmxitem->username);
3208 			zbx_strpool_release(jmxitem->password);
3209 			zbx_strpool_release(jmxitem->jmx_endpoint);
3210 
3211 			zbx_hashset_remove_direct(&config->jmxitems, jmxitem);
3212 		}
3213 
3214 		/* calculated items */
3215 
3216 		if (ITEM_TYPE_CALCULATED == item->type)
3217 		{
3218 			calcitem = (ZBX_DC_CALCITEM *)zbx_hashset_search(&config->calcitems, &itemid);
3219 			zbx_strpool_release(calcitem->params);
3220 			zbx_hashset_remove_direct(&config->calcitems, calcitem);
3221 		}
3222 
3223 		/* HTTP agent items */
3224 
3225 		if (ITEM_TYPE_HTTPAGENT == item->type)
3226 		{
3227 			httpitem = (ZBX_DC_HTTPITEM *)zbx_hashset_search(&config->httpitems, &itemid);
3228 
3229 			zbx_strpool_release(httpitem->timeout);
3230 			zbx_strpool_release(httpitem->url);
3231 			zbx_strpool_release(httpitem->query_fields);
3232 			zbx_strpool_release(httpitem->posts);
3233 			zbx_strpool_release(httpitem->status_codes);
3234 			zbx_strpool_release(httpitem->http_proxy);
3235 			zbx_strpool_release(httpitem->headers);
3236 			zbx_strpool_release(httpitem->ssl_cert_file);
3237 			zbx_strpool_release(httpitem->ssl_key_file);
3238 			zbx_strpool_release(httpitem->ssl_key_password);
3239 			zbx_strpool_release(httpitem->username);
3240 			zbx_strpool_release(httpitem->password);
3241 			zbx_strpool_release(httpitem->trapper_hosts);
3242 
3243 			zbx_hashset_remove_direct(&config->httpitems, httpitem);
3244 		}
3245 
3246 		/* items */
3247 
3248 		item_hk_local.hostid = item->hostid;
3249 		item_hk_local.key = item->key;
3250 
3251 		if (NULL == (item_hk = (ZBX_DC_ITEM_HK *)zbx_hashset_search(&config->items_hk, &item_hk_local)))
3252 		{
3253 			/* item keys should be unique for items within a host, otherwise items with  */
3254 			/* same key share index and removal of last added item already cleared index */
3255 			THIS_SHOULD_NEVER_HAPPEN;
3256 		}
3257 		else if (item == item_hk->item_ptr)
3258 		{
3259 			zbx_strpool_release(item_hk->key);
3260 			zbx_hashset_remove_direct(&config->items_hk, item_hk);
3261 		}
3262 
3263 		if (ZBX_LOC_QUEUE == item->location)
3264 			zbx_binary_heap_remove_direct(&config->queues[item->poller_type], item->itemid);
3265 
3266 		zbx_strpool_release(item->key);
3267 		zbx_strpool_release(item->error);
3268 		zbx_strpool_release(item->delay);
3269 
3270 		if (NULL != item->triggers)
3271 			config->items.mem_free_func(item->triggers);
3272 
3273 		if (NULL != (preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_search(&config->preprocitems, &item->itemid)))
3274 		{
3275 			zbx_vector_ptr_destroy(&preprocitem->preproc_ops);
3276 			zbx_hashset_remove_direct(&config->preprocitems, preprocitem);
3277 		}
3278 
3279 		zbx_hashset_remove_direct(&config->items, item);
3280 	}
3281 
3282 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3283 }
3284 
DCsync_template_items(zbx_dbsync_t * sync)3285 static void	DCsync_template_items(zbx_dbsync_t *sync)
3286 {
3287 	char			**row;
3288 	zbx_uint64_t		rowid, itemid;
3289 	unsigned char		tag;
3290 	int			ret, found;
3291 	ZBX_DC_TEMPLATE_ITEM 	*item;
3292 
3293 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3294 
3295 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3296 	{
3297 		/* removed rows will be always added at the end */
3298 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3299 			break;
3300 
3301 		ZBX_STR2UINT64(itemid, row[0]);
3302 		item = (ZBX_DC_TEMPLATE_ITEM *)DCfind_id(&config->template_items, itemid, sizeof(ZBX_DC_TEMPLATE_ITEM),
3303 				&found);
3304 
3305 		ZBX_STR2UINT64(item->hostid, row[1]);
3306 		ZBX_DBROW2UINT64(item->templateid, row[2]);
3307 	}
3308 
3309 	/* remove deleted template items from buffer */
3310 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3311 	{
3312 		if (NULL == (item = (ZBX_DC_TEMPLATE_ITEM *)zbx_hashset_search(&config->template_items, &rowid)))
3313 			continue;
3314 
3315 		zbx_hashset_remove_direct(&config->template_items, item);
3316 	}
3317 
3318 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3319 }
3320 
DCsync_prototype_items(zbx_dbsync_t * sync)3321 static void	DCsync_prototype_items(zbx_dbsync_t *sync)
3322 {
3323 	char			**row;
3324 	zbx_uint64_t		rowid, itemid;
3325 	unsigned char		tag;
3326 	int			ret, found;
3327 	ZBX_DC_PROTOTYPE_ITEM 	*item;
3328 
3329 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3330 
3331 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3332 	{
3333 		/* removed rows will be always added at the end */
3334 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3335 			break;
3336 
3337 		ZBX_STR2UINT64(itemid, row[0]);
3338 		item = (ZBX_DC_PROTOTYPE_ITEM *)DCfind_id(&config->prototype_items, itemid,
3339 				sizeof(ZBX_DC_PROTOTYPE_ITEM), &found);
3340 
3341 		ZBX_STR2UINT64(item->hostid, row[1]);
3342 		ZBX_DBROW2UINT64(item->templateid, row[2]);
3343 	}
3344 
3345 	/* remove deleted prototype items from buffer */
3346 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3347 	{
3348 		if (NULL == (item = (ZBX_DC_PROTOTYPE_ITEM *)zbx_hashset_search(&config->prototype_items, &rowid)))
3349 			continue;
3350 
3351 		zbx_hashset_remove_direct(&config->prototype_items, item);
3352 	}
3353 
3354 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3355 }
3356 
DCsync_triggers(zbx_dbsync_t * sync)3357 static void	DCsync_triggers(zbx_dbsync_t *sync)
3358 {
3359 	char		**row;
3360 	zbx_uint64_t	rowid;
3361 	unsigned char	tag;
3362 
3363 	ZBX_DC_TRIGGER	*trigger;
3364 
3365 	int		found, ret;
3366 	zbx_uint64_t	triggerid;
3367 
3368 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3369 
3370 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3371 	{
3372 		/* removed rows will be always added at the end */
3373 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3374 			break;
3375 
3376 		ZBX_STR2UINT64(triggerid, row[0]);
3377 
3378 		trigger = (ZBX_DC_TRIGGER *)DCfind_id(&config->triggers, triggerid, sizeof(ZBX_DC_TRIGGER), &found);
3379 
3380 		/* store new information in trigger structure */
3381 
3382 		DCstrpool_replace(found, &trigger->description, row[1]);
3383 		DCstrpool_replace(found, &trigger->expression, row[2]);
3384 		DCstrpool_replace(found, &trigger->recovery_expression, row[11]);
3385 		DCstrpool_replace(found, &trigger->correlation_tag, row[13]);
3386 		DCstrpool_replace(found, &trigger->opdata, row[14]);
3387 		ZBX_STR2UCHAR(trigger->priority, row[4]);
3388 		ZBX_STR2UCHAR(trigger->type, row[5]);
3389 		ZBX_STR2UCHAR(trigger->status, row[9]);
3390 		ZBX_STR2UCHAR(trigger->recovery_mode, row[10]);
3391 		ZBX_STR2UCHAR(trigger->correlation_mode, row[12]);
3392 
3393 		if (0 == found)
3394 		{
3395 			DCstrpool_replace(found, &trigger->error, row[3]);
3396 			ZBX_STR2UCHAR(trigger->value, row[6]);
3397 			ZBX_STR2UCHAR(trigger->state, row[7]);
3398 			trigger->lastchange = atoi(row[8]);
3399 			trigger->locked = 0;
3400 
3401 			zbx_vector_ptr_create_ext(&trigger->tags, __config_mem_malloc_func, __config_mem_realloc_func,
3402 					__config_mem_free_func);
3403 			trigger->topoindex = 1;
3404 		}
3405 	}
3406 
3407 	/* remove deleted triggers from buffer */
3408 	if (SUCCEED == ret)
3409 	{
3410 		zbx_vector_uint64_t	functionids;
3411 		int			i;
3412 		ZBX_DC_ITEM		*item;
3413 		ZBX_DC_FUNCTION		*function;
3414 
3415 		zbx_vector_uint64_create(&functionids);
3416 
3417 		for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3418 		{
3419 			if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &rowid)))
3420 				continue;
3421 
3422 			/* force trigger list update for items used in removed trigger */
3423 
3424 			get_functionids(&functionids, trigger->expression);
3425 
3426 			if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode)
3427 				get_functionids(&functionids, trigger->recovery_expression);
3428 
3429 			for (i = 0; i < functionids.values_num; i++)
3430 			{
3431 				if (NULL == (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids.values[i])))
3432 					continue;
3433 
3434 				if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
3435 					continue;
3436 
3437 				item->update_triggers = 1;
3438 				if (NULL != item->triggers)
3439 				{
3440 					config->items.mem_free_func(item->triggers);
3441 					item->triggers = NULL;
3442 				}
3443 			}
3444 			zbx_vector_uint64_clear(&functionids);
3445 
3446 			zbx_strpool_release(trigger->description);
3447 			zbx_strpool_release(trigger->expression);
3448 			zbx_strpool_release(trigger->recovery_expression);
3449 			zbx_strpool_release(trigger->error);
3450 			zbx_strpool_release(trigger->correlation_tag);
3451 			zbx_strpool_release(trigger->opdata);
3452 
3453 			zbx_vector_ptr_destroy(&trigger->tags);
3454 
3455 			zbx_hashset_remove_direct(&config->triggers, trigger);
3456 		}
3457 		zbx_vector_uint64_destroy(&functionids);
3458 	}
3459 
3460 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3461 }
3462 
3463 static void	DCconfig_sort_triggers_topologically(void);
3464 
3465 /******************************************************************************
3466  *                                                                            *
3467  * Function: dc_trigger_deplist_release                                       *
3468  *                                                                            *
3469  * Purpose: releases trigger dependency list, removing it if necessary        *
3470  *                                                                            *
3471  ******************************************************************************/
dc_trigger_deplist_release(ZBX_DC_TRIGGER_DEPLIST * trigdep)3472 static int	dc_trigger_deplist_release(ZBX_DC_TRIGGER_DEPLIST *trigdep)
3473 {
3474 	if (0 == --trigdep->refcount)
3475 	{
3476 		zbx_vector_ptr_destroy(&trigdep->dependencies);
3477 		zbx_hashset_remove_direct(&config->trigdeps, trigdep);
3478 		return SUCCEED;
3479 	}
3480 
3481 	return FAIL;
3482 }
3483 
3484 /******************************************************************************
3485  *                                                                            *
3486  * Function: dc_trigger_deplist_init                                          *
3487  *                                                                            *
3488  * Purpose: initializes trigger dependency list                               *
3489  *                                                                            *
3490  ******************************************************************************/
dc_trigger_deplist_init(ZBX_DC_TRIGGER_DEPLIST * trigdep,ZBX_DC_TRIGGER * trigger)3491 static void	dc_trigger_deplist_init(ZBX_DC_TRIGGER_DEPLIST *trigdep, ZBX_DC_TRIGGER *trigger)
3492 {
3493 	trigdep->refcount = 1;
3494 	trigdep->trigger = trigger;
3495 	zbx_vector_ptr_create_ext(&trigdep->dependencies, __config_mem_malloc_func, __config_mem_realloc_func,
3496 			__config_mem_free_func);
3497 }
3498 
3499 /******************************************************************************
3500  *                                                                            *
3501  * Function: dc_trigger_deplist_reset                                         *
3502  *                                                                            *
3503  * Purpose: resets trigger dependency list to release memory allocated by     *
3504  *          dependencies vector                                               *
3505  *                                                                            *
3506  ******************************************************************************/
dc_trigger_deplist_reset(ZBX_DC_TRIGGER_DEPLIST * trigdep)3507 static void	dc_trigger_deplist_reset(ZBX_DC_TRIGGER_DEPLIST *trigdep)
3508 {
3509 	zbx_vector_ptr_destroy(&trigdep->dependencies);
3510 	zbx_vector_ptr_create_ext(&trigdep->dependencies, __config_mem_malloc_func, __config_mem_realloc_func,
3511 			__config_mem_free_func);
3512 }
3513 
DCsync_trigdeps(zbx_dbsync_t * sync)3514 static void	DCsync_trigdeps(zbx_dbsync_t *sync)
3515 {
3516 	char			**row;
3517 	zbx_uint64_t		rowid;
3518 	unsigned char		tag;
3519 
3520 	ZBX_DC_TRIGGER_DEPLIST	*trigdep_down, *trigdep_up;
3521 
3522 	int			found, index, ret;
3523 	zbx_uint64_t		triggerid_down, triggerid_up;
3524 	ZBX_DC_TRIGGER		*trigger_up, *trigger_down;
3525 
3526 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3527 
3528 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3529 	{
3530 		/* removed rows will be always added at the end */
3531 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3532 			break;
3533 
3534 		/* find trigdep_down pointer */
3535 
3536 		ZBX_STR2UINT64(triggerid_down, row[0]);
3537 		if (NULL == (trigger_down = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerid_down)))
3538 			continue;
3539 
3540 		ZBX_STR2UINT64(triggerid_up, row[1]);
3541 		if (NULL == (trigger_up = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerid_up)))
3542 			continue;
3543 
3544 		trigdep_down = (ZBX_DC_TRIGGER_DEPLIST *)DCfind_id(&config->trigdeps, triggerid_down, sizeof(ZBX_DC_TRIGGER_DEPLIST), &found);
3545 		if (0 == found)
3546 			dc_trigger_deplist_init(trigdep_down, trigger_down);
3547 		else
3548 			trigdep_down->refcount++;
3549 
3550 		trigdep_up = (ZBX_DC_TRIGGER_DEPLIST *)DCfind_id(&config->trigdeps, triggerid_up, sizeof(ZBX_DC_TRIGGER_DEPLIST), &found);
3551 		if (0 == found)
3552 			dc_trigger_deplist_init(trigdep_up, trigger_up);
3553 		else
3554 			trigdep_up->refcount++;
3555 
3556 		zbx_vector_ptr_append(&trigdep_down->dependencies, trigdep_up);
3557 	}
3558 
3559 	/* remove deleted trigger dependencies from buffer */
3560 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3561 	{
3562 		ZBX_STR2UINT64(triggerid_down, row[0]);
3563 		if (NULL == (trigdep_down = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps,
3564 				&triggerid_down)))
3565 		{
3566 			continue;
3567 		}
3568 
3569 		ZBX_STR2UINT64(triggerid_up, row[1]);
3570 		if (NULL != (trigdep_up = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps,
3571 				&triggerid_up)))
3572 		{
3573 			dc_trigger_deplist_release(trigdep_up);
3574 		}
3575 
3576 		if (SUCCEED != dc_trigger_deplist_release(trigdep_down))
3577 		{
3578 			if (FAIL == (index = zbx_vector_ptr_search(&trigdep_down->dependencies, &triggerid_up,
3579 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
3580 			{
3581 				continue;
3582 			}
3583 
3584 			if (1 == trigdep_down->dependencies.values_num)
3585 				dc_trigger_deplist_reset(trigdep_down);
3586 			else
3587 				zbx_vector_ptr_remove_noorder(&trigdep_down->dependencies, index);
3588 		}
3589 	}
3590 
3591 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3592 }
3593 
DCsync_functions(zbx_dbsync_t * sync)3594 static void	DCsync_functions(zbx_dbsync_t *sync)
3595 {
3596 	char		**row;
3597 	zbx_uint64_t	rowid;
3598 	unsigned char	tag;
3599 
3600 	ZBX_DC_ITEM	*item;
3601 	ZBX_DC_FUNCTION	*function;
3602 
3603 	int		found, ret;
3604 	zbx_uint64_t	itemid, functionid, triggerid;
3605 
3606 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3607 
3608 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3609 	{
3610 		/* removed rows will be always added at the end */
3611 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3612 			break;
3613 
3614 		ZBX_STR2UINT64(itemid, row[0]);
3615 		ZBX_STR2UINT64(functionid, row[1]);
3616 		ZBX_STR2UINT64(triggerid, row[4]);
3617 
3618 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
3619 		{
3620 			/* Item could have been created after we have selected them in the             */
3621 			/* previous queries. However, we shall avoid the check for functions being the */
3622 			/* same as in the trigger expression, because that is somewhat expensive, not  */
3623 			/* 100% (think functions keeping their functionid, but changing their function */
3624 			/* or parameters), and even if there is an inconsistency, we can live with it. */
3625 
3626 			continue;
3627 		}
3628 
3629 		/* process function information */
3630 
3631 		function = (ZBX_DC_FUNCTION *)DCfind_id(&config->functions, functionid, sizeof(ZBX_DC_FUNCTION), &found);
3632 
3633 		if (1 == found && function->itemid != itemid)
3634 		{
3635 			ZBX_DC_ITEM	*item_last;
3636 
3637 			if (NULL != (item_last = zbx_hashset_search(&config->items, &function->itemid)))
3638 			{
3639 				item_last->update_triggers = 1;
3640 				if (NULL != item_last->triggers)
3641 				{
3642 					config->items.mem_free_func(item_last->triggers);
3643 					item_last->triggers = NULL;
3644 				}
3645 			}
3646 		}
3647 
3648 		function->triggerid = triggerid;
3649 		function->itemid = itemid;
3650 		DCstrpool_replace(found, &function->function, row[2]);
3651 		DCstrpool_replace(found, &function->parameter, row[3]);
3652 
3653 		function->timer = (SUCCEED == is_time_function(function->function) ? 1 : 0);
3654 
3655 		item->update_triggers = 1;
3656 		if (NULL != item->triggers)
3657 			item->triggers[0] = NULL;
3658 	}
3659 
3660 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3661 	{
3662 		if (NULL == (function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &rowid)))
3663 			continue;
3664 
3665 		if (NULL != (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
3666 		{
3667 			item->update_triggers = 1;
3668 			if (NULL != item->triggers)
3669 			{
3670 				config->items.mem_free_func(item->triggers);
3671 				item->triggers = NULL;
3672 			}
3673 		}
3674 
3675 		zbx_strpool_release(function->function);
3676 		zbx_strpool_release(function->parameter);
3677 
3678 		zbx_hashset_remove_direct(&config->functions, function);
3679 	}
3680 
3681 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3682 }
3683 
3684 /******************************************************************************
3685  *                                                                            *
3686  * Function: dc_regexp_remove_expression                                      *
3687  *                                                                            *
3688  * Purpose: removes expression from regexp                                    *
3689  *                                                                            *
3690  ******************************************************************************/
dc_regexp_remove_expression(const char * regexp_name,zbx_uint64_t expressionid)3691 static ZBX_DC_REGEXP	*dc_regexp_remove_expression(const char *regexp_name, zbx_uint64_t expressionid)
3692 {
3693 	ZBX_DC_REGEXP	*regexp, regexp_local;
3694 	int		index;
3695 
3696 	regexp_local.name = regexp_name;
3697 
3698 	if (NULL == (regexp = (ZBX_DC_REGEXP *)zbx_hashset_search(&config->regexps, &regexp_local)))
3699 		return NULL;
3700 
3701 	if (FAIL == (index = zbx_vector_uint64_search(&regexp->expressionids, expressionid,
3702 			ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
3703 	{
3704 		return NULL;
3705 	}
3706 
3707 	zbx_vector_uint64_remove_noorder(&regexp->expressionids, index);
3708 
3709 	return regexp;
3710 }
3711 
3712 /******************************************************************************
3713  *                                                                            *
3714  * Function: DCsync_expressions                                               *
3715  *                                                                            *
3716  * Purpose: Updates expressions configuration cache                           *
3717  *                                                                            *
3718  * Parameters: result - [IN] the result of expressions database select        *
3719  *                                                                            *
3720  ******************************************************************************/
DCsync_expressions(zbx_dbsync_t * sync)3721 static void	DCsync_expressions(zbx_dbsync_t *sync)
3722 {
3723 	char			**row;
3724 	zbx_uint64_t		rowid;
3725 	unsigned char		tag;
3726 	zbx_hashset_iter_t	iter;
3727 	ZBX_DC_EXPRESSION	*expression;
3728 	ZBX_DC_REGEXP		*regexp, regexp_local;
3729 	zbx_uint64_t		expressionid;
3730 	int			found, ret;
3731 
3732 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3733 
3734 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3735 	{
3736 		/* removed rows will be always added at the end */
3737 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3738 			break;
3739 
3740 		ZBX_STR2UINT64(expressionid, row[1]);
3741 		expression = (ZBX_DC_EXPRESSION *)DCfind_id(&config->expressions, expressionid, sizeof(ZBX_DC_EXPRESSION), &found);
3742 
3743 		if (0 != found)
3744 			dc_regexp_remove_expression(expression->regexp, expressionid);
3745 
3746 		DCstrpool_replace(found, &expression->regexp, row[0]);
3747 		DCstrpool_replace(found, &expression->expression, row[2]);
3748 		ZBX_STR2UCHAR(expression->type, row[3]);
3749 		ZBX_STR2UCHAR(expression->case_sensitive, row[5]);
3750 		expression->delimiter = *row[4];
3751 
3752 		regexp_local.name = row[0];
3753 
3754 		if (NULL == (regexp = (ZBX_DC_REGEXP *)zbx_hashset_search(&config->regexps, &regexp_local)))
3755 		{
3756 			DCstrpool_replace(0, &regexp_local.name, row[0]);
3757 			zbx_vector_uint64_create_ext(&regexp_local.expressionids,
3758 					__config_mem_malloc_func,
3759 					__config_mem_realloc_func,
3760 					__config_mem_free_func);
3761 
3762 			regexp = (ZBX_DC_REGEXP *)zbx_hashset_insert(&config->regexps, &regexp_local, sizeof(ZBX_DC_REGEXP));
3763 		}
3764 
3765 		zbx_vector_uint64_append(&regexp->expressionids, expressionid);
3766 	}
3767 
3768 	/* remove regexps with no expressions related to it */
3769 	zbx_hashset_iter_reset(&config->regexps, &iter);
3770 
3771 	while (NULL != (regexp = (ZBX_DC_REGEXP *)zbx_hashset_iter_next(&iter)))
3772 	{
3773 		if (0 < regexp->expressionids.values_num)
3774 			continue;
3775 
3776 		zbx_strpool_release(regexp->name);
3777 		zbx_vector_uint64_destroy(&regexp->expressionids);
3778 		zbx_hashset_iter_remove(&iter);
3779 	}
3780 
3781 	/* remove unused expressions */
3782 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3783 	{
3784 		if (NULL == (expression = (ZBX_DC_EXPRESSION *)zbx_hashset_search(&config->expressions, &rowid)))
3785 			continue;
3786 
3787 		if (NULL != (regexp = dc_regexp_remove_expression(expression->regexp, expression->expressionid)))
3788 		{
3789 			if (0 == regexp->expressionids.values_num)
3790 			{
3791 				zbx_strpool_release(regexp->name);
3792 				zbx_vector_uint64_destroy(&regexp->expressionids);
3793 				zbx_hashset_remove_direct(&config->regexps, regexp);
3794 			}
3795 		}
3796 
3797 		zbx_strpool_release(expression->expression);
3798 		zbx_strpool_release(expression->regexp);
3799 		zbx_hashset_remove_direct(&config->expressions, expression);
3800 	}
3801 
3802 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3803 }
3804 
3805 /******************************************************************************
3806  *                                                                            *
3807  * Function: DCsync_actions                                                   *
3808  *                                                                            *
3809  * Purpose: Updates actions configuration cache                               *
3810  *                                                                            *
3811  * Parameters: sync - [IN] the db synchronization data                        *
3812  *                                                                            *
3813  * Comments: The result contains the following fields:                        *
3814  *           0 - actionid                                                     *
3815  *           1 - eventsource                                                  *
3816  *           2 - evaltype                                                     *
3817  *           3 - formula                                                      *
3818  *                                                                            *
3819  ******************************************************************************/
DCsync_actions(zbx_dbsync_t * sync)3820 static void	DCsync_actions(zbx_dbsync_t *sync)
3821 {
3822 	char		**row;
3823 	zbx_uint64_t	rowid;
3824 	unsigned char	tag;
3825 	zbx_uint64_t	actionid;
3826 	zbx_dc_action_t	*action;
3827 	int		found, ret;
3828 
3829 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3830 
3831 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3832 	{
3833 		/* removed rows will be always added at the end */
3834 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3835 			break;
3836 
3837 		ZBX_STR2UINT64(actionid, row[0]);
3838 		action = (zbx_dc_action_t *)DCfind_id(&config->actions, actionid, sizeof(zbx_dc_action_t), &found);
3839 
3840 		ZBX_STR2UCHAR(action->eventsource, row[1]);
3841 		ZBX_STR2UCHAR(action->evaltype, row[2]);
3842 
3843 		DCstrpool_replace(found, &action->formula, row[3]);
3844 
3845 		if (0 == found)
3846 		{
3847 			if (EVENT_SOURCE_INTERNAL == action->eventsource)
3848 				config->internal_actions++;
3849 
3850 			zbx_vector_ptr_create_ext(&action->conditions, __config_mem_malloc_func,
3851 					__config_mem_realloc_func, __config_mem_free_func);
3852 
3853 			zbx_vector_ptr_reserve(&action->conditions, 1);
3854 
3855 			action->opflags = ZBX_ACTION_OPCLASS_NONE;
3856 		}
3857 	}
3858 
3859 	/* remove deleted actions */
3860 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3861 	{
3862 		if (NULL == (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &rowid)))
3863 			continue;
3864 
3865 		if (EVENT_SOURCE_INTERNAL == action->eventsource)
3866 			config->internal_actions--;
3867 
3868 		zbx_strpool_release(action->formula);
3869 		zbx_vector_ptr_destroy(&action->conditions);
3870 
3871 		zbx_hashset_remove_direct(&config->actions, action);
3872 	}
3873 
3874 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3875 }
3876 
3877 /******************************************************************************
3878  *                                                                            *
3879  * Function: DCsync_action_ops                                                *
3880  *                                                                            *
3881  * Purpose: Updates action operation class flags in configuration cache       *
3882  *                                                                            *
3883  * Parameters: sync - [IN] the db synchronization data                        *
3884  *                                                                            *
3885  * Comments: The result contains the following fields:                        *
3886  *           0 - actionid                                                     *
3887  *           1 - action operation class flags                                 *
3888  *                                                                            *
3889  ******************************************************************************/
DCsync_action_ops(zbx_dbsync_t * sync)3890 static void	DCsync_action_ops(zbx_dbsync_t *sync)
3891 {
3892 	char		**row;
3893 	zbx_uint64_t	rowid;
3894 	unsigned char	tag;
3895 	zbx_uint64_t	actionid;
3896 	zbx_dc_action_t	*action;
3897 
3898 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3899 
3900 	while (SUCCEED == zbx_dbsync_next(sync, &rowid, &row, &tag))
3901 	{
3902 		ZBX_STR2UINT64(actionid, row[0]);
3903 
3904 		if (NULL == (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &actionid)))
3905 			continue;
3906 
3907 		action->opflags = atoi(row[1]);
3908 	}
3909 
3910 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3911 }
3912 
3913 /******************************************************************************
3914  *                                                                            *
3915  * Function: dc_compare_action_conditions_by_type                             *
3916  *                                                                            *
3917  * Purpose: compare two action conditions by their type                       *
3918  *                                                                            *
3919  * Comments: This function is used to sort action conditions by type.         *
3920  *                                                                            *
3921  ******************************************************************************/
dc_compare_action_conditions_by_type(const void * d1,const void * d2)3922 static int	dc_compare_action_conditions_by_type(const void *d1, const void *d2)
3923 {
3924 	zbx_dc_action_condition_t	*c1 = *(zbx_dc_action_condition_t **)d1;
3925 	zbx_dc_action_condition_t	*c2 = *(zbx_dc_action_condition_t **)d2;
3926 
3927 	ZBX_RETURN_IF_NOT_EQUAL(c1->conditiontype, c2->conditiontype);
3928 
3929 	return 0;
3930 }
3931 
3932 /******************************************************************************
3933  *                                                                            *
3934  * Function: DCsync_action_conditions                                         *
3935  *                                                                            *
3936  * Purpose: Updates action conditions configuration cache                     *
3937  *                                                                            *
3938  * Parameters: sync - [IN] the db synchronization data                        *
3939  *                                                                            *
3940  * Comments: The result contains the following fields:                        *
3941  *           0 - conditionid                                                  *
3942  *           1 - actionid                                                     *
3943  *           2 - conditiontype                                                *
3944  *           3 - operator                                                     *
3945  *           4 - value                                                        *
3946  *                                                                            *
3947  ******************************************************************************/
DCsync_action_conditions(zbx_dbsync_t * sync)3948 static void	DCsync_action_conditions(zbx_dbsync_t *sync)
3949 {
3950 	char				**row;
3951 	zbx_uint64_t			rowid;
3952 	unsigned char			tag;
3953 	zbx_uint64_t			actionid, conditionid;
3954 	zbx_dc_action_t			*action;
3955 	zbx_dc_action_condition_t	*condition;
3956 	int				found, i, index, ret;
3957 	zbx_vector_ptr_t		actions;
3958 
3959 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3960 
3961 	zbx_vector_ptr_create(&actions);
3962 
3963 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
3964 	{
3965 		/* removed rows will be always added at the end */
3966 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
3967 			break;
3968 
3969 		ZBX_STR2UINT64(actionid, row[1]);
3970 
3971 		if (NULL == (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &actionid)))
3972 			continue;
3973 
3974 		ZBX_STR2UINT64(conditionid, row[0]);
3975 
3976 		condition = (zbx_dc_action_condition_t *)DCfind_id(&config->action_conditions, conditionid, sizeof(zbx_dc_action_condition_t),
3977 				&found);
3978 
3979 		ZBX_STR2UCHAR(condition->conditiontype, row[2]);
3980 		ZBX_STR2UCHAR(condition->op, row[3]);
3981 
3982 		DCstrpool_replace(found, &condition->value, row[4]);
3983 		DCstrpool_replace(found, &condition->value2, row[5]);
3984 
3985 		if (0 == found)
3986 		{
3987 			condition->actionid = actionid;
3988 			zbx_vector_ptr_append(&action->conditions, condition);
3989 		}
3990 
3991 		if (CONDITION_EVAL_TYPE_AND_OR == action->evaltype)
3992 			zbx_vector_ptr_append(&actions, action);
3993 	}
3994 
3995 	/* remove deleted conditions */
3996 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
3997 	{
3998 		if (NULL == (condition = (zbx_dc_action_condition_t *)zbx_hashset_search(&config->action_conditions, &rowid)))
3999 			continue;
4000 
4001 		if (NULL != (action = (zbx_dc_action_t *)zbx_hashset_search(&config->actions, &condition->actionid)))
4002 		{
4003 			if (FAIL != (index = zbx_vector_ptr_search(&action->conditions, condition,
4004 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4005 			{
4006 				zbx_vector_ptr_remove_noorder(&action->conditions, index);
4007 
4008 				if (CONDITION_EVAL_TYPE_AND_OR == action->evaltype)
4009 					zbx_vector_ptr_append(&actions, action);
4010 			}
4011 		}
4012 
4013 		zbx_strpool_release(condition->value);
4014 		zbx_strpool_release(condition->value2);
4015 
4016 		zbx_hashset_remove_direct(&config->action_conditions, condition);
4017 	}
4018 
4019 	/* sort conditions by type */
4020 
4021 	zbx_vector_ptr_sort(&actions, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4022 	zbx_vector_ptr_uniq(&actions, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4023 
4024 	for (i = 0; i < actions.values_num; i++)
4025 	{
4026 		action = (zbx_dc_action_t *)actions.values[i];
4027 
4028 		if (CONDITION_EVAL_TYPE_AND_OR == action->evaltype)
4029 			zbx_vector_ptr_sort(&action->conditions, dc_compare_action_conditions_by_type);
4030 	}
4031 
4032 	zbx_vector_ptr_destroy(&actions);
4033 
4034 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4035 }
4036 
4037 /******************************************************************************
4038  *                                                                            *
4039  * Function: DCsync_correlations                                              *
4040  *                                                                            *
4041  * Purpose: Updates correlations configuration cache                          *
4042  *                                                                            *
4043  * Parameters: sync - [IN] the db synchronization data                        *
4044  *                                                                            *
4045  * Comments: The result contains the following fields:                        *
4046  *           0 - correlationid                                                *
4047  *           1 - name                                                         *
4048  *           2 - evaltype                                                     *
4049  *           3 - formula                                                      *
4050  *                                                                            *
4051  ******************************************************************************/
DCsync_correlations(zbx_dbsync_t * sync)4052 static void	DCsync_correlations(zbx_dbsync_t *sync)
4053 {
4054 	char			**row;
4055 	zbx_uint64_t		rowid;
4056 	unsigned char		tag;
4057 	zbx_uint64_t		correlationid;
4058 	zbx_dc_correlation_t	*correlation;
4059 	int			found, ret;
4060 
4061 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4062 
4063 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4064 	{
4065 		/* removed rows will be always added at the end */
4066 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4067 			break;
4068 
4069 		ZBX_STR2UINT64(correlationid, row[0]);
4070 
4071 		correlation = (zbx_dc_correlation_t *)DCfind_id(&config->correlations, correlationid, sizeof(zbx_dc_correlation_t), &found);
4072 
4073 		if (0 == found)
4074 		{
4075 			zbx_vector_ptr_create_ext(&correlation->conditions, __config_mem_malloc_func,
4076 					__config_mem_realloc_func, __config_mem_free_func);
4077 
4078 			zbx_vector_ptr_create_ext(&correlation->operations, __config_mem_malloc_func,
4079 					__config_mem_realloc_func, __config_mem_free_func);
4080 		}
4081 
4082 		DCstrpool_replace(found, &correlation->name, row[1]);
4083 		DCstrpool_replace(found, &correlation->formula, row[3]);
4084 
4085 		ZBX_STR2UCHAR(correlation->evaltype, row[2]);
4086 	}
4087 
4088 	/* remove deleted correlations */
4089 
4090 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4091 	{
4092 		if (NULL == (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &rowid)))
4093 			continue;
4094 
4095 		zbx_strpool_release(correlation->name);
4096 		zbx_strpool_release(correlation->formula);
4097 
4098 		zbx_vector_ptr_destroy(&correlation->conditions);
4099 		zbx_vector_ptr_destroy(&correlation->operations);
4100 
4101 		zbx_hashset_remove_direct(&config->correlations, correlation);
4102 	}
4103 
4104 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4105 }
4106 
4107 /******************************************************************************
4108  *                                                                            *
4109  * Function: dc_corr_condition_get_size                                       *
4110  *                                                                            *
4111  * Purpose: get the actual size of correlation condition data depending on    *
4112  *          its type                                                          *
4113  *                                                                            *
4114  * Parameters: type - [IN] the condition type                                 *
4115  *                                                                            *
4116  * Return value: the size                                                     *
4117  *                                                                            *
4118  ******************************************************************************/
dc_corr_condition_get_size(unsigned char type)4119 static size_t	dc_corr_condition_get_size(unsigned char type)
4120 {
4121 	switch (type)
4122 	{
4123 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
4124 			/* break; is not missing here */
4125 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
4126 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_tag_t);
4127 		case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP:
4128 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_group_t);
4129 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
4130 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_tag_pair_t);
4131 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
4132 			/* break; is not missing here */
4133 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
4134 			return offsetof(zbx_dc_corr_condition_t, data) + sizeof(zbx_dc_corr_condition_tag_value_t);
4135 	}
4136 
4137 	THIS_SHOULD_NEVER_HAPPEN;
4138 	return 0;
4139 }
4140 
4141 /******************************************************************************
4142  *                                                                            *
4143  * Function: dc_corr_condition_init_data                                      *
4144  *                                                                            *
4145  * Purpose: initializes correlation condition data from database row          *
4146  *                                                                            *
4147  * Parameters: condition - [IN] the condition to initialize                   *
4148  *             found     - [IN] 0 - new condition, 1 - cached condition       *
4149  *             row       - [IN] the database row containing condition data    *
4150  *                                                                            *
4151  ******************************************************************************/
dc_corr_condition_init_data(zbx_dc_corr_condition_t * condition,int found,DB_ROW row)4152 static void	dc_corr_condition_init_data(zbx_dc_corr_condition_t *condition, int found,  DB_ROW row)
4153 {
4154 	if (ZBX_CORR_CONDITION_OLD_EVENT_TAG == condition->type || ZBX_CORR_CONDITION_NEW_EVENT_TAG == condition->type)
4155 	{
4156 		DCstrpool_replace(found, &condition->data.tag.tag, row[0]);
4157 		return;
4158 	}
4159 
4160 	row++;
4161 
4162 	if (ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE == condition->type ||
4163 			ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE == condition->type)
4164 	{
4165 		DCstrpool_replace(found, &condition->data.tag_value.tag, row[0]);
4166 		DCstrpool_replace(found, &condition->data.tag_value.value, row[1]);
4167 		ZBX_STR2UCHAR(condition->data.tag_value.op, row[2]);
4168 		return;
4169 	}
4170 
4171 	row += 3;
4172 
4173 	if (ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP == condition->type)
4174 	{
4175 		ZBX_STR2UINT64(condition->data.group.groupid, row[0]);
4176 		ZBX_STR2UCHAR(condition->data.group.op, row[1]);
4177 		return;
4178 	}
4179 
4180 	row += 2;
4181 
4182 	if (ZBX_CORR_CONDITION_EVENT_TAG_PAIR == condition->type)
4183 	{
4184 		DCstrpool_replace(found, &condition->data.tag_pair.oldtag, row[0]);
4185 		DCstrpool_replace(found, &condition->data.tag_pair.newtag, row[1]);
4186 		return;
4187 	}
4188 }
4189 
4190 /******************************************************************************
4191  *                                                                            *
4192  * Function: corr_condition_free_data                                         *
4193  *                                                                            *
4194  * Purpose: frees correlation condition data                                  *
4195  *                                                                            *
4196  * Parameters: condition - [IN] the condition                                 *
4197  *                                                                            *
4198  ******************************************************************************/
corr_condition_free_data(zbx_dc_corr_condition_t * condition)4199 static void	corr_condition_free_data(zbx_dc_corr_condition_t *condition)
4200 {
4201 	switch (condition->type)
4202 	{
4203 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
4204 			/* break; is not missing here */
4205 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
4206 			zbx_strpool_release(condition->data.tag.tag);
4207 			break;
4208 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
4209 			zbx_strpool_release(condition->data.tag_pair.oldtag);
4210 			zbx_strpool_release(condition->data.tag_pair.newtag);
4211 			break;
4212 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
4213 			/* break; is not missing here */
4214 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
4215 			zbx_strpool_release(condition->data.tag_value.tag);
4216 			zbx_strpool_release(condition->data.tag_value.value);
4217 			break;
4218 	}
4219 }
4220 
4221 /******************************************************************************
4222  *                                                                            *
4223  * Function: dc_compare_corr_conditions_by_type                               *
4224  *                                                                            *
4225  * Purpose: compare two correlation conditions by their type                  *
4226  *                                                                            *
4227  * Comments: This function is used to sort correlation conditions by type.    *
4228  *                                                                            *
4229  ******************************************************************************/
dc_compare_corr_conditions_by_type(const void * d1,const void * d2)4230 static int	dc_compare_corr_conditions_by_type(const void *d1, const void *d2)
4231 {
4232 	zbx_dc_corr_condition_t	*c1 = *(zbx_dc_corr_condition_t **)d1;
4233 	zbx_dc_corr_condition_t	*c2 = *(zbx_dc_corr_condition_t **)d2;
4234 
4235 	ZBX_RETURN_IF_NOT_EQUAL(c1->type, c2->type);
4236 
4237 	return 0;
4238 }
4239 
4240 /******************************************************************************
4241  *                                                                            *
4242  * Function: DCsync_corr_conditions                                           *
4243  *                                                                            *
4244  * Purpose: Updates correlation conditions configuration cache                *
4245  *                                                                            *
4246  * Parameters: sync - [IN] the db synchronization data                        *
4247  *                                                                            *
4248  * Comments: The result contains the following fields:                        *
4249  *           0 - corr_conditionid                                             *
4250  *           1 - correlationid                                                *
4251  *           2 - type                                                         *
4252  *           3 - corr_condition_tag.tag                                       *
4253  *           4 - corr_condition_tagvalue.tag                                  *
4254  *           5 - corr_condition_tagvalue.value                                *
4255  *           6 - corr_condition_tagvalue.operator                             *
4256  *           7 - corr_condition_group.groupid                                 *
4257  *           8 - corr_condition_group.operator                                *
4258  *           9 - corr_condition_tagpair.oldtag                                *
4259  *          10 - corr_condition_tagpair.newtag                                *
4260  *                                                                            *
4261  ******************************************************************************/
DCsync_corr_conditions(zbx_dbsync_t * sync)4262 static void	DCsync_corr_conditions(zbx_dbsync_t *sync)
4263 {
4264 	char			**row;
4265 	zbx_uint64_t		rowid;
4266 	unsigned char		tag;
4267 	zbx_uint64_t		conditionid, correlationid;
4268 	zbx_dc_corr_condition_t	*condition;
4269 	zbx_dc_correlation_t	*correlation;
4270 	int			found, ret, i, index;
4271 	unsigned char		type;
4272 	size_t			condition_size;
4273 	zbx_vector_ptr_t	correlations;
4274 
4275 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4276 
4277 	zbx_vector_ptr_create(&correlations);
4278 
4279 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4280 	{
4281 		/* removed rows will be always added at the end */
4282 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4283 			break;
4284 
4285 		ZBX_STR2UINT64(correlationid, row[1]);
4286 
4287 		if (NULL == (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &correlationid)))
4288 			continue;
4289 
4290 		ZBX_STR2UINT64(conditionid, row[0]);
4291 		ZBX_STR2UCHAR(type, row[2]);
4292 
4293 		condition_size = dc_corr_condition_get_size(type);
4294 		condition = (zbx_dc_corr_condition_t *)DCfind_id(&config->corr_conditions, conditionid, condition_size, &found);
4295 
4296 		condition->correlationid = correlationid;
4297 		condition->type = type;
4298 		dc_corr_condition_init_data(condition, found, row + 3);
4299 
4300 		if (0 == found)
4301 			zbx_vector_ptr_append(&correlation->conditions, condition);
4302 
4303 		/* sort the conditions later */
4304 		if (CONDITION_EVAL_TYPE_AND_OR == correlation->evaltype)
4305 			zbx_vector_ptr_append(&correlations, correlation);
4306 	}
4307 
4308 	/* remove deleted correlation conditions */
4309 
4310 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4311 	{
4312 		if (NULL == (condition = (zbx_dc_corr_condition_t *)zbx_hashset_search(&config->corr_conditions, &rowid)))
4313 			continue;
4314 
4315 		/* remove condition from correlation->conditions vector */
4316 		if (NULL != (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &condition->correlationid)))
4317 		{
4318 			if (FAIL != (index = zbx_vector_ptr_search(&correlation->conditions, condition,
4319 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4320 			{
4321 				/* sort the conditions later */
4322 				if (CONDITION_EVAL_TYPE_AND_OR == correlation->evaltype)
4323 					zbx_vector_ptr_append(&correlations, correlation);
4324 
4325 				zbx_vector_ptr_remove_noorder(&correlation->conditions, index);
4326 			}
4327 		}
4328 
4329 		corr_condition_free_data(condition);
4330 		zbx_hashset_remove_direct(&config->corr_conditions, condition);
4331 	}
4332 
4333 	/* sort conditions by type */
4334 
4335 	zbx_vector_ptr_sort(&correlations, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4336 	zbx_vector_ptr_uniq(&correlations, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4337 
4338 	for (i = 0; i < correlations.values_num; i++)
4339 	{
4340 		correlation = (zbx_dc_correlation_t *)correlations.values[i];
4341 		zbx_vector_ptr_sort(&correlation->conditions, dc_compare_corr_conditions_by_type);
4342 	}
4343 
4344 	zbx_vector_ptr_destroy(&correlations);
4345 
4346 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4347 }
4348 
4349 /******************************************************************************
4350  *                                                                            *
4351  * Function: DCsync_corr_operations                                           *
4352  *                                                                            *
4353  * Purpose: Updates correlation operations configuration cache                *
4354  *                                                                            *
4355  * Parameters: result - [IN] the result of correlation operations database    *
4356  *                           select                                           *
4357  *                                                                            *
4358  * Comments: The result contains the following fields:                        *
4359  *           0 - corr_operationid                                             *
4360  *           1 - correlationid                                                *
4361  *           2 - type                                                         *
4362  *                                                                            *
4363  ******************************************************************************/
DCsync_corr_operations(zbx_dbsync_t * sync)4364 static void	DCsync_corr_operations(zbx_dbsync_t *sync)
4365 {
4366 	char			**row;
4367 	zbx_uint64_t		rowid;
4368 	unsigned char		tag;
4369 	zbx_uint64_t		operationid, correlationid;
4370 	zbx_dc_corr_operation_t	*operation;
4371 	zbx_dc_correlation_t	*correlation;
4372 	int			found, ret, index;
4373 	unsigned char		type;
4374 
4375 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4376 
4377 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4378 	{
4379 		/* removed rows will be always added at the end */
4380 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4381 			break;
4382 
4383 		ZBX_STR2UINT64(correlationid, row[1]);
4384 
4385 		if (NULL == (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &correlationid)))
4386 			continue;
4387 
4388 		ZBX_STR2UINT64(operationid, row[0]);
4389 		ZBX_STR2UCHAR(type, row[2]);
4390 
4391 		operation = (zbx_dc_corr_operation_t *)DCfind_id(&config->corr_operations, operationid, sizeof(zbx_dc_corr_operation_t), &found);
4392 
4393 		operation->type = type;
4394 
4395 		if (0 == found)
4396 		{
4397 			operation->correlationid = correlationid;
4398 			zbx_vector_ptr_append(&correlation->operations, operation);
4399 		}
4400 	}
4401 
4402 	/* remove deleted correlation operations */
4403 
4404 	/* remove deleted actions */
4405 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4406 	{
4407 		if (NULL == (operation = (zbx_dc_corr_operation_t *)zbx_hashset_search(&config->corr_operations, &rowid)))
4408 			continue;
4409 
4410 		/* remove operation from correlation->conditions vector */
4411 		if (NULL != (correlation = (zbx_dc_correlation_t *)zbx_hashset_search(&config->correlations, &operation->correlationid)))
4412 		{
4413 			if (FAIL != (index = zbx_vector_ptr_search(&correlation->operations, operation,
4414 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4415 			{
4416 				zbx_vector_ptr_remove_noorder(&correlation->operations, index);
4417 			}
4418 		}
4419 		zbx_hashset_remove_direct(&config->corr_operations, operation);
4420 	}
4421 
4422 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4423 }
4424 
dc_compare_hgroups(const void * d1,const void * d2)4425 static int	dc_compare_hgroups(const void *d1, const void *d2)
4426 {
4427 	const zbx_dc_hostgroup_t	*g1 = *((const zbx_dc_hostgroup_t **)d1);
4428 	const zbx_dc_hostgroup_t	*g2 = *((const zbx_dc_hostgroup_t **)d2);
4429 
4430 	return strcmp(g1->name, g2->name);
4431 }
4432 
4433 /******************************************************************************
4434  *                                                                            *
4435  * Function: DCsync_hostgroups                                                *
4436  *                                                                            *
4437  * Purpose: Updates host groups configuration cache                           *
4438  *                                                                            *
4439  * Parameters: sync - [IN] the db synchronization data                        *
4440  *                                                                            *
4441  * Comments: The result contains the following fields:                        *
4442  *           0 - groupid                                                      *
4443  *           1 - name                                                         *
4444  *                                                                            *
4445  ******************************************************************************/
DCsync_hostgroups(zbx_dbsync_t * sync)4446 static void	DCsync_hostgroups(zbx_dbsync_t *sync)
4447 {
4448 	char			**row;
4449 	zbx_uint64_t		rowid;
4450 	unsigned char		tag;
4451 	zbx_uint64_t		groupid;
4452 	zbx_dc_hostgroup_t	*group;
4453 	int			found, ret, index;
4454 
4455 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4456 
4457 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4458 	{
4459 		/* removed rows will be always added at the end */
4460 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4461 			break;
4462 
4463 		ZBX_STR2UINT64(groupid, row[0]);
4464 
4465 		group = (zbx_dc_hostgroup_t *)DCfind_id(&config->hostgroups, groupid, sizeof(zbx_dc_hostgroup_t), &found);
4466 
4467 		if (0 == found)
4468 		{
4469 			group->flags = ZBX_DC_HOSTGROUP_FLAGS_NONE;
4470 			zbx_vector_ptr_append(&config->hostgroups_name, group);
4471 
4472 			zbx_hashset_create_ext(&group->hostids, 0, ZBX_DEFAULT_UINT64_HASH_FUNC,
4473 					ZBX_DEFAULT_UINT64_COMPARE_FUNC, NULL, __config_mem_malloc_func,
4474 					__config_mem_realloc_func, __config_mem_free_func);
4475 		}
4476 
4477 		DCstrpool_replace(found, &group->name, row[1]);
4478 	}
4479 
4480 	/* remove deleted host groups */
4481 
4482 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4483 	{
4484 		if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &rowid)))
4485 			continue;
4486 
4487 		if (FAIL != (index = zbx_vector_ptr_search(&config->hostgroups_name, group, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4488 			zbx_vector_ptr_remove_noorder(&config->hostgroups_name, index);
4489 
4490 		if (ZBX_DC_HOSTGROUP_FLAGS_NONE != group->flags)
4491 			zbx_vector_uint64_destroy(&group->nested_groupids);
4492 
4493 		zbx_strpool_release(group->name);
4494 		zbx_hashset_destroy(&group->hostids);
4495 		zbx_hashset_remove_direct(&config->hostgroups, group);
4496 	}
4497 
4498 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4499 }
4500 
4501 /******************************************************************************
4502  *                                                                            *
4503  * Function: DCsync_trigger_tags                                              *
4504  *                                                                            *
4505  * Purpose: Updates trigger tags in configuration cache                       *
4506  *                                                                            *
4507  * Parameters: sync - [IN] the db synchronization data                        *
4508  *                                                                            *
4509  * Comments: The result contains the following fields:                        *
4510  *           0 - triggertagid                                                 *
4511  *           1 - triggerid                                                    *
4512  *           2 - tag                                                          *
4513  *           3 - value                                                        *
4514  *                                                                            *
4515  ******************************************************************************/
DCsync_trigger_tags(zbx_dbsync_t * sync)4516 static void	DCsync_trigger_tags(zbx_dbsync_t *sync)
4517 {
4518 	char			**row;
4519 	zbx_uint64_t		rowid;
4520 	unsigned char		tag;
4521 	int			found, ret, index;
4522 	zbx_uint64_t		triggerid, triggertagid;
4523 	ZBX_DC_TRIGGER		*trigger;
4524 	zbx_dc_trigger_tag_t	*trigger_tag;
4525 
4526 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4527 
4528 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4529 	{
4530 		/* removed rows will be always added at the end */
4531 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4532 			break;
4533 
4534 		ZBX_STR2UINT64(triggerid, row[1]);
4535 
4536 		if (NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerid)))
4537 			continue;
4538 
4539 		ZBX_STR2UINT64(triggertagid, row[0]);
4540 
4541 		trigger_tag = (zbx_dc_trigger_tag_t *)DCfind_id(&config->trigger_tags, triggertagid, sizeof(zbx_dc_trigger_tag_t), &found);
4542 		DCstrpool_replace(found, &trigger_tag->tag, row[2]);
4543 		DCstrpool_replace(found, &trigger_tag->value, row[3]);
4544 
4545 		if (0 == found)
4546 		{
4547 			trigger_tag->triggerid = triggerid;
4548 			zbx_vector_ptr_append(&trigger->tags, trigger_tag);
4549 		}
4550 	}
4551 
4552 	/* remove unused trigger tags */
4553 
4554 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4555 	{
4556 		if (NULL == (trigger_tag = (zbx_dc_trigger_tag_t *)zbx_hashset_search(&config->trigger_tags, &rowid)))
4557 			continue;
4558 
4559 		if (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &trigger_tag->triggerid)))
4560 		{
4561 			if (FAIL != (index = zbx_vector_ptr_search(&trigger->tags, trigger_tag,
4562 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4563 			{
4564 				zbx_vector_ptr_remove_noorder(&trigger->tags, index);
4565 
4566 				/* recreate empty tags vector to release used memory */
4567 				if (0 == trigger->tags.values_num)
4568 				{
4569 					zbx_vector_ptr_destroy(&trigger->tags);
4570 					zbx_vector_ptr_create_ext(&trigger->tags, __config_mem_malloc_func,
4571 							__config_mem_realloc_func, __config_mem_free_func);
4572 				}
4573 			}
4574 		}
4575 
4576 		zbx_strpool_release(trigger_tag->tag);
4577 		zbx_strpool_release(trigger_tag->value);
4578 
4579 		zbx_hashset_remove_direct(&config->trigger_tags, trigger_tag);
4580 	}
4581 
4582 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4583 }
4584 
4585 /******************************************************************************
4586  *                                                                            *
4587  * Function: DCsync_host_tags                                                 *
4588  *                                                                            *
4589  * Purpose: Updates host tags in configuration cache                          *
4590  *                                                                            *
4591  * Parameters: sync - [IN] the db synchronization data                        *
4592  *                                                                            *
4593  * Comments: The result contains the following fields:                        *
4594  *           0 - hosttagid                                                    *
4595  *           1 - hostid                                                       *
4596  *           2 - tag                                                          *
4597  *           3 - value                                                        *
4598  *                                                                            *
4599  ******************************************************************************/
DCsync_host_tags(zbx_dbsync_t * sync)4600 static void	DCsync_host_tags(zbx_dbsync_t *sync)
4601 {
4602 	char		**row;
4603 	zbx_uint64_t	rowid;
4604 	unsigned char	tag;
4605 
4606 	zbx_dc_host_tag_t		*host_tag;
4607 	zbx_dc_host_tag_index_t		*host_tag_index_entry;
4608 
4609 	int		found, index, ret;
4610 	zbx_uint64_t	hosttagid, hostid;
4611 
4612 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4613 
4614 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4615 	{
4616 		/* removed rows will be always added at the end */
4617 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4618 			break;
4619 
4620 		ZBX_STR2UINT64(hosttagid, row[0]);
4621 		ZBX_STR2UINT64(hostid, row[1]);
4622 
4623 		host_tag = (zbx_dc_host_tag_t *)DCfind_id(&config->host_tags, hosttagid,
4624 				sizeof(zbx_dc_host_tag_t), &found);
4625 
4626 		/* store new information in host_tag structure */
4627 		host_tag->hostid = hostid;
4628 		DCstrpool_replace(found, &host_tag->tag, row[2]);
4629 		DCstrpool_replace(found, &host_tag->value, row[3]);
4630 
4631 		/* update host_tags_index*/
4632 		if (tag == ZBX_DBSYNC_ROW_ADD)
4633 		{
4634 			host_tag_index_entry = (zbx_dc_host_tag_index_t *)DCfind_id(&config->host_tags_index, hostid,
4635 					sizeof(zbx_dc_host_tag_index_t), &found);
4636 
4637 			if (0 == found)
4638 			{
4639 				zbx_vector_ptr_create_ext(&host_tag_index_entry->tags, __config_mem_malloc_func,
4640 						__config_mem_realloc_func, __config_mem_free_func);
4641 			}
4642 
4643 			zbx_vector_ptr_append(&host_tag_index_entry->tags, host_tag);
4644 		}
4645 	}
4646 
4647 	/* remove deleted host tags from buffer */
4648 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4649 	{
4650 		if (NULL == (host_tag = (zbx_dc_host_tag_t *)zbx_hashset_search(&config->host_tags, &rowid)))
4651 			continue;
4652 
4653 		/* update host_tags_index*/
4654 		host_tag_index_entry = (zbx_dc_host_tag_index_t *)zbx_hashset_search(&config->host_tags_index,
4655 				&host_tag->hostid);
4656 
4657 		if (NULL != host_tag_index_entry)
4658 		{
4659 			if (FAIL != (index = zbx_vector_ptr_search(&host_tag_index_entry->tags, host_tag,
4660 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4661 			{
4662 				zbx_vector_ptr_remove(&host_tag_index_entry->tags, index);
4663 			}
4664 
4665 			/* remove index entry if it's empty */
4666 			if (0 == host_tag_index_entry->tags.values_num)
4667 			{
4668 				zbx_vector_ptr_destroy(&host_tag_index_entry->tags);
4669 				zbx_hashset_remove_direct(&config->host_tags_index, host_tag_index_entry);
4670 			}
4671 		}
4672 
4673 		/* clear host_tag structure */
4674 		zbx_strpool_release(host_tag->tag);
4675 		zbx_strpool_release(host_tag->value);
4676 
4677 		zbx_hashset_remove_direct(&config->host_tags, host_tag);
4678 	}
4679 
4680 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4681 }
4682 
4683 /******************************************************************************
4684  *                                                                            *
4685  * Function: dc_compare_item_preproc_by_step                                  *
4686  *                                                                            *
4687  * Purpose: compare two item preprocessing operations by step                 *
4688  *                                                                            *
4689  * Comments: This function is used to sort correlation conditions by type.    *
4690  *                                                                            *
4691  ******************************************************************************/
dc_compare_preprocops_by_step(const void * d1,const void * d2)4692 static int	dc_compare_preprocops_by_step(const void *d1, const void *d2)
4693 {
4694 	zbx_dc_preproc_op_t	*p1 = *(zbx_dc_preproc_op_t **)d1;
4695 	zbx_dc_preproc_op_t	*p2 = *(zbx_dc_preproc_op_t **)d2;
4696 
4697 	ZBX_RETURN_IF_NOT_EQUAL(p1->step, p2->step);
4698 
4699 	return 0;
4700 }
4701 
4702 /******************************************************************************
4703  *                                                                            *
4704  * Function: DCsync_item_preproc                                              *
4705  *                                                                            *
4706  * Purpose: Updates item preprocessing steps in configuration cache           *
4707  *                                                                            *
4708  * Parameters: sync - [IN] the db synchronization data                        *
4709  *                                                                            *
4710  * Comments: The result contains the following fields:                        *
4711  *           0 - item_preprocid                                               *
4712  *           1 - itemid                                                       *
4713  *           2 - type                                                         *
4714  *           3 - params                                                       *
4715  *                                                                            *
4716  ******************************************************************************/
DCsync_item_preproc(zbx_dbsync_t * sync,int timestamp)4717 static void	DCsync_item_preproc(zbx_dbsync_t *sync, int timestamp)
4718 {
4719 	char			**row;
4720 	zbx_uint64_t		rowid;
4721 	unsigned char		tag;
4722 	zbx_uint64_t		item_preprocid, itemid;
4723 	int			found, ret, i, index;
4724 	ZBX_DC_PREPROCITEM	*preprocitem = NULL;
4725 	zbx_dc_preproc_op_t	*op;
4726 	zbx_vector_ptr_t	items;
4727 
4728 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4729 
4730 	zbx_vector_ptr_create(&items);
4731 
4732 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4733 	{
4734 		/* removed rows will be always added at the end */
4735 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4736 			break;
4737 
4738 		ZBX_STR2UINT64(itemid, row[1]);
4739 
4740 		if (NULL == preprocitem || itemid != preprocitem->itemid)
4741 		{
4742 			if (NULL == (preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_search(&config->preprocitems, &itemid)))
4743 			{
4744 				ZBX_DC_PREPROCITEM	preprocitem_local;
4745 
4746 				preprocitem_local.itemid = itemid;
4747 
4748 				preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_insert(&config->preprocitems, &preprocitem_local,
4749 						sizeof(preprocitem_local));
4750 
4751 				zbx_vector_ptr_create_ext(&preprocitem->preproc_ops, __config_mem_malloc_func,
4752 						__config_mem_realloc_func, __config_mem_free_func);
4753 			}
4754 
4755 			preprocitem->update_time = timestamp;
4756 		}
4757 
4758 		ZBX_STR2UINT64(item_preprocid, row[0]);
4759 
4760 		op = (zbx_dc_preproc_op_t *)DCfind_id(&config->preprocops, item_preprocid, sizeof(zbx_dc_preproc_op_t), &found);
4761 
4762 		ZBX_STR2UCHAR(op->type, row[2]);
4763 		DCstrpool_replace(found, &op->params, row[3]);
4764 		op->step = atoi(row[4]);
4765 		op->error_handler = atoi(row[6]);
4766 		DCstrpool_replace(found, &op->error_handler_params, row[7]);
4767 
4768 		if (0 == found)
4769 		{
4770 			op->itemid = itemid;
4771 			zbx_vector_ptr_append(&preprocitem->preproc_ops, op);
4772 		}
4773 
4774 		zbx_vector_ptr_append(&items, preprocitem);
4775 	}
4776 
4777 	/* remove deleted item preprocessing operations */
4778 
4779 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4780 	{
4781 		if (NULL == (op = (zbx_dc_preproc_op_t *)zbx_hashset_search(&config->preprocops, &rowid)))
4782 			continue;
4783 
4784 		if (NULL != (preprocitem = (ZBX_DC_PREPROCITEM *)zbx_hashset_search(&config->preprocitems, &op->itemid)))
4785 		{
4786 			if (FAIL != (index = zbx_vector_ptr_search(&preprocitem->preproc_ops, op,
4787 					ZBX_DEFAULT_PTR_COMPARE_FUNC)))
4788 			{
4789 				zbx_vector_ptr_remove_noorder(&preprocitem->preproc_ops, index);
4790 				zbx_vector_ptr_append(&items, preprocitem);
4791 			}
4792 		}
4793 
4794 		zbx_strpool_release(op->params);
4795 		zbx_strpool_release(op->error_handler_params);
4796 		zbx_hashset_remove_direct(&config->preprocops, op);
4797 	}
4798 
4799 	/* sort item preprocessing operations by step */
4800 
4801 	zbx_vector_ptr_sort(&items, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4802 	zbx_vector_ptr_uniq(&items, ZBX_DEFAULT_PTR_COMPARE_FUNC);
4803 
4804 	for (i = 0; i < items.values_num; i++)
4805 	{
4806 		preprocitem = (ZBX_DC_PREPROCITEM *)items.values[i];
4807 
4808 		if (0 == preprocitem->preproc_ops.values_num)
4809 		{
4810 			zbx_vector_ptr_destroy(&preprocitem->preproc_ops);
4811 			zbx_hashset_remove_direct(&config->preprocitems, preprocitem);
4812 		}
4813 		else
4814 			zbx_vector_ptr_sort(&preprocitem->preproc_ops, dc_compare_preprocops_by_step);
4815 	}
4816 
4817 	zbx_vector_ptr_destroy(&items);
4818 
4819 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4820 }
4821 
4822 /******************************************************************************
4823  *                                                                            *
4824  * Function: DCsync_hostgroup_hosts                                           *
4825  *                                                                            *
4826  * Purpose: Updates group hosts in configuration cache                        *
4827  *                                                                            *
4828  * Parameters: sync - [IN] the db synchronization data                        *
4829  *                                                                            *
4830  * Comments: The result contains the following fields:                        *
4831  *           0 - groupid                                                      *
4832  *           1 - hostid                                                       *
4833  *                                                                            *
4834  ******************************************************************************/
DCsync_hostgroup_hosts(zbx_dbsync_t * sync)4835 static void	DCsync_hostgroup_hosts(zbx_dbsync_t *sync)
4836 {
4837 	char			**row;
4838 	zbx_uint64_t		rowid;
4839 	unsigned char		tag;
4840 
4841 	zbx_dc_hostgroup_t	*group = NULL;
4842 
4843 	int			ret;
4844 	zbx_uint64_t		last_groupid = 0, groupid, hostid;
4845 
4846 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4847 
4848 	while (SUCCEED == (ret = zbx_dbsync_next(sync, &rowid, &row, &tag)))
4849 	{
4850 		config->maintenance_update = ZBX_MAINTENANCE_UPDATE_TRUE;
4851 
4852 		/* removed rows will be always added at the end */
4853 		if (ZBX_DBSYNC_ROW_REMOVE == tag)
4854 			break;
4855 
4856 		ZBX_STR2UINT64(groupid, row[0]);
4857 
4858 		if (last_groupid != groupid)
4859 		{
4860 			group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &groupid);
4861 			last_groupid = groupid;
4862 		}
4863 
4864 		if (NULL == group)
4865 			continue;
4866 
4867 		ZBX_STR2UINT64(hostid, row[1]);
4868 		zbx_hashset_insert(&group->hostids, &hostid, sizeof(hostid));
4869 	}
4870 
4871 	/* remove deleted group hostids from cache */
4872 	for (; SUCCEED == ret; ret = zbx_dbsync_next(sync, &rowid, &row, &tag))
4873 	{
4874 		ZBX_STR2UINT64(groupid, row[0]);
4875 
4876 		if (NULL == (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &groupid)))
4877 			continue;
4878 
4879 		ZBX_STR2UINT64(hostid, row[1]);
4880 		zbx_hashset_remove(&group->hostids, &hostid);
4881 	}
4882 
4883 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
4884 }
4885 
4886 /******************************************************************************
4887  *                                                                            *
4888  * Function: dc_trigger_update_topology                                       *
4889  *                                                                            *
4890  * Purpose: updates trigger topology after trigger dependency changes         *
4891  *                                                                            *
4892  ******************************************************************************/
dc_trigger_update_topology(void)4893 static void	dc_trigger_update_topology(void)
4894 {
4895 	zbx_hashset_iter_t	iter;
4896 	ZBX_DC_TRIGGER		*trigger;
4897 
4898 	zbx_hashset_iter_reset(&config->triggers, &iter);
4899 	while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
4900 		trigger->topoindex = 1;
4901 
4902 	DCconfig_sort_triggers_topologically();
4903 }
4904 
zbx_default_ptr_pair_ptr_compare_func(const void * d1,const void * d2)4905 static int	zbx_default_ptr_pair_ptr_compare_func(const void *d1, const void *d2)
4906 {
4907 	const zbx_ptr_pair_t	*p1 = (const zbx_ptr_pair_t *)d1;
4908 	const zbx_ptr_pair_t	*p2 = (const zbx_ptr_pair_t *)d2;
4909 
4910 	ZBX_RETURN_IF_NOT_EQUAL(p1->first, p2->first);
4911 	ZBX_RETURN_IF_NOT_EQUAL(p1->second, p2->second);
4912 
4913 	return 0;
4914 }
4915 
4916 #define ZBX_TIMER_DELAY		30
4917 
4918 /******************************************************************************
4919  *                                                                            *
4920  * Function: dc_timer_calculate_nextcheck                                     *
4921  *                                                                            *
4922  * Purpose: calculates next check for timer queue item                        *
4923  *                                                                            *
4924  ******************************************************************************/
dc_timer_calculate_nextcheck(time_t now,zbx_uint64_t seed)4925 static int	dc_timer_calculate_nextcheck(time_t now, zbx_uint64_t seed)
4926 {
4927 	int	nextcheck;
4928 
4929 	nextcheck = ZBX_TIMER_DELAY * (int)(now / (time_t)ZBX_TIMER_DELAY) +
4930 			(int)(seed % (zbx_uint64_t)ZBX_TIMER_DELAY);
4931 
4932 	while (nextcheck <= now)
4933 		nextcheck += ZBX_TIMER_DELAY;
4934 
4935 	return nextcheck;
4936 }
4937 
4938 /******************************************************************************
4939  *                                                                            *
4940  * Function: dc_trigger_update_cache                                          *
4941  *                                                                            *
4942  * Purpose: updates trigger related cache data;                               *
4943  *              1) time triggers assigned to timer processes                  *
4944  *              2) trigger functionality (if it uses contain disabled         *
4945  *                 items/hosts)                                               *
4946  *              3) list of triggers each item is used by                      *
4947  *                                                                            *
4948  ******************************************************************************/
dc_trigger_update_cache(void)4949 static void	dc_trigger_update_cache(void)
4950 {
4951 	zbx_hashset_iter_t	iter;
4952 	ZBX_DC_TRIGGER		*trigger;
4953 	ZBX_DC_FUNCTION		*function;
4954 	ZBX_DC_ITEM		*item;
4955 	int			i, j, k, now;
4956 	zbx_ptr_pair_t		itemtrig;
4957 	zbx_vector_ptr_pair_t	itemtrigs;
4958 	ZBX_DC_HOST		*host;
4959 
4960 	zbx_hashset_iter_reset(&config->triggers, &iter);
4961 	while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
4962 	{
4963 		trigger->functional = TRIGGER_FUNCTIONAL_TRUE;
4964 		trigger->timer = ZBX_TRIGGER_TIMER_UNKNOWN;
4965 	}
4966 
4967 	zbx_vector_ptr_pair_create(&itemtrigs);
4968 	zbx_hashset_iter_reset(&config->functions, &iter);
4969 	while (NULL != (function = (ZBX_DC_FUNCTION *)zbx_hashset_iter_next(&iter)))
4970 	{
4971 
4972 		if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)) ||
4973 				NULL == (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &function->triggerid)))
4974 		{
4975 			continue;
4976 		}
4977 
4978 		/* cache item - trigger link */
4979 		if (0 != item->update_triggers)
4980 		{
4981 			itemtrig.first = item;
4982 			itemtrig.second = trigger;
4983 			zbx_vector_ptr_pair_append(&itemtrigs, itemtrig);
4984 		}
4985 
4986 		/* disable functionality for triggers with expression containing */
4987 		/* disabled or not monitored items                               */
4988 
4989 		if (TRIGGER_FUNCTIONAL_FALSE == trigger->functional)
4990 			continue;
4991 
4992 		if (ITEM_STATUS_DISABLED == item->status ||
4993 				(NULL == (host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &item->hostid)) ||
4994 						HOST_STATUS_NOT_MONITORED == host->status))
4995 		{
4996 			trigger->functional = TRIGGER_FUNCTIONAL_FALSE;
4997 		}
4998 
4999 		if (1 == function->timer)
5000 			trigger->timer = ZBX_TRIGGER_TIMER_QUEUE;
5001 	}
5002 
5003 	zbx_vector_ptr_pair_sort(&itemtrigs, zbx_default_ptr_pair_ptr_compare_func);
5004 	zbx_vector_ptr_pair_uniq(&itemtrigs, zbx_default_ptr_pair_ptr_compare_func);
5005 
5006 	/* update links from items to triggers */
5007 	for (i = 0; i < itemtrigs.values_num; i++)
5008 	{
5009 		for (j = i + 1; j < itemtrigs.values_num; j++)
5010 		{
5011 			if (itemtrigs.values[i].first != itemtrigs.values[j].first)
5012 				break;
5013 		}
5014 
5015 		item = (ZBX_DC_ITEM *)itemtrigs.values[i].first;
5016 		item->update_triggers = 0;
5017 		item->triggers = (ZBX_DC_TRIGGER **)config->items.mem_realloc_func(item->triggers, (j - i + 1) * sizeof(ZBX_DC_TRIGGER *));
5018 
5019 		for (k = i; k < j; k++)
5020 			item->triggers[k - i] = (ZBX_DC_TRIGGER *)itemtrigs.values[k].second;
5021 
5022 		item->triggers[j - i] = NULL;
5023 
5024 		i = j - 1;
5025 	}
5026 
5027 	zbx_vector_ptr_pair_destroy(&itemtrigs);
5028 
5029 	/* add triggers to timer queue */
5030 	now = time(NULL);
5031 	zbx_binary_heap_clear(&config->timer_queue);
5032 	zbx_hashset_iter_reset(&config->triggers, &iter);
5033 	while (NULL != (trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
5034 	{
5035 		zbx_binary_heap_elem_t	elem;
5036 
5037 		if (TRIGGER_STATUS_DISABLED == trigger->status)
5038 			continue;
5039 
5040 		if (TRIGGER_FUNCTIONAL_FALSE == trigger->functional)
5041 			continue;
5042 
5043 		if (ZBX_TRIGGER_TIMER_QUEUE != trigger->timer)
5044 			continue;
5045 
5046 		trigger->nextcheck = dc_timer_calculate_nextcheck(now, trigger->triggerid);
5047 		elem.key = trigger->triggerid;
5048 		elem.data = (void *)trigger;
5049 		zbx_binary_heap_insert(&config->timer_queue, &elem);
5050 	}
5051 }
5052 
5053 /******************************************************************************
5054  *                                                                            *
5055  * Function: dc_hostgroups_update_cache                                       *
5056  *                                                                            *
5057  * Purpose: updates hostgroup name index and resets nested group lists        *
5058  *                                                                            *
5059  ******************************************************************************/
dc_hostgroups_update_cache(void)5060 static void	dc_hostgroups_update_cache(void)
5061 {
5062 	zbx_hashset_iter_t	iter;
5063 	zbx_dc_hostgroup_t	*group;
5064 
5065 	zbx_vector_ptr_sort(&config->hostgroups_name, dc_compare_hgroups);
5066 
5067 	zbx_hashset_iter_reset(&config->hostgroups, &iter);
5068 	while (NULL != (group = (zbx_dc_hostgroup_t *)zbx_hashset_iter_next(&iter)))
5069 	{
5070 		if (ZBX_DC_HOSTGROUP_FLAGS_NONE != group->flags)
5071 		{
5072 			group->flags = ZBX_DC_HOSTGROUP_FLAGS_NONE;
5073 			zbx_vector_uint64_destroy(&group->nested_groupids);
5074 		}
5075 	}
5076 }
5077 
5078 /******************************************************************************
5079  *                                                                            *
5080  * Function: DCsync_configuration                                             *
5081  *                                                                            *
5082  * Purpose: Synchronize configuration data from database                      *
5083  *                                                                            *
5084  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
5085  *                                                                            *
5086  ******************************************************************************/
DCsync_configuration(unsigned char mode)5087 void	DCsync_configuration(unsigned char mode)
5088 {
5089 	int		i, flags;
5090 	double		sec, csec, hsec, hisec, htsec, gmsec, hmsec, ifsec, isec, tsec, dsec, fsec, expr_sec, csec2,
5091 			hsec2, hisec2, htsec2, gmsec2, hmsec2, ifsec2, isec2, tsec2, dsec2, fsec2, expr_sec2,
5092 			action_sec, action_sec2, action_op_sec, action_op_sec2, action_condition_sec,
5093 			action_condition_sec2, trigger_tag_sec, trigger_tag_sec2, host_tag_sec, host_tag_sec2,
5094 			correlation_sec, correlation_sec2, corr_condition_sec, corr_condition_sec2, corr_operation_sec,
5095 			corr_operation_sec2, hgroups_sec, hgroups_sec2, itempp_sec, itempp_sec2, total, total2,
5096 			update_sec, maintenance_sec, maintenance_sec2;
5097 
5098 	zbx_dbsync_t	config_sync, hosts_sync, hi_sync, htmpl_sync, gmacro_sync, hmacro_sync, if_sync, items_sync,
5099 			template_items_sync, prototype_items_sync, triggers_sync, tdep_sync, func_sync, expr_sync,
5100 			action_sync, action_op_sync, action_condition_sync, trigger_tag_sync, host_tag_sync,
5101 			correlation_sync, corr_condition_sync, corr_operation_sync, hgroups_sync, itempp_sync,
5102 			maintenance_sync, maintenance_period_sync, maintenance_tag_sync, maintenance_group_sync,
5103 			maintenance_host_sync, hgroup_host_sync;
5104 
5105 	double		autoreg_csec, autoreg_csec2;
5106 	zbx_dbsync_t	autoreg_config_sync;
5107 	zbx_uint64_t	update_flags = 0;
5108 
5109 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5110 
5111 	zbx_dbsync_init_env(config);
5112 
5113 	/* global configuration must be synchronized directly with database */
5114 	zbx_dbsync_init(&config_sync, ZBX_DBSYNC_INIT);
5115 	zbx_dbsync_init(&autoreg_config_sync, mode);
5116 	zbx_dbsync_init(&hosts_sync, mode);
5117 	zbx_dbsync_init(&hi_sync, mode);
5118 	zbx_dbsync_init(&htmpl_sync, mode);
5119 	zbx_dbsync_init(&gmacro_sync, mode);
5120 	zbx_dbsync_init(&hmacro_sync, mode);
5121 	zbx_dbsync_init(&if_sync, mode);
5122 	zbx_dbsync_init(&items_sync, mode);
5123 	zbx_dbsync_init(&template_items_sync, mode);
5124 	zbx_dbsync_init(&prototype_items_sync, mode);
5125 	zbx_dbsync_init(&triggers_sync, mode);
5126 	zbx_dbsync_init(&tdep_sync, mode);
5127 	zbx_dbsync_init(&func_sync, mode);
5128 	zbx_dbsync_init(&expr_sync, mode);
5129 	zbx_dbsync_init(&action_sync, mode);
5130 
5131 	/* Action operation sync produces virtual rows with two columns - actionid, opflags. */
5132 	/* Because of this it cannot return the original database select and must always be  */
5133 	/* initialized in update mode.                                                       */
5134 	zbx_dbsync_init(&action_op_sync, ZBX_DBSYNC_UPDATE);
5135 
5136 	zbx_dbsync_init(&action_condition_sync, mode);
5137 	zbx_dbsync_init(&trigger_tag_sync, mode);
5138 	zbx_dbsync_init(&host_tag_sync, mode);
5139 	zbx_dbsync_init(&correlation_sync, mode);
5140 	zbx_dbsync_init(&corr_condition_sync, mode);
5141 	zbx_dbsync_init(&corr_operation_sync, mode);
5142 	zbx_dbsync_init(&hgroups_sync, mode);
5143 	zbx_dbsync_init(&hgroup_host_sync, mode);
5144 	zbx_dbsync_init(&itempp_sync, mode);
5145 
5146 	zbx_dbsync_init(&maintenance_sync, mode);
5147 	zbx_dbsync_init(&maintenance_period_sync, mode);
5148 	zbx_dbsync_init(&maintenance_tag_sync, mode);
5149 	zbx_dbsync_init(&maintenance_group_sync, mode);
5150 	zbx_dbsync_init(&maintenance_host_sync, mode);
5151 
5152 	sec = zbx_time();
5153 	if (FAIL == zbx_dbsync_compare_config(&config_sync))
5154 		goto out;
5155 	csec = zbx_time() - sec;
5156 
5157 	sec = zbx_time();
5158 	if (FAIL == zbx_dbsync_compare_autoreg_psk(&autoreg_config_sync))
5159 		goto out;
5160 	autoreg_csec = zbx_time() - sec;
5161 
5162 	/* sync global configuration settings */
5163 	START_SYNC;
5164 	sec = zbx_time();
5165 	DCsync_config(&config_sync, &flags);
5166 	csec2 = zbx_time() - sec;
5167 
5168 	sec = zbx_time();
5169 	DCsync_autoreg_config(&autoreg_config_sync);	/* must be done in the same cache locking with config sync */
5170 	autoreg_csec2 = zbx_time() - sec;
5171 	FINISH_SYNC;
5172 
5173 	/* sync macro related data, to support macro resolving during configuration sync */
5174 
5175 	sec = zbx_time();
5176 	if (FAIL == zbx_dbsync_compare_host_templates(&htmpl_sync))
5177 		goto out;
5178 	htsec = zbx_time() - sec;
5179 
5180 	sec = zbx_time();
5181 	if (FAIL == zbx_dbsync_compare_global_macros(&gmacro_sync))
5182 		goto out;
5183 	gmsec = zbx_time() - sec;
5184 
5185 	sec = zbx_time();
5186 	if (FAIL == zbx_dbsync_compare_host_macros(&hmacro_sync))
5187 		goto out;
5188 	hmsec = zbx_time() - sec;
5189 
5190 	sec = zbx_time();
5191 	if (FAIL == zbx_dbsync_compare_host_tags(&host_tag_sync))
5192 		goto out;
5193 	host_tag_sec = zbx_time() - sec;
5194 
5195 	START_SYNC;
5196 	sec = zbx_time();
5197 	DCsync_htmpls(&htmpl_sync);
5198 	htsec2 = zbx_time() - sec;
5199 
5200 	sec = zbx_time();
5201 	DCsync_gmacros(&gmacro_sync);
5202 	gmsec2 = zbx_time() - sec;
5203 
5204 	sec = zbx_time();
5205 	DCsync_hmacros(&hmacro_sync);
5206 	hmsec2 = zbx_time() - sec;
5207 
5208 	sec = zbx_time();
5209 	DCsync_host_tags(&host_tag_sync);
5210 	host_tag_sec2 = zbx_time() - sec;
5211 	FINISH_SYNC;
5212 
5213 	/* sync host data to support host lookups when resolving macros during configuration sync */
5214 
5215 	sec = zbx_time();
5216 	if (FAIL == zbx_dbsync_compare_hosts(&hosts_sync))
5217 		goto out;
5218 	hsec = zbx_time() - sec;
5219 
5220 	sec = zbx_time();
5221 	if (FAIL == zbx_dbsync_compare_host_inventory(&hi_sync))
5222 		goto out;
5223 	hisec = zbx_time() - sec;
5224 
5225 	sec = zbx_time();
5226 	if (FAIL == zbx_dbsync_compare_host_groups(&hgroups_sync))
5227 		goto out;
5228 	if (FAIL == zbx_dbsync_compare_host_group_hosts(&hgroup_host_sync))
5229 		goto out;
5230 	hgroups_sec = zbx_time() - sec;
5231 
5232 	sec = zbx_time();
5233 	if (FAIL == zbx_dbsync_compare_maintenances(&maintenance_sync))
5234 		goto out;
5235 	if (FAIL == zbx_dbsync_compare_maintenance_tags(&maintenance_tag_sync))
5236 		goto out;
5237 	if (FAIL == zbx_dbsync_compare_maintenance_periods(&maintenance_period_sync))
5238 		goto out;
5239 	if (FAIL == zbx_dbsync_compare_maintenance_groups(&maintenance_group_sync))
5240 		goto out;
5241 	if (FAIL == zbx_dbsync_compare_maintenance_hosts(&maintenance_host_sync))
5242 		goto out;
5243 	maintenance_sec = zbx_time() - sec;
5244 
5245 	START_SYNC;
5246 	sec = zbx_time();
5247 	DCsync_hosts(&hosts_sync);
5248 	hsec2 = zbx_time() - sec;
5249 
5250 	sec = zbx_time();
5251 	DCsync_host_inventory(&hi_sync);
5252 	hisec2 = zbx_time() - sec;
5253 
5254 	sec = zbx_time();
5255 	DCsync_hostgroups(&hgroups_sync);
5256 	DCsync_hostgroup_hosts(&hgroup_host_sync);
5257 	hgroups_sec2 = zbx_time() - sec;
5258 
5259 	sec = zbx_time();
5260 	DCsync_maintenances(&maintenance_sync);
5261 	DCsync_maintenance_tags(&maintenance_tag_sync);
5262 	DCsync_maintenance_groups(&maintenance_group_sync);
5263 	DCsync_maintenance_hosts(&maintenance_host_sync);
5264 	DCsync_maintenance_periods(&maintenance_period_sync);
5265 	maintenance_sec2 = zbx_time() - sec;
5266 
5267 	if (0 != hgroups_sync.add_num + hgroups_sync.update_num + hgroups_sync.remove_num)
5268 		update_flags |= ZBX_DBSYNC_UPDATE_HOST_GROUPS;
5269 
5270 	if (0 != maintenance_group_sync.add_num + maintenance_group_sync.update_num + maintenance_group_sync.remove_num)
5271 		update_flags |= ZBX_DBSYNC_UPDATE_MAINTENANCE_GROUPS;
5272 
5273 	if (0 != (update_flags & ZBX_DBSYNC_UPDATE_HOST_GROUPS))
5274 		dc_hostgroups_update_cache();
5275 
5276 	/* pre-cache nested groups used in maintenances to allow read lock */
5277 	/* during host maintenance update calculations                     */
5278 	if (0 != (update_flags & (ZBX_DBSYNC_UPDATE_HOST_GROUPS | ZBX_DBSYNC_UPDATE_MAINTENANCE_GROUPS)))
5279 		dc_maintenance_precache_nested_groups();
5280 
5281 	FINISH_SYNC;
5282 
5283 	/* sync item data to support item lookups when resolving macros during configuration sync */
5284 
5285 	sec = zbx_time();
5286 	if (FAIL == zbx_dbsync_compare_interfaces(&if_sync))
5287 		goto out;
5288 	ifsec = zbx_time() - sec;
5289 
5290 	sec = zbx_time();
5291 	if (FAIL == zbx_dbsync_compare_items(&items_sync))
5292 		goto out;
5293 
5294 	if (FAIL == zbx_dbsync_compare_template_items(&template_items_sync))
5295 		goto out;
5296 
5297 	if (FAIL == zbx_dbsync_compare_prototype_items(&prototype_items_sync))
5298 		goto out;
5299 	isec = zbx_time() - sec;
5300 
5301 	sec = zbx_time();
5302 	if (FAIL == zbx_dbsync_compare_item_preprocs(&itempp_sync))
5303 		goto out;
5304 	itempp_sec = zbx_time() - sec;
5305 
5306 	START_SYNC;
5307 
5308 	/* resolves macros for interface_snmpaddrs, must be after DCsync_hmacros() */
5309 	sec = zbx_time();
5310 	DCsync_interfaces(&if_sync);
5311 	ifsec2 = zbx_time() - sec;
5312 
5313 	/* relies on hosts, proxies and interfaces, must be after DCsync_{hosts,interfaces}() */
5314 	sec = zbx_time();
5315 	DCsync_items(&items_sync, flags);
5316 	DCsync_template_items(&template_items_sync);
5317 	DCsync_prototype_items(&prototype_items_sync);
5318 	isec2 = zbx_time() - sec;
5319 
5320 	/* relies on items, must be after DCsync_items() */
5321 	sec = zbx_time();
5322 	DCsync_item_preproc(&itempp_sync, sec);
5323 	itempp_sec2 = zbx_time() - sec;
5324 
5325 	config->item_sync_ts = time(NULL);
5326 	FINISH_SYNC;
5327 
5328 	dc_flush_history();	/* misconfigured items generate pseudo-historic values to become notsupported */
5329 
5330 	/* sync function data to support function lookups when resolving macros during configuration sync */
5331 
5332 	sec = zbx_time();
5333 	if (FAIL == zbx_dbsync_compare_functions(&func_sync))
5334 		goto out;
5335 	fsec = zbx_time() - sec;
5336 
5337 	START_SYNC;
5338 	sec = zbx_time();
5339 	DCsync_functions(&func_sync);
5340 	fsec2 = zbx_time() - sec;
5341 	FINISH_SYNC;
5342 
5343 	/* sync rest of the data */
5344 
5345 	sec = zbx_time();
5346 	if (FAIL == zbx_dbsync_compare_triggers(&triggers_sync))
5347 		goto out;
5348 	tsec = zbx_time() - sec;
5349 
5350 	sec = zbx_time();
5351 	if (FAIL == zbx_dbsync_compare_trigger_dependency(&tdep_sync))
5352 		goto out;
5353 	dsec = zbx_time() - sec;
5354 
5355 	sec = zbx_time();
5356 	if (FAIL == zbx_dbsync_compare_expressions(&expr_sync))
5357 		goto out;
5358 	expr_sec = zbx_time() - sec;
5359 
5360 	sec = zbx_time();
5361 	if (FAIL == zbx_dbsync_compare_actions(&action_sync))
5362 		goto out;
5363 	action_sec = zbx_time() - sec;
5364 
5365 	sec = zbx_time();
5366 	if (FAIL == zbx_dbsync_compare_action_ops(&action_op_sync))
5367 		goto out;
5368 	action_op_sec = zbx_time() - sec;
5369 
5370 	sec = zbx_time();
5371 	if (FAIL == zbx_dbsync_compare_action_conditions(&action_condition_sync))
5372 		goto out;
5373 	action_condition_sec = zbx_time() - sec;
5374 
5375 	sec = zbx_time();
5376 	if (FAIL == zbx_dbsync_compare_trigger_tags(&trigger_tag_sync))
5377 		goto out;
5378 	trigger_tag_sec = zbx_time() - sec;
5379 
5380 	sec = zbx_time();
5381 	if (FAIL == zbx_dbsync_compare_correlations(&correlation_sync))
5382 		goto out;
5383 	correlation_sec = zbx_time() - sec;
5384 
5385 	sec = zbx_time();
5386 	if (FAIL == zbx_dbsync_compare_corr_conditions(&corr_condition_sync))
5387 		goto out;
5388 	corr_condition_sec = zbx_time() - sec;
5389 
5390 	sec = zbx_time();
5391 	if (FAIL == zbx_dbsync_compare_corr_operations(&corr_operation_sync))
5392 		goto out;
5393 	corr_operation_sec = zbx_time() - sec;
5394 
5395 	START_SYNC;
5396 
5397 	sec = zbx_time();
5398 	DCsync_triggers(&triggers_sync);
5399 	tsec2 = zbx_time() - sec;
5400 
5401 	sec = zbx_time();
5402 	DCsync_trigdeps(&tdep_sync);
5403 	dsec2 = zbx_time() - sec;
5404 
5405 	sec = zbx_time();
5406 	DCsync_expressions(&expr_sync);
5407 	expr_sec2 = zbx_time() - sec;
5408 
5409 	sec = zbx_time();
5410 	DCsync_actions(&action_sync);
5411 	action_sec2 = zbx_time() - sec;
5412 
5413 	sec = zbx_time();
5414 	DCsync_action_ops(&action_op_sync);
5415 	action_op_sec2 = zbx_time() - sec;
5416 
5417 	sec = zbx_time();
5418 	DCsync_action_conditions(&action_condition_sync);
5419 	action_condition_sec2 = zbx_time() - sec;
5420 
5421 	sec = zbx_time();
5422 	/* relies on triggers, must be after DCsync_triggers() */
5423 	DCsync_trigger_tags(&trigger_tag_sync);
5424 	trigger_tag_sec2 = zbx_time() - sec;
5425 
5426 	sec = zbx_time();
5427 	DCsync_correlations(&correlation_sync);
5428 	correlation_sec2 = zbx_time() - sec;
5429 
5430 	sec = zbx_time();
5431 	/* relies on correlation rules, must be after DCsync_correlations() */
5432 	DCsync_corr_conditions(&corr_condition_sync);
5433 	corr_condition_sec2 = zbx_time() - sec;
5434 
5435 	sec = zbx_time();
5436 	/* relies on correlation rules, must be after DCsync_correlations() */
5437 	DCsync_corr_operations(&corr_operation_sync);
5438 	corr_operation_sec2 = zbx_time() - sec;
5439 
5440 	sec = zbx_time();
5441 
5442 	if (0 != hosts_sync.add_num + hosts_sync.update_num + hosts_sync.remove_num)
5443 		update_flags |= ZBX_DBSYNC_UPDATE_HOSTS;
5444 
5445 	if (0 != items_sync.add_num + items_sync.update_num + items_sync.remove_num)
5446 		update_flags |= ZBX_DBSYNC_UPDATE_ITEMS;
5447 
5448 	if (0 != func_sync.add_num + func_sync.update_num + func_sync.remove_num)
5449 		update_flags |= ZBX_DBSYNC_UPDATE_FUNCTIONS;
5450 
5451 	if (0 != triggers_sync.add_num + triggers_sync.update_num + triggers_sync.remove_num)
5452 		update_flags |= ZBX_DBSYNC_UPDATE_TRIGGERS;
5453 
5454 	if (0 != tdep_sync.add_num + tdep_sync.update_num + tdep_sync.remove_num)
5455 		update_flags |= ZBX_DBSYNC_UPDATE_TRIGGER_DEPENDENCY;
5456 
5457 	/* update trigger topology if trigger dependency was changed */
5458 	if (0 != (update_flags & ZBX_DBSYNC_UPDATE_TRIGGER_DEPENDENCY))
5459 		dc_trigger_update_topology();
5460 
5461 	/* update various trigger related links in cache */
5462 	if (0 != (update_flags & (ZBX_DBSYNC_UPDATE_HOSTS | ZBX_DBSYNC_UPDATE_ITEMS | ZBX_DBSYNC_UPDATE_FUNCTIONS |
5463 			ZBX_DBSYNC_UPDATE_TRIGGERS)))
5464 	{
5465 		dc_trigger_update_cache();
5466 	}
5467 
5468 	update_sec = zbx_time() - sec;
5469 
5470 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
5471 	{
5472 		total = csec + hsec + hisec + htsec + gmsec + hmsec + ifsec + isec + tsec + dsec + fsec + expr_sec +
5473 				action_sec + action_op_sec + action_condition_sec + trigger_tag_sec + correlation_sec +
5474 				corr_condition_sec + corr_operation_sec + hgroups_sec + itempp_sec + maintenance_sec;
5475 		total2 = csec2 + hsec2 + hisec2 + htsec2 + gmsec2 + hmsec2 + ifsec2 + isec2 + tsec2 + dsec2 + fsec2 +
5476 				expr_sec2 + action_op_sec2 + action_sec2 + action_condition_sec2 + trigger_tag_sec2 +
5477 				correlation_sec2 + corr_condition_sec2 + corr_operation_sec2 + hgroups_sec2 +
5478 				itempp_sec2 + maintenance_sec2 + update_sec;
5479 
5480 		zabbix_log(LOG_LEVEL_DEBUG, "%s() config     : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5481 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5482 				__func__, csec, csec2, config_sync.add_num, config_sync.update_num,
5483 				config_sync.remove_num);
5484 
5485 		total += autoreg_csec;
5486 		total2 += autoreg_csec2;
5487 		zabbix_log(LOG_LEVEL_DEBUG, "%s() autoreg    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5488 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5489 				__func__, autoreg_csec, autoreg_csec2, autoreg_config_sync.add_num,
5490 				autoreg_config_sync.update_num, autoreg_config_sync.remove_num);
5491 
5492 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5493 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5494 				__func__, hsec, hsec2, hosts_sync.add_num, hosts_sync.update_num,
5495 				hosts_sync.remove_num);
5496 		zabbix_log(LOG_LEVEL_DEBUG, "%s() host_invent: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5497 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5498 				__func__, hisec, hisec2, hi_sync.add_num, hi_sync.update_num,
5499 				hi_sync.remove_num);
5500 		zabbix_log(LOG_LEVEL_DEBUG, "%s() templates  : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5501 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5502 				__func__, htsec, htsec2, htmpl_sync.add_num, htmpl_sync.update_num,
5503 				htmpl_sync.remove_num);
5504 		zabbix_log(LOG_LEVEL_DEBUG, "%s() globmacros : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5505 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5506 				__func__, gmsec, gmsec2, gmacro_sync.add_num, gmacro_sync.update_num,
5507 				gmacro_sync.remove_num);
5508 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hostmacros : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5509 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5510 				__func__, hmsec, hmsec2, hmacro_sync.add_num, hmacro_sync.update_num,
5511 				hmacro_sync.remove_num);
5512 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfaces : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5513 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5514 				__func__, ifsec, ifsec2, if_sync.add_num, if_sync.update_num,
5515 				if_sync.remove_num);
5516 		zabbix_log(LOG_LEVEL_DEBUG, "%s() items      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5517 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5518 				__func__, isec, isec2, items_sync.add_num, items_sync.update_num,
5519 				items_sync.remove_num);
5520 		zabbix_log(LOG_LEVEL_DEBUG, "%s() template_items      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5521 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5522 				__func__, isec, isec2, template_items_sync.add_num,
5523 				template_items_sync.update_num, template_items_sync.remove_num);
5524 		zabbix_log(LOG_LEVEL_DEBUG, "%s() prototype_items      : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5525 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5526 				__func__, isec, isec2, prototype_items_sync.add_num,
5527 				prototype_items_sync.update_num, prototype_items_sync.remove_num);
5528 		zabbix_log(LOG_LEVEL_DEBUG, "%s() triggers   : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5529 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5530 				__func__, tsec, tsec2, triggers_sync.add_num, triggers_sync.update_num,
5531 				triggers_sync.remove_num);
5532 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trigdeps   : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5533 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5534 				__func__, dsec, dsec2, tdep_sync.add_num, tdep_sync.update_num,
5535 				tdep_sync.remove_num);
5536 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trig. tags : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5537 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5538 				__func__, trigger_tag_sec, trigger_tag_sec2, trigger_tag_sync.add_num,
5539 				trigger_tag_sync.update_num, trigger_tag_sync.remove_num);
5540 		zabbix_log(LOG_LEVEL_DEBUG, "%s() host tags : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5541 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5542 				__func__, host_tag_sec, host_tag_sec2, host_tag_sync.add_num,
5543 				host_tag_sync.update_num, host_tag_sync.remove_num);
5544 		zabbix_log(LOG_LEVEL_DEBUG, "%s() functions  : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5545 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5546 				__func__, fsec, fsec2, func_sync.add_num, func_sync.update_num,
5547 				func_sync.remove_num);
5548 		zabbix_log(LOG_LEVEL_DEBUG, "%s() expressions: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5549 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5550 				__func__, expr_sec, expr_sec2, expr_sync.add_num, expr_sync.update_num,
5551 				expr_sync.remove_num);
5552 		zabbix_log(LOG_LEVEL_DEBUG, "%s() actions    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5553 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5554 				__func__, action_sec, action_sec2, action_sync.add_num, action_sync.update_num,
5555 				action_sync.remove_num);
5556 		zabbix_log(LOG_LEVEL_DEBUG, "%s() operations : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5557 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5558 				__func__, action_op_sec, action_op_sec2, action_op_sync.add_num,
5559 				action_op_sync.update_num, action_op_sync.remove_num);
5560 		zabbix_log(LOG_LEVEL_DEBUG, "%s() conditions : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5561 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5562 				__func__, action_condition_sec, action_condition_sec2,
5563 				action_condition_sync.add_num, action_condition_sync.update_num,
5564 				action_condition_sync.remove_num);
5565 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr       : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5566 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5567 				__func__, correlation_sec, correlation_sec2, correlation_sync.add_num,
5568 				correlation_sync.update_num, correlation_sync.remove_num);
5569 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr_cond  : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5570 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5571 				__func__, corr_condition_sec, corr_condition_sec2, corr_condition_sync.add_num,
5572 				corr_condition_sync.update_num, corr_condition_sync.remove_num);
5573 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr_op    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5574 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5575 				__func__, corr_operation_sec, corr_operation_sec2, corr_operation_sync.add_num,
5576 				corr_operation_sync.update_num, corr_operation_sync.remove_num);
5577 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hgroups    : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5578 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5579 				__func__, hgroups_sec, hgroups_sec2, hgroups_sync.add_num,
5580 				hgroups_sync.update_num, hgroups_sync.remove_num);
5581 		zabbix_log(LOG_LEVEL_DEBUG, "%s() item pproc : sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5582 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5583 				__func__, itempp_sec, itempp_sec2, itempp_sync.add_num, itempp_sync.update_num,
5584 				itempp_sync.remove_num);
5585 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maintenance: sql:" ZBX_FS_DBL " sync:" ZBX_FS_DBL " sec ("
5586 				ZBX_FS_UI64 "/" ZBX_FS_UI64 "/" ZBX_FS_UI64 ").",
5587 				__func__, maintenance_sec, maintenance_sec2, maintenance_sync.add_num,
5588 				maintenance_sync.update_num, maintenance_sync.remove_num);
5589 
5590 		zabbix_log(LOG_LEVEL_DEBUG, "%s() reindex    : " ZBX_FS_DBL " sec.", __func__, update_sec);
5591 
5592 		zabbix_log(LOG_LEVEL_DEBUG, "%s() total sql  : " ZBX_FS_DBL " sec.", __func__, total);
5593 		zabbix_log(LOG_LEVEL_DEBUG, "%s() total sync : " ZBX_FS_DBL " sec.", __func__, total2);
5594 
5595 		zabbix_log(LOG_LEVEL_DEBUG, "%s() proxies    : %d (%d slots)", __func__,
5596 				config->proxies.num_data, config->proxies.num_slots);
5597 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts      : %d (%d slots)", __func__,
5598 				config->hosts.num_data, config->hosts.num_slots);
5599 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts_h    : %d (%d slots)", __func__,
5600 				config->hosts_h.num_data, config->hosts_h.num_slots);
5601 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hosts_p    : %d (%d slots)", __func__,
5602 				config->hosts_p.num_data, config->hosts_p.num_slots);
5603 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
5604 		zabbix_log(LOG_LEVEL_DEBUG, "%s() psks       : %d (%d slots)", __func__,
5605 				config->psks.num_data, config->psks.num_slots);
5606 #endif
5607 		zabbix_log(LOG_LEVEL_DEBUG, "%s() ipmihosts  : %d (%d slots)", __func__,
5608 				config->ipmihosts.num_data, config->ipmihosts.num_slots);
5609 		zabbix_log(LOG_LEVEL_DEBUG, "%s() host_invent: %d (%d slots)", __func__,
5610 				config->host_inventories.num_data, config->host_inventories.num_slots);
5611 		zabbix_log(LOG_LEVEL_DEBUG, "%s() htmpls     : %d (%d slots)", __func__,
5612 				config->htmpls.num_data, config->htmpls.num_slots);
5613 		zabbix_log(LOG_LEVEL_DEBUG, "%s() gmacros    : %d (%d slots)", __func__,
5614 				config->gmacros.num_data, config->gmacros.num_slots);
5615 		zabbix_log(LOG_LEVEL_DEBUG, "%s() gmacros_m  : %d (%d slots)", __func__,
5616 				config->gmacros_m.num_data, config->gmacros_m.num_slots);
5617 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hmacros    : %d (%d slots)", __func__,
5618 				config->hmacros.num_data, config->hmacros.num_slots);
5619 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hmacros_hm : %d (%d slots)", __func__,
5620 				config->hmacros_hm.num_data, config->hmacros_hm.num_slots);
5621 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfaces : %d (%d slots)", __func__,
5622 				config->interfaces.num_data, config->interfaces.num_slots);
5623 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfaces_snmp : %d (%d slots)", __func__,
5624 				config->interfaces_snmp.num_data, config->interfaces_snmp.num_slots);
5625 		zabbix_log(LOG_LEVEL_DEBUG, "%s() interfac_ht: %d (%d slots)", __func__,
5626 				config->interfaces_ht.num_data, config->interfaces_ht.num_slots);
5627 		zabbix_log(LOG_LEVEL_DEBUG, "%s() if_snmpitms: %d (%d slots)", __func__,
5628 				config->interface_snmpitems.num_data, config->interface_snmpitems.num_slots);
5629 		zabbix_log(LOG_LEVEL_DEBUG, "%s() if_snmpaddr: %d (%d slots)", __func__,
5630 				config->interface_snmpaddrs.num_data, config->interface_snmpaddrs.num_slots);
5631 		zabbix_log(LOG_LEVEL_DEBUG, "%s() items      : %d (%d slots)", __func__,
5632 				config->items.num_data, config->items.num_slots);
5633 		zabbix_log(LOG_LEVEL_DEBUG, "%s() items_hk   : %d (%d slots)", __func__,
5634 				config->items_hk.num_data, config->items_hk.num_slots);
5635 		zabbix_log(LOG_LEVEL_DEBUG, "%s() numitems   : %d (%d slots)", __func__,
5636 				config->numitems.num_data, config->numitems.num_slots);
5637 		zabbix_log(LOG_LEVEL_DEBUG, "%s() preprocitems: %d (%d slots)", __func__,
5638 				config->preprocitems.num_data, config->preprocitems.num_slots);
5639 		zabbix_log(LOG_LEVEL_DEBUG, "%s() preprocops : %d (%d slots)", __func__,
5640 				config->preprocops.num_data, config->preprocops.num_slots);
5641 		zabbix_log(LOG_LEVEL_DEBUG, "%s() snmpitems  : %d (%d slots)", __func__,
5642 				config->snmpitems.num_data, config->snmpitems.num_slots);
5643 		zabbix_log(LOG_LEVEL_DEBUG, "%s() ipmiitems  : %d (%d slots)", __func__,
5644 				config->ipmiitems.num_data, config->ipmiitems.num_slots);
5645 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trapitems  : %d (%d slots)", __func__,
5646 				config->trapitems.num_data, config->trapitems.num_slots);
5647 		zabbix_log(LOG_LEVEL_DEBUG, "%s() dependentitems  : %d (%d slots)", __func__,
5648 				config->dependentitems.num_data, config->dependentitems.num_slots);
5649 		zabbix_log(LOG_LEVEL_DEBUG, "%s() logitems   : %d (%d slots)", __func__,
5650 				config->logitems.num_data, config->logitems.num_slots);
5651 		zabbix_log(LOG_LEVEL_DEBUG, "%s() dbitems    : %d (%d slots)", __func__,
5652 				config->dbitems.num_data, config->dbitems.num_slots);
5653 		zabbix_log(LOG_LEVEL_DEBUG, "%s() sshitems   : %d (%d slots)", __func__,
5654 				config->sshitems.num_data, config->sshitems.num_slots);
5655 		zabbix_log(LOG_LEVEL_DEBUG, "%s() telnetitems: %d (%d slots)", __func__,
5656 				config->telnetitems.num_data, config->telnetitems.num_slots);
5657 		zabbix_log(LOG_LEVEL_DEBUG, "%s() simpleitems: %d (%d slots)", __func__,
5658 				config->simpleitems.num_data, config->simpleitems.num_slots);
5659 		zabbix_log(LOG_LEVEL_DEBUG, "%s() jmxitems   : %d (%d slots)", __func__,
5660 				config->jmxitems.num_data, config->jmxitems.num_slots);
5661 		zabbix_log(LOG_LEVEL_DEBUG, "%s() calcitems  : %d (%d slots)", __func__,
5662 				config->calcitems.num_data, config->calcitems.num_slots);
5663 		zabbix_log(LOG_LEVEL_DEBUG, "%s() httpitems  : %d (%d slots)", __func__,
5664 				config->httpitems.num_data, config->httpitems.num_slots);
5665 		zabbix_log(LOG_LEVEL_DEBUG, "%s() functions  : %d (%d slots)", __func__,
5666 				config->functions.num_data, config->functions.num_slots);
5667 		zabbix_log(LOG_LEVEL_DEBUG, "%s() triggers   : %d (%d slots)", __func__,
5668 				config->triggers.num_data, config->triggers.num_slots);
5669 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trigdeps   : %d (%d slots)", __func__,
5670 				config->trigdeps.num_data, config->trigdeps.num_slots);
5671 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trig. tags : %d (%d slots)", __func__,
5672 				config->trigger_tags.num_data, config->trigger_tags.num_slots);
5673 		zabbix_log(LOG_LEVEL_DEBUG, "%s() expressions: %d (%d slots)", __func__,
5674 				config->expressions.num_data, config->expressions.num_slots);
5675 
5676 		zabbix_log(LOG_LEVEL_DEBUG, "%s() actions    : %d (%d slots)", __func__,
5677 				config->actions.num_data, config->actions.num_slots);
5678 		zabbix_log(LOG_LEVEL_DEBUG, "%s() conditions : %d (%d slots)", __func__,
5679 				config->action_conditions.num_data, config->action_conditions.num_slots);
5680 
5681 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr.      : %d (%d slots)", __func__,
5682 				config->correlations.num_data, config->correlations.num_slots);
5683 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr. conds: %d (%d slots)", __func__,
5684 				config->corr_conditions.num_data, config->corr_conditions.num_slots);
5685 		zabbix_log(LOG_LEVEL_DEBUG, "%s() corr. ops  : %d (%d slots)", __func__,
5686 				config->corr_operations.num_data, config->corr_operations.num_slots);
5687 		zabbix_log(LOG_LEVEL_DEBUG, "%s() hgroups    : %d (%d slots)", __func__,
5688 				config->hostgroups.num_data, config->hostgroups.num_slots);
5689 		zabbix_log(LOG_LEVEL_DEBUG, "%s() item procs : %d (%d slots)", __func__,
5690 				config->preprocops.num_data, config->preprocops.num_slots);
5691 
5692 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maintenance: %d (%d slots)", __func__,
5693 				config->maintenances.num_data, config->maintenances.num_slots);
5694 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maint tags : %d (%d slots)", __func__,
5695 				config->maintenance_tags.num_data, config->maintenance_tags.num_slots);
5696 		zabbix_log(LOG_LEVEL_DEBUG, "%s() maint time : %d (%d slots)", __func__,
5697 				config->maintenance_periods.num_data, config->maintenance_periods.num_slots);
5698 
5699 		for (i = 0; ZBX_POLLER_TYPE_COUNT > i; i++)
5700 		{
5701 			zabbix_log(LOG_LEVEL_DEBUG, "%s() queue[%d]   : %d (%d allocated)", __func__,
5702 					i, config->queues[i].elems_num, config->queues[i].elems_alloc);
5703 		}
5704 
5705 		zabbix_log(LOG_LEVEL_DEBUG, "%s() pqueue     : %d (%d allocated)", __func__,
5706 				config->pqueue.elems_num, config->pqueue.elems_alloc);
5707 
5708 		zabbix_log(LOG_LEVEL_DEBUG, "%s() timer queue: %d (%d allocated)", __func__,
5709 				config->timer_queue.elems_num, config->timer_queue.elems_alloc);
5710 
5711 		zabbix_log(LOG_LEVEL_DEBUG, "%s() configfree : " ZBX_FS_DBL "%%", __func__,
5712 				100 * ((double)config_mem->free_size / config_mem->orig_size));
5713 
5714 		zabbix_log(LOG_LEVEL_DEBUG, "%s() strings    : %d (%d slots)", __func__,
5715 				config->strpool.num_data, config->strpool.num_slots);
5716 
5717 		zbx_mem_dump_stats(LOG_LEVEL_DEBUG, config_mem);
5718 	}
5719 out:
5720 	if (0 == sync_in_progress)
5721 	{
5722 		/* non recoverable database error is encountered */
5723 		THIS_SHOULD_NEVER_HAPPEN;
5724 		START_SYNC;
5725 	}
5726 
5727 	config->status->last_update = 0;
5728 	config->sync_ts = time(NULL);
5729 
5730 	FINISH_SYNC;
5731 
5732 	zbx_dbsync_clear(&config_sync);
5733 	zbx_dbsync_clear(&autoreg_config_sync);
5734 	zbx_dbsync_clear(&hosts_sync);
5735 	zbx_dbsync_clear(&hi_sync);
5736 	zbx_dbsync_clear(&htmpl_sync);
5737 	zbx_dbsync_clear(&gmacro_sync);
5738 	zbx_dbsync_clear(&hmacro_sync);
5739 	zbx_dbsync_clear(&host_tag_sync);
5740 	zbx_dbsync_clear(&if_sync);
5741 	zbx_dbsync_clear(&items_sync);
5742 	zbx_dbsync_clear(&template_items_sync);
5743 	zbx_dbsync_clear(&prototype_items_sync);
5744 	zbx_dbsync_clear(&triggers_sync);
5745 	zbx_dbsync_clear(&tdep_sync);
5746 	zbx_dbsync_clear(&func_sync);
5747 	zbx_dbsync_clear(&expr_sync);
5748 	zbx_dbsync_clear(&action_sync);
5749 	zbx_dbsync_clear(&action_op_sync);
5750 	zbx_dbsync_clear(&action_condition_sync);
5751 	zbx_dbsync_clear(&trigger_tag_sync);
5752 	zbx_dbsync_clear(&correlation_sync);
5753 	zbx_dbsync_clear(&corr_condition_sync);
5754 	zbx_dbsync_clear(&corr_operation_sync);
5755 	zbx_dbsync_clear(&hgroups_sync);
5756 	zbx_dbsync_clear(&itempp_sync);
5757 	zbx_dbsync_clear(&maintenance_sync);
5758 	zbx_dbsync_clear(&maintenance_period_sync);
5759 	zbx_dbsync_clear(&maintenance_tag_sync);
5760 	zbx_dbsync_clear(&maintenance_group_sync);
5761 	zbx_dbsync_clear(&maintenance_host_sync);
5762 	zbx_dbsync_clear(&hgroup_host_sync);
5763 
5764 	zbx_dbsync_free_env();
5765 
5766 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_TRACE))
5767 		DCdump_configuration();
5768 
5769 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5770 }
5771 
5772 /******************************************************************************
5773  *                                                                            *
5774  * Helper functions for configuration cache data structure element comparison *
5775  * and hash value calculation.                                                *
5776  *                                                                            *
5777  * The __config_mem_XXX_func(), __config_XXX_hash and __config_XXX_compare    *
5778  * functions are used only inside init_configuration_cache() function to      *
5779  * initialize internal data structures.                                       *
5780  *                                                                            *
5781  ******************************************************************************/
5782 
__config_item_hk_hash(const void * data)5783 static zbx_hash_t	__config_item_hk_hash(const void *data)
5784 {
5785 	const ZBX_DC_ITEM_HK	*item_hk = (const ZBX_DC_ITEM_HK *)data;
5786 
5787 	zbx_hash_t		hash;
5788 
5789 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&item_hk->hostid);
5790 	hash = ZBX_DEFAULT_STRING_HASH_ALGO(item_hk->key, strlen(item_hk->key), hash);
5791 
5792 	return hash;
5793 }
5794 
__config_item_hk_compare(const void * d1,const void * d2)5795 static int	__config_item_hk_compare(const void *d1, const void *d2)
5796 {
5797 	const ZBX_DC_ITEM_HK	*item_hk_1 = (const ZBX_DC_ITEM_HK *)d1;
5798 	const ZBX_DC_ITEM_HK	*item_hk_2 = (const ZBX_DC_ITEM_HK *)d2;
5799 
5800 	ZBX_RETURN_IF_NOT_EQUAL(item_hk_1->hostid, item_hk_2->hostid);
5801 
5802 	return item_hk_1->key == item_hk_2->key ? 0 : strcmp(item_hk_1->key, item_hk_2->key);
5803 }
5804 
__config_host_h_hash(const void * data)5805 static zbx_hash_t	__config_host_h_hash(const void *data)
5806 {
5807 	const ZBX_DC_HOST_H	*host_h = (const ZBX_DC_HOST_H *)data;
5808 
5809 	return ZBX_DEFAULT_STRING_HASH_ALGO(host_h->host, strlen(host_h->host), ZBX_DEFAULT_HASH_SEED);
5810 }
5811 
__config_host_h_compare(const void * d1,const void * d2)5812 static int	__config_host_h_compare(const void *d1, const void *d2)
5813 {
5814 	const ZBX_DC_HOST_H	*host_h_1 = (const ZBX_DC_HOST_H *)d1;
5815 	const ZBX_DC_HOST_H	*host_h_2 = (const ZBX_DC_HOST_H *)d2;
5816 
5817 	return host_h_1->host == host_h_2->host ? 0 : strcmp(host_h_1->host, host_h_2->host);
5818 }
5819 
__config_gmacro_m_hash(const void * data)5820 static zbx_hash_t	__config_gmacro_m_hash(const void *data)
5821 {
5822 	const ZBX_DC_GMACRO_M	*gmacro_m = (const ZBX_DC_GMACRO_M *)data;
5823 
5824 	zbx_hash_t		hash;
5825 
5826 	hash = ZBX_DEFAULT_STRING_HASH_FUNC(gmacro_m->macro);
5827 
5828 	return hash;
5829 }
5830 
__config_gmacro_m_compare(const void * d1,const void * d2)5831 static int	__config_gmacro_m_compare(const void *d1, const void *d2)
5832 {
5833 	const ZBX_DC_GMACRO_M	*gmacro_m_1 = (const ZBX_DC_GMACRO_M *)d1;
5834 	const ZBX_DC_GMACRO_M	*gmacro_m_2 = (const ZBX_DC_GMACRO_M *)d2;
5835 
5836 	return gmacro_m_1->macro == gmacro_m_2->macro ? 0 : strcmp(gmacro_m_1->macro, gmacro_m_2->macro);
5837 }
5838 
__config_hmacro_hm_hash(const void * data)5839 static zbx_hash_t	__config_hmacro_hm_hash(const void *data)
5840 {
5841 	const ZBX_DC_HMACRO_HM	*hmacro_hm = (const ZBX_DC_HMACRO_HM *)data;
5842 
5843 	zbx_hash_t		hash;
5844 
5845 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&hmacro_hm->hostid);
5846 	hash = ZBX_DEFAULT_STRING_HASH_ALGO(hmacro_hm->macro, strlen(hmacro_hm->macro), hash);
5847 
5848 	return hash;
5849 }
5850 
__config_hmacro_hm_compare(const void * d1,const void * d2)5851 static int	__config_hmacro_hm_compare(const void *d1, const void *d2)
5852 {
5853 	const ZBX_DC_HMACRO_HM	*hmacro_hm_1 = (const ZBX_DC_HMACRO_HM *)d1;
5854 	const ZBX_DC_HMACRO_HM	*hmacro_hm_2 = (const ZBX_DC_HMACRO_HM *)d2;
5855 
5856 	ZBX_RETURN_IF_NOT_EQUAL(hmacro_hm_1->hostid, hmacro_hm_2->hostid);
5857 
5858 	return hmacro_hm_1->macro == hmacro_hm_2->macro ? 0 : strcmp(hmacro_hm_1->macro, hmacro_hm_2->macro);
5859 }
5860 
__config_interface_ht_hash(const void * data)5861 static zbx_hash_t	__config_interface_ht_hash(const void *data)
5862 {
5863 	const ZBX_DC_INTERFACE_HT	*interface_ht = (const ZBX_DC_INTERFACE_HT *)data;
5864 
5865 	zbx_hash_t			hash;
5866 
5867 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&interface_ht->hostid);
5868 	hash = ZBX_DEFAULT_STRING_HASH_ALGO((char *)&interface_ht->type, 1, hash);
5869 
5870 	return hash;
5871 }
5872 
__config_interface_ht_compare(const void * d1,const void * d2)5873 static int	__config_interface_ht_compare(const void *d1, const void *d2)
5874 {
5875 	const ZBX_DC_INTERFACE_HT	*interface_ht_1 = (const ZBX_DC_INTERFACE_HT *)d1;
5876 	const ZBX_DC_INTERFACE_HT	*interface_ht_2 = (const ZBX_DC_INTERFACE_HT *)d2;
5877 
5878 	ZBX_RETURN_IF_NOT_EQUAL(interface_ht_1->hostid, interface_ht_2->hostid);
5879 	ZBX_RETURN_IF_NOT_EQUAL(interface_ht_1->type, interface_ht_2->type);
5880 
5881 	return 0;
5882 }
5883 
__config_interface_addr_hash(const void * data)5884 static zbx_hash_t	__config_interface_addr_hash(const void *data)
5885 {
5886 	const ZBX_DC_INTERFACE_ADDR	*interface_addr = (const ZBX_DC_INTERFACE_ADDR *)data;
5887 
5888 	return ZBX_DEFAULT_STRING_HASH_ALGO(interface_addr->addr, strlen(interface_addr->addr), ZBX_DEFAULT_HASH_SEED);
5889 }
5890 
__config_interface_addr_compare(const void * d1,const void * d2)5891 static int	__config_interface_addr_compare(const void *d1, const void *d2)
5892 {
5893 	const ZBX_DC_INTERFACE_ADDR	*interface_addr_1 = (const ZBX_DC_INTERFACE_ADDR *)d1;
5894 	const ZBX_DC_INTERFACE_ADDR	*interface_addr_2 = (const ZBX_DC_INTERFACE_ADDR *)d2;
5895 
5896 	return (interface_addr_1->addr == interface_addr_2->addr ? 0 : strcmp(interface_addr_1->addr, interface_addr_2->addr));
5897 }
5898 
__config_snmp_item_compare(const ZBX_DC_ITEM * i1,const ZBX_DC_ITEM * i2)5899 static int	__config_snmp_item_compare(const ZBX_DC_ITEM *i1, const ZBX_DC_ITEM *i2)
5900 {
5901 	const ZBX_DC_SNMPITEM	*s1;
5902 	const ZBX_DC_SNMPITEM	*s2;
5903 
5904 	unsigned char		f1;
5905 	unsigned char		f2;
5906 
5907 	ZBX_RETURN_IF_NOT_EQUAL(i1->interfaceid, i2->interfaceid);
5908 	ZBX_RETURN_IF_NOT_EQUAL(i1->type, i2->type);
5909 
5910 	f1 = ZBX_FLAG_DISCOVERY_RULE & i1->flags;
5911 	f2 = ZBX_FLAG_DISCOVERY_RULE & i2->flags;
5912 
5913 	ZBX_RETURN_IF_NOT_EQUAL(f1, f2);
5914 
5915 	s1 = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &i1->itemid);
5916 	s2 = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &i2->itemid);
5917 
5918 	ZBX_RETURN_IF_NOT_EQUAL(s1->snmp_oid_type, s2->snmp_oid_type);
5919 
5920 	return 0;
5921 }
5922 
__config_heap_elem_compare(const void * d1,const void * d2)5923 static int	__config_heap_elem_compare(const void *d1, const void *d2)
5924 {
5925 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
5926 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
5927 
5928 	const ZBX_DC_ITEM		*i1 = (const ZBX_DC_ITEM *)e1->data;
5929 	const ZBX_DC_ITEM		*i2 = (const ZBX_DC_ITEM *)e2->data;
5930 
5931 	ZBX_RETURN_IF_NOT_EQUAL(i1->nextcheck, i2->nextcheck);
5932 	ZBX_RETURN_IF_NOT_EQUAL(i1->queue_priority, i2->queue_priority);
5933 
5934 	if (ITEM_TYPE_SNMP != i1->type)
5935 	{
5936 		if (ITEM_TYPE_SNMP != i2->type)
5937 			return 0;
5938 
5939 		return -1;
5940 	}
5941 	else
5942 	{
5943 		if (ITEM_TYPE_SNMP != i2->type)
5944 			return +1;
5945 
5946 		return __config_snmp_item_compare(i1, i2);
5947 	}
5948 }
5949 
__config_pinger_elem_compare(const void * d1,const void * d2)5950 static int	__config_pinger_elem_compare(const void *d1, const void *d2)
5951 {
5952 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
5953 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
5954 
5955 	const ZBX_DC_ITEM		*i1 = (const ZBX_DC_ITEM *)e1->data;
5956 	const ZBX_DC_ITEM		*i2 = (const ZBX_DC_ITEM *)e2->data;
5957 
5958 	ZBX_RETURN_IF_NOT_EQUAL(i1->nextcheck, i2->nextcheck);
5959 	ZBX_RETURN_IF_NOT_EQUAL(i1->queue_priority, i2->queue_priority);
5960 	ZBX_RETURN_IF_NOT_EQUAL(i1->interfaceid, i2->interfaceid);
5961 
5962 	return 0;
5963 }
5964 
__config_java_item_compare(const ZBX_DC_ITEM * i1,const ZBX_DC_ITEM * i2)5965 static int	__config_java_item_compare(const ZBX_DC_ITEM *i1, const ZBX_DC_ITEM *i2)
5966 {
5967 	const ZBX_DC_JMXITEM	*j1;
5968 	const ZBX_DC_JMXITEM	*j2;
5969 
5970 	ZBX_RETURN_IF_NOT_EQUAL(i1->interfaceid, i2->interfaceid);
5971 
5972 	j1 = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &i1->itemid);
5973 	j2 = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &i2->itemid);
5974 
5975 	ZBX_RETURN_IF_NOT_EQUAL(j1->username, j2->username);
5976 	ZBX_RETURN_IF_NOT_EQUAL(j1->password, j2->password);
5977 	ZBX_RETURN_IF_NOT_EQUAL(j1->jmx_endpoint, j2->jmx_endpoint);
5978 
5979 	return 0;
5980 }
5981 
__config_java_elem_compare(const void * d1,const void * d2)5982 static int	__config_java_elem_compare(const void *d1, const void *d2)
5983 {
5984 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
5985 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
5986 
5987 	const ZBX_DC_ITEM		*i1 = (const ZBX_DC_ITEM *)e1->data;
5988 	const ZBX_DC_ITEM		*i2 = (const ZBX_DC_ITEM *)e2->data;
5989 
5990 	ZBX_RETURN_IF_NOT_EQUAL(i1->nextcheck, i2->nextcheck);
5991 	ZBX_RETURN_IF_NOT_EQUAL(i1->queue_priority, i2->queue_priority);
5992 
5993 	return __config_java_item_compare(i1, i2);
5994 }
5995 
__config_proxy_compare(const void * d1,const void * d2)5996 static int	__config_proxy_compare(const void *d1, const void *d2)
5997 {
5998 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
5999 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6000 
6001 	const ZBX_DC_PROXY		*p1 = (const ZBX_DC_PROXY *)e1->data;
6002 	const ZBX_DC_PROXY		*p2 = (const ZBX_DC_PROXY *)e2->data;
6003 
6004 	ZBX_RETURN_IF_NOT_EQUAL(p1->nextcheck, p2->nextcheck);
6005 
6006 	return 0;
6007 }
6008 
6009 /* hash and compare functions for expressions hashset */
6010 
__config_regexp_hash(const void * data)6011 static zbx_hash_t	__config_regexp_hash(const void *data)
6012 {
6013 	const ZBX_DC_REGEXP	*regexp = (const ZBX_DC_REGEXP *)data;
6014 
6015 	return ZBX_DEFAULT_STRING_HASH_FUNC(regexp->name);
6016 }
6017 
__config_regexp_compare(const void * d1,const void * d2)6018 static int	__config_regexp_compare(const void *d1, const void *d2)
6019 {
6020 	const ZBX_DC_REGEXP	*r1 = (const ZBX_DC_REGEXP *)d1;
6021 	const ZBX_DC_REGEXP	*r2 = (const ZBX_DC_REGEXP *)d2;
6022 
6023 	return r1->name == r2->name ? 0 : strcmp(r1->name, r2->name);
6024 }
6025 
6026 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
__config_psk_hash(const void * data)6027 static zbx_hash_t	__config_psk_hash(const void *data)
6028 {
6029 	const ZBX_DC_PSK	*psk_i = (const ZBX_DC_PSK *)data;
6030 
6031 	return ZBX_DEFAULT_STRING_HASH_ALGO(psk_i->tls_psk_identity, strlen(psk_i->tls_psk_identity),
6032 			ZBX_DEFAULT_HASH_SEED);
6033 }
6034 
__config_psk_compare(const void * d1,const void * d2)6035 static int	__config_psk_compare(const void *d1, const void *d2)
6036 {
6037 	const ZBX_DC_PSK	*psk_1 = (const ZBX_DC_PSK *)d1;
6038 	const ZBX_DC_PSK	*psk_2 = (const ZBX_DC_PSK *)d2;
6039 
6040 	return psk_1->tls_psk_identity == psk_2->tls_psk_identity ? 0 : strcmp(psk_1->tls_psk_identity,
6041 			psk_2->tls_psk_identity);
6042 }
6043 #endif
6044 
__config_timer_compare(const void * d1,const void * d2)6045 static int	__config_timer_compare(const void *d1, const void *d2)
6046 {
6047 	const zbx_binary_heap_elem_t	*e1 = (const zbx_binary_heap_elem_t *)d1;
6048 	const zbx_binary_heap_elem_t	*e2 = (const zbx_binary_heap_elem_t *)d2;
6049 
6050 	const ZBX_DC_TRIGGER		*t1 = (const ZBX_DC_TRIGGER *)e1->data;
6051 	const ZBX_DC_TRIGGER		*t2 = (const ZBX_DC_TRIGGER *)e2->data;
6052 
6053 	ZBX_RETURN_IF_NOT_EQUAL(t1->nextcheck, t2->nextcheck);
6054 
6055 	return 0;
6056 }
6057 
__config_data_session_hash(const void * data)6058 static zbx_hash_t	__config_data_session_hash(const void *data)
6059 {
6060 	const zbx_data_session_t	*session = (const zbx_data_session_t *)data;
6061 	zbx_hash_t			hash;
6062 
6063 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&session->hostid);
6064 	return ZBX_DEFAULT_STRING_HASH_ALGO(session->token, strlen(session->token), hash);
6065 }
6066 
__config_data_session_compare(const void * d1,const void * d2)6067 static int	__config_data_session_compare(const void *d1, const void *d2)
6068 {
6069 	const zbx_data_session_t	*s1 = (const zbx_data_session_t *)d1;
6070 	const zbx_data_session_t	*s2 = (const zbx_data_session_t *)d2;
6071 
6072 	ZBX_RETURN_IF_NOT_EQUAL(s1->hostid, s2->hostid);
6073 	return strcmp(s1->token, s2->token);
6074 }
6075 
6076 /******************************************************************************
6077  *                                                                            *
6078  * Function: init_configuration_cache                                         *
6079  *                                                                            *
6080  * Purpose: Allocate shared memory for configuration cache                    *
6081  *                                                                            *
6082  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
6083  *                                                                            *
6084  ******************************************************************************/
init_configuration_cache(char ** error)6085 int	init_configuration_cache(char **error)
6086 {
6087 	int	i, ret;
6088 
6089 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() size:" ZBX_FS_UI64, __func__, CONFIG_CONF_CACHE_SIZE);
6090 
6091 	if (SUCCEED != (ret = zbx_rwlock_create(&config_lock, ZBX_RWLOCK_CONFIG, error)))
6092 		goto out;
6093 
6094 	if (SUCCEED != (ret = zbx_mem_create(&config_mem, CONFIG_CONF_CACHE_SIZE, "configuration cache",
6095 			"CacheSize", 0, error)))
6096 	{
6097 		goto out;
6098 	}
6099 
6100 	config = (ZBX_DC_CONFIG *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_CONFIG) +
6101 			CONFIG_TIMER_FORKS * sizeof(zbx_vector_ptr_t));
6102 
6103 #define CREATE_HASHSET(hashset, hashset_size)									\
6104 														\
6105 	CREATE_HASHSET_EXT(hashset, hashset_size, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC)
6106 
6107 #define CREATE_HASHSET_EXT(hashset, hashset_size, hash_func, compare_func)					\
6108 														\
6109 	zbx_hashset_create_ext(&hashset, hashset_size, hash_func, compare_func, NULL,				\
6110 			__config_mem_malloc_func, __config_mem_realloc_func, __config_mem_free_func)
6111 
6112 	CREATE_HASHSET(config->items, 100);
6113 	CREATE_HASHSET(config->numitems, 0);
6114 	CREATE_HASHSET(config->snmpitems, 0);
6115 	CREATE_HASHSET(config->ipmiitems, 0);
6116 	CREATE_HASHSET(config->trapitems, 0);
6117 	CREATE_HASHSET(config->dependentitems, 0);
6118 	CREATE_HASHSET(config->logitems, 0);
6119 	CREATE_HASHSET(config->dbitems, 0);
6120 	CREATE_HASHSET(config->sshitems, 0);
6121 	CREATE_HASHSET(config->telnetitems, 0);
6122 	CREATE_HASHSET(config->simpleitems, 0);
6123 	CREATE_HASHSET(config->jmxitems, 0);
6124 	CREATE_HASHSET(config->calcitems, 0);
6125 	CREATE_HASHSET(config->masteritems, 0);
6126 	CREATE_HASHSET(config->preprocitems, 0);
6127 	CREATE_HASHSET(config->httpitems, 0);
6128 	CREATE_HASHSET(config->template_items, 0);
6129 	CREATE_HASHSET(config->prototype_items, 0);
6130 	CREATE_HASHSET(config->functions, 100);
6131 	CREATE_HASHSET(config->triggers, 100);
6132 	CREATE_HASHSET(config->trigdeps, 0);
6133 	CREATE_HASHSET(config->hosts, 10);
6134 	CREATE_HASHSET(config->proxies, 0);
6135 	CREATE_HASHSET(config->host_inventories, 0);
6136 	CREATE_HASHSET(config->host_inventories_auto, 0);
6137 	CREATE_HASHSET(config->ipmihosts, 0);
6138 	CREATE_HASHSET(config->htmpls, 0);
6139 	CREATE_HASHSET(config->gmacros, 0);
6140 	CREATE_HASHSET(config->hmacros, 0);
6141 	CREATE_HASHSET(config->interfaces, 10);
6142 	CREATE_HASHSET(config->interfaces_snmp, 0);
6143 	CREATE_HASHSET(config->interface_snmpitems, 0);
6144 	CREATE_HASHSET(config->expressions, 0);
6145 	CREATE_HASHSET(config->actions, 0);
6146 	CREATE_HASHSET(config->action_conditions, 0);
6147 	CREATE_HASHSET(config->trigger_tags, 0);
6148 	CREATE_HASHSET(config->host_tags, 0);
6149 	CREATE_HASHSET(config->host_tags_index, 0);
6150 	CREATE_HASHSET(config->correlations, 0);
6151 	CREATE_HASHSET(config->corr_conditions, 0);
6152 	CREATE_HASHSET(config->corr_operations, 0);
6153 	CREATE_HASHSET(config->hostgroups, 0);
6154 	zbx_vector_ptr_create_ext(&config->hostgroups_name, __config_mem_malloc_func, __config_mem_realloc_func,
6155 			__config_mem_free_func);
6156 
6157 	CREATE_HASHSET(config->preprocops, 0);
6158 
6159 	CREATE_HASHSET(config->maintenances, 0);
6160 	CREATE_HASHSET(config->maintenance_periods, 0);
6161 	CREATE_HASHSET(config->maintenance_tags, 0);
6162 
6163 	CREATE_HASHSET_EXT(config->items_hk, 100, __config_item_hk_hash, __config_item_hk_compare);
6164 	CREATE_HASHSET_EXT(config->hosts_h, 10, __config_host_h_hash, __config_host_h_compare);
6165 	CREATE_HASHSET_EXT(config->hosts_p, 0, __config_host_h_hash, __config_host_h_compare);
6166 	CREATE_HASHSET_EXT(config->gmacros_m, 0, __config_gmacro_m_hash, __config_gmacro_m_compare);
6167 	CREATE_HASHSET_EXT(config->hmacros_hm, 0, __config_hmacro_hm_hash, __config_hmacro_hm_compare);
6168 	CREATE_HASHSET_EXT(config->interfaces_ht, 10, __config_interface_ht_hash, __config_interface_ht_compare);
6169 	CREATE_HASHSET_EXT(config->interface_snmpaddrs, 0, __config_interface_addr_hash, __config_interface_addr_compare);
6170 	CREATE_HASHSET_EXT(config->regexps, 0, __config_regexp_hash, __config_regexp_compare);
6171 
6172 	CREATE_HASHSET_EXT(config->strpool, 100, __config_strpool_hash, __config_strpool_compare);
6173 
6174 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
6175 	CREATE_HASHSET_EXT(config->psks, 0, __config_psk_hash, __config_psk_compare);
6176 #endif
6177 
6178 	for (i = 0; i < ZBX_POLLER_TYPE_COUNT; i++)
6179 	{
6180 		switch (i)
6181 		{
6182 			case ZBX_POLLER_TYPE_JAVA:
6183 				zbx_binary_heap_create_ext(&config->queues[i],
6184 						__config_java_elem_compare,
6185 						ZBX_BINARY_HEAP_OPTION_DIRECT,
6186 						__config_mem_malloc_func,
6187 						__config_mem_realloc_func,
6188 						__config_mem_free_func);
6189 				break;
6190 			case ZBX_POLLER_TYPE_PINGER:
6191 				zbx_binary_heap_create_ext(&config->queues[i],
6192 						__config_pinger_elem_compare,
6193 						ZBX_BINARY_HEAP_OPTION_DIRECT,
6194 						__config_mem_malloc_func,
6195 						__config_mem_realloc_func,
6196 						__config_mem_free_func);
6197 				break;
6198 			default:
6199 				zbx_binary_heap_create_ext(&config->queues[i],
6200 						__config_heap_elem_compare,
6201 						ZBX_BINARY_HEAP_OPTION_DIRECT,
6202 						__config_mem_malloc_func,
6203 						__config_mem_realloc_func,
6204 						__config_mem_free_func);
6205 				break;
6206 		}
6207 	}
6208 
6209 	zbx_binary_heap_create_ext(&config->pqueue,
6210 					__config_proxy_compare,
6211 					ZBX_BINARY_HEAP_OPTION_DIRECT,
6212 					__config_mem_malloc_func,
6213 					__config_mem_realloc_func,
6214 					__config_mem_free_func);
6215 
6216 	zbx_binary_heap_create_ext(&config->timer_queue,
6217 					__config_timer_compare,
6218 					ZBX_BINARY_HEAP_OPTION_DIRECT,
6219 					__config_mem_malloc_func,
6220 					__config_mem_realloc_func,
6221 					__config_mem_free_func);
6222 
6223 	CREATE_HASHSET_EXT(config->data_sessions, 0, __config_data_session_hash, __config_data_session_compare);
6224 
6225 	config->config = NULL;
6226 
6227 	config->status = (ZBX_DC_STATUS *)__config_mem_malloc_func(NULL, sizeof(ZBX_DC_STATUS));
6228 	config->status->last_update = 0;
6229 
6230 	config->availability_diff_ts = 0;
6231 	config->sync_ts = 0;
6232 	config->item_sync_ts = 0;
6233 
6234 	config->internal_actions = 0;
6235 
6236 	/* maintenance data are used only when timers are defined (server) */
6237 	if (0 != CONFIG_TIMER_FORKS)
6238 	{
6239 		config->maintenance_update = ZBX_MAINTENANCE_UPDATE_FALSE;
6240 		config->maintenance_update_flags = (zbx_uint64_t *)__config_mem_malloc_func(NULL, sizeof(zbx_uint64_t) *
6241 				ZBX_MAINTENANCE_UPDATE_FLAGS_NUM());
6242 		memset(config->maintenance_update_flags, 0, sizeof(zbx_uint64_t) * ZBX_MAINTENANCE_UPDATE_FLAGS_NUM());
6243 	}
6244 
6245 	config->proxy_lastaccess_ts = time(NULL);
6246 
6247 	/* create data session token for proxies */
6248 	if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
6249 	{
6250 		char	*token;
6251 
6252 		token = zbx_create_token(0);
6253 		config->session_token = dc_strdup(token);
6254 		zbx_free(token);
6255 	}
6256 	else
6257 		config->session_token = NULL;
6258 
6259 #undef CREATE_HASHSET
6260 #undef CREATE_HASHSET_EXT
6261 out:
6262 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
6263 
6264 	return ret;
6265 }
6266 
6267 /******************************************************************************
6268  *                                                                            *
6269  * Function: free_configuration_cache                                         *
6270  *                                                                            *
6271  * Purpose: Free memory allocated for configuration cache                     *
6272  *                                                                            *
6273  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
6274  *                                                                            *
6275  ******************************************************************************/
free_configuration_cache(void)6276 void	free_configuration_cache(void)
6277 {
6278 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
6279 
6280 	WRLOCK_CACHE;
6281 
6282 	config = NULL;
6283 
6284 	UNLOCK_CACHE;
6285 
6286 	zbx_rwlock_destroy(&config_lock);
6287 
6288 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
6289 }
6290 
6291 /******************************************************************************
6292  *                                                                            *
6293  * Function: in_maintenance_without_data_collection                           *
6294  *                                                                            *
6295  * Parameters: maintenance_status - [IN] maintenance status                   *
6296  *                                       HOST_MAINTENANCE_STATUS_* flag       *
6297  *             maintenance_type   - [IN] maintenance type                     *
6298  *                                       MAINTENANCE_TYPE_* flag              *
6299  *             type               - [IN] item type                            *
6300  *                                       ITEM_TYPE_* flag                     *
6301  *                                                                            *
6302  * Return value: SUCCEED if host in maintenance without data collection       *
6303  *               FAIL otherwise                                               *
6304  *                                                                            *
6305  ******************************************************************************/
in_maintenance_without_data_collection(unsigned char maintenance_status,unsigned char maintenance_type,unsigned char type)6306 int	in_maintenance_without_data_collection(unsigned char maintenance_status, unsigned char maintenance_type,
6307 		unsigned char type)
6308 {
6309 	if (HOST_MAINTENANCE_STATUS_ON != maintenance_status)
6310 		return FAIL;
6311 
6312 	if (MAINTENANCE_TYPE_NODATA != maintenance_type)
6313 		return FAIL;
6314 
6315 	if (ITEM_TYPE_INTERNAL == type)
6316 		return FAIL;
6317 
6318 	return SUCCEED;
6319 }
6320 
DCget_host(DC_HOST * dst_host,const ZBX_DC_HOST * src_host,unsigned int mode)6321 static void	DCget_host(DC_HOST *dst_host, const ZBX_DC_HOST *src_host, unsigned int mode)
6322 {
6323 	const ZBX_DC_IPMIHOST		*ipmihost;
6324 	const ZBX_DC_HOST_INVENTORY	*host_inventory;
6325 
6326 	dst_host->hostid = src_host->hostid;
6327 	dst_host->proxy_hostid = src_host->proxy_hostid;
6328 	dst_host->status = src_host->status;
6329 
6330 	strscpy(dst_host->host, src_host->host);
6331 
6332 	if (ZBX_ITEM_GET_HOSTNAME & mode)
6333 		zbx_strlcpy_utf8(dst_host->name, src_host->name, sizeof(dst_host->name));
6334 
6335 	if (ZBX_ITEM_GET_MAINTENANCE & mode)
6336 	{
6337 		dst_host->maintenance_status = src_host->maintenance_status;
6338 		dst_host->maintenance_type = src_host->maintenance_type;
6339 		dst_host->maintenance_from = src_host->maintenance_from;
6340 	}
6341 
6342 	if (ZBX_ITEM_GET_HOSTINFO & mode)
6343 	{
6344 		dst_host->errors_from = src_host->errors_from;
6345 		dst_host->available = src_host->available;
6346 		dst_host->disable_until = src_host->disable_until;
6347 		dst_host->snmp_errors_from = src_host->snmp_errors_from;
6348 		dst_host->snmp_available = src_host->snmp_available;
6349 		dst_host->snmp_disable_until = src_host->snmp_disable_until;
6350 		dst_host->ipmi_errors_from = src_host->ipmi_errors_from;
6351 		dst_host->ipmi_available = src_host->ipmi_available;
6352 		dst_host->ipmi_disable_until = src_host->ipmi_disable_until;
6353 		dst_host->jmx_errors_from = src_host->jmx_errors_from;
6354 		dst_host->jmx_available = src_host->jmx_available;
6355 		dst_host->jmx_disable_until = src_host->jmx_disable_until;
6356 		strscpy(dst_host->error, src_host->error);
6357 		strscpy(dst_host->snmp_error, src_host->snmp_error);
6358 		strscpy(dst_host->ipmi_error, src_host->ipmi_error);
6359 		strscpy(dst_host->jmx_error, src_host->jmx_error);
6360 		dst_host->tls_connect = src_host->tls_connect;
6361 		dst_host->tls_accept = src_host->tls_accept;
6362 	#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
6363 		strscpy(dst_host->tls_issuer, src_host->tls_issuer);
6364 		strscpy(dst_host->tls_subject, src_host->tls_subject);
6365 
6366 		if (NULL == src_host->tls_dc_psk)
6367 		{
6368 			*dst_host->tls_psk_identity = '\0';
6369 			*dst_host->tls_psk = '\0';
6370 		}
6371 		else
6372 		{
6373 			strscpy(dst_host->tls_psk_identity, src_host->tls_dc_psk->tls_psk_identity);
6374 			strscpy(dst_host->tls_psk, src_host->tls_dc_psk->tls_psk);
6375 		}
6376 	#endif
6377 		if (NULL != (ipmihost = (ZBX_DC_IPMIHOST *)zbx_hashset_search(&config->ipmihosts, &src_host->hostid)))
6378 		{
6379 			dst_host->ipmi_authtype = ipmihost->ipmi_authtype;
6380 			dst_host->ipmi_privilege = ipmihost->ipmi_privilege;
6381 			strscpy(dst_host->ipmi_username, ipmihost->ipmi_username);
6382 			strscpy(dst_host->ipmi_password, ipmihost->ipmi_password);
6383 		}
6384 		else
6385 		{
6386 			dst_host->ipmi_authtype = ZBX_IPMI_DEFAULT_AUTHTYPE;
6387 			dst_host->ipmi_privilege = ZBX_IPMI_DEFAULT_PRIVILEGE;
6388 			*dst_host->ipmi_username = '\0';
6389 			*dst_host->ipmi_password = '\0';
6390 		}
6391 	}
6392 
6393 	if (ZBX_ITEM_GET_INVENTORY & mode)
6394 	{
6395 		if (NULL != (host_inventory = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories, &src_host->hostid)))
6396 			dst_host->inventory_mode = (char)host_inventory->inventory_mode;
6397 		else
6398 			dst_host->inventory_mode = HOST_INVENTORY_DISABLED;
6399 	}
6400 }
6401 
6402 /******************************************************************************
6403  *                                                                            *
6404  * Function: DCget_host_by_hostid                                             *
6405  *                                                                            *
6406  * Purpose: Locate host in configuration cache                                *
6407  *                                                                            *
6408  * Parameters: host - [OUT] pointer to DC_HOST structure                      *
6409  *             hostid - [IN] host ID from database                            *
6410  *                                                                            *
6411  * Return value: SUCCEED if record located and FAIL otherwise                 *
6412  *                                                                            *
6413  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
6414  *                                                                            *
6415  ******************************************************************************/
DCget_host_by_hostid(DC_HOST * host,zbx_uint64_t hostid)6416 int	DCget_host_by_hostid(DC_HOST *host, zbx_uint64_t hostid)
6417 {
6418 	int			ret = FAIL;
6419 	const ZBX_DC_HOST	*dc_host;
6420 
6421 	RDLOCK_CACHE;
6422 
6423 	if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
6424 	{
6425 		DCget_host(host, dc_host, ZBX_ITEM_GET_ALL);
6426 		ret = SUCCEED;
6427 	}
6428 
6429 	UNLOCK_CACHE;
6430 
6431 	return ret;
6432 }
6433 
6434 /******************************************************************************
6435  *                                                                            *
6436  * Function: DCcheck_proxy_permissions                                        *
6437  *                                                                            *
6438  * Purpose:                                                                   *
6439  *     Check access rights for an active proxy and get the proxy ID           *
6440  *                                                                            *
6441  * Parameters:                                                                *
6442  *     host   - [IN] proxy name                                               *
6443  *     sock   - [IN] connection socket context                                *
6444  *     hostid - [OUT] proxy ID found in configuration cache                   *
6445  *     error  - [OUT] error message why access was denied                     *
6446  *                                                                            *
6447  * Return value:                                                              *
6448  *     SUCCEED - access is allowed, FAIL - access denied                      *
6449  *                                                                            *
6450  * Comments:                                                                  *
6451  *     Generating of error messages is done outside of configuration cache    *
6452  *     locking.                                                               *
6453  *                                                                            *
6454  ******************************************************************************/
DCcheck_proxy_permissions(const char * host,const zbx_socket_t * sock,zbx_uint64_t * hostid,char ** error)6455 int	DCcheck_proxy_permissions(const char *host, const zbx_socket_t *sock, zbx_uint64_t *hostid, char **error)
6456 {
6457 	const ZBX_DC_HOST	*dc_host;
6458 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
6459 	zbx_tls_conn_attr_t	attr;
6460 
6461 	if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type)
6462 	{
6463 		if (SUCCEED != zbx_tls_get_attr_cert(sock, &attr))
6464 		{
6465 			*error = zbx_strdup(*error, "internal error: cannot get connection attributes");
6466 			THIS_SHOULD_NEVER_HAPPEN;
6467 			return FAIL;
6468 		}
6469 	}
6470 #if defined(HAVE_GNUTLS) || (defined(HAVE_OPENSSL) && defined(HAVE_OPENSSL_WITH_PSK))
6471 	else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type)
6472 	{
6473 		if (SUCCEED != zbx_tls_get_attr_psk(sock, &attr))
6474 		{
6475 			*error = zbx_strdup(*error, "internal error: cannot get connection attributes");
6476 			THIS_SHOULD_NEVER_HAPPEN;
6477 			return FAIL;
6478 		}
6479 	}
6480 #endif
6481 	else if (ZBX_TCP_SEC_UNENCRYPTED != sock->connection_type)
6482 	{
6483 		*error = zbx_strdup(*error, "internal error: invalid connection type");
6484 		THIS_SHOULD_NEVER_HAPPEN;
6485 		return FAIL;
6486 	}
6487 #endif
6488 	RDLOCK_CACHE;
6489 
6490 	if (NULL == (dc_host = DCfind_proxy(host)))
6491 	{
6492 		UNLOCK_CACHE;
6493 		*error = zbx_dsprintf(*error, "proxy \"%s\" not found", host);
6494 		return FAIL;
6495 	}
6496 
6497 	if (HOST_STATUS_PROXY_ACTIVE != dc_host->status)
6498 	{
6499 		UNLOCK_CACHE;
6500 		*error = zbx_dsprintf(*error, "proxy \"%s\" is configured in passive mode", host);
6501 		return FAIL;
6502 	}
6503 
6504 	if (0 == ((unsigned int)dc_host->tls_accept & sock->connection_type))
6505 	{
6506 		UNLOCK_CACHE;
6507 		*error = zbx_dsprintf(NULL, "connection of type \"%s\" is not allowed for proxy \"%s\"",
6508 				zbx_tcp_connection_type_name(sock->connection_type), host);
6509 		return FAIL;
6510 	}
6511 
6512 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
6513 	if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type)
6514 	{
6515 		/* simplified match, not compliant with RFC 4517, 4518 */
6516 		if ('\0' != *dc_host->tls_issuer && 0 != strcmp(dc_host->tls_issuer, attr.issuer))
6517 		{
6518 			UNLOCK_CACHE;
6519 			*error = zbx_dsprintf(*error, "proxy \"%s\" certificate issuer does not match", host);
6520 			return FAIL;
6521 		}
6522 
6523 		/* simplified match, not compliant with RFC 4517, 4518 */
6524 		if ('\0' != *dc_host->tls_subject && 0 != strcmp(dc_host->tls_subject, attr.subject))
6525 		{
6526 			UNLOCK_CACHE;
6527 			*error = zbx_dsprintf(*error, "proxy \"%s\" certificate subject does not match", host);
6528 			return FAIL;
6529 		}
6530 	}
6531 #if defined(HAVE_GNUTLS) || (defined(HAVE_OPENSSL) && defined(HAVE_OPENSSL_WITH_PSK))
6532 	else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type)
6533 	{
6534 		if (NULL != dc_host->tls_dc_psk)
6535 		{
6536 			if (strlen(dc_host->tls_dc_psk->tls_psk_identity) != attr.psk_identity_len ||
6537 					0 != memcmp(dc_host->tls_dc_psk->tls_psk_identity, attr.psk_identity,
6538 					attr.psk_identity_len))
6539 			{
6540 				UNLOCK_CACHE;
6541 				*error = zbx_dsprintf(*error, "proxy \"%s\" is using false PSK identity", host);
6542 				return FAIL;
6543 			}
6544 		}
6545 		else
6546 		{
6547 			UNLOCK_CACHE;
6548 			*error = zbx_dsprintf(*error, "active proxy \"%s\" is connecting with PSK but there is no PSK"
6549 					" in the database for this proxy", host);
6550 			return FAIL;
6551 		}
6552 	}
6553 #endif
6554 #endif
6555 	*hostid = dc_host->hostid;
6556 
6557 	UNLOCK_CACHE;
6558 
6559 	return SUCCEED;
6560 }
6561 
6562 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
6563 /******************************************************************************
6564  *                                                                            *
6565  * Function: DCget_psk_by_identity                                            *
6566  *                                                                            *
6567  * Purpose:                                                                   *
6568  *     Find PSK with the specified identity in configuration cache            *
6569  *                                                                            *
6570  * Parameters:                                                                *
6571  *     psk_identity - [IN] PSK identity to search for ('\0' terminated)       *
6572  *     psk_buf      - [OUT] output buffer for PSK value with size             *
6573  *                    HOST_TLS_PSK_LEN_MAX                                    *
6574  *     psk_usage    - [OUT] 0 - PSK not found, 1 - found in host PSKs,        *
6575  *                          2 - found in autoregistration PSK, 3 - found in   *
6576  *                          both                                              *
6577  * Return value:                                                              *
6578  *     PSK length in bytes if PSK found. 0 - if PSK not found.                *
6579  *                                                                            *
6580  * Comments:                                                                  *
6581  *     ATTENTION! This function's address and arguments are described and     *
6582  *     used in file src/libs/zbxcrypto/tls.c for calling this function by     *
6583  *     pointer. If you ever change this DCget_psk_by_identity() function      *
6584  *     arguments or return value do not forget to synchronize changes with    *
6585  *     the src/libs/zbxcrypto/tls.c.                                          *
6586  *                                                                            *
6587  ******************************************************************************/
DCget_psk_by_identity(const unsigned char * psk_identity,unsigned char * psk_buf,unsigned int * psk_usage)6588 size_t	DCget_psk_by_identity(const unsigned char *psk_identity, unsigned char *psk_buf, unsigned int *psk_usage)
6589 {
6590 	const ZBX_DC_PSK	*psk_i;
6591 	ZBX_DC_PSK		psk_i_local;
6592 	size_t			psk_len = 0;
6593 	unsigned char		autoreg_psk_tmp[HOST_TLS_PSK_LEN_MAX];
6594 
6595 	*psk_usage = 0;
6596 
6597 	psk_i_local.tls_psk_identity = (const char *)psk_identity;
6598 
6599 	RDLOCK_CACHE;
6600 
6601 	/* Is it among host PSKs? */
6602 	if (NULL != (psk_i = (ZBX_DC_PSK *)zbx_hashset_search(&config->psks, &psk_i_local)))
6603 	{
6604 		psk_len = zbx_strlcpy((char *)psk_buf, psk_i->tls_psk, HOST_TLS_PSK_LEN_MAX);
6605 		*psk_usage |= ZBX_PSK_FOR_HOST;
6606 	}
6607 
6608 	/* Does it match autoregistration PSK? */
6609 	if (0 != strcmp(config->autoreg_psk_identity, (const char *)psk_identity))
6610 	{
6611 		UNLOCK_CACHE;
6612 		return psk_len;
6613 	}
6614 
6615 	if (0 == *psk_usage)	/* only as autoregistration PSK */
6616 	{
6617 		psk_len = zbx_strlcpy((char *)psk_buf, config->autoreg_psk, HOST_TLS_PSK_LEN_MAX);
6618 		UNLOCK_CACHE;
6619 		*psk_usage |= ZBX_PSK_FOR_AUTOREG;
6620 
6621 		return psk_len;
6622 	}
6623 
6624 	/* the requested PSK is used as host PSK and as autoregistration PSK */
6625 	zbx_strlcpy((char *)autoreg_psk_tmp, config->autoreg_psk, sizeof(autoreg_psk_tmp));
6626 
6627 	UNLOCK_CACHE;
6628 
6629 	if (0 == strcmp((const char *)psk_buf, (const char *)autoreg_psk_tmp))
6630 	{
6631 		*psk_usage |= ZBX_PSK_FOR_AUTOREG;
6632 		return psk_len;
6633 	}
6634 
6635 	zabbix_log(LOG_LEVEL_WARNING, "host PSK and autoregistration PSK have the same identity \"%s\" but"
6636 			" different PSK values, autoregistration will not be allowed", psk_identity);
6637 	return psk_len;
6638 }
6639 #endif
6640 
6641 /******************************************************************************
6642  *                                                                            *
6643  * Function: DCget_autoregistration_psk                                       *
6644  *                                                                            *
6645  * Purpose:                                                                   *
6646  *     Copy autoregistration PSK identity and value from configuration cache  *
6647  *     into caller's buffers                                                  *
6648  *                                                                            *
6649  * Parameters:                                                                *
6650  *     psk_identity_buf     - [OUT] buffer for PSK identity                   *
6651  *     psk_identity_buf_len - [IN] buffer length for PSK identity             *
6652  *     psk_buf              - [OUT] buffer for PSK value                      *
6653  *     psk_buf_len          - [IN] buffer length for PSK value                *
6654  *                                                                            *
6655  * Comments: if autoregistration PSK is not configured then empty strings     *
6656  *           will be copied into buffers                                      *
6657  *                                                                            *
6658  ******************************************************************************/
DCget_autoregistration_psk(char * psk_identity_buf,size_t psk_identity_buf_len,unsigned char * psk_buf,size_t psk_buf_len)6659 void	DCget_autoregistration_psk(char *psk_identity_buf, size_t psk_identity_buf_len,
6660 		unsigned char *psk_buf, size_t psk_buf_len)
6661 {
6662 	RDLOCK_CACHE;
6663 
6664 	zbx_strlcpy((char *)psk_identity_buf, config->autoreg_psk_identity, psk_identity_buf_len);
6665 	zbx_strlcpy((char *)psk_buf, config->autoreg_psk, psk_buf_len);
6666 
6667 	UNLOCK_CACHE;
6668 }
6669 
DCget_interface(DC_INTERFACE * dst_interface,const ZBX_DC_INTERFACE * src_interface)6670 static void	DCget_interface(DC_INTERFACE *dst_interface, const ZBX_DC_INTERFACE *src_interface)
6671 {
6672 	if (NULL != src_interface)
6673 	{
6674 		dst_interface->interfaceid = src_interface->interfaceid;
6675 		strscpy(dst_interface->ip_orig, src_interface->ip);
6676 		strscpy(dst_interface->dns_orig, src_interface->dns);
6677 		strscpy(dst_interface->port_orig, src_interface->port);
6678 		dst_interface->useip = src_interface->useip;
6679 		dst_interface->type = src_interface->type;
6680 		dst_interface->main = src_interface->main;
6681 	}
6682 	else
6683 	{
6684 		dst_interface->interfaceid = 0;
6685 		*dst_interface->ip_orig = '\0';
6686 		*dst_interface->dns_orig = '\0';
6687 		*dst_interface->port_orig = '\0';
6688 		dst_interface->useip = 1;
6689 		dst_interface->type = INTERFACE_TYPE_UNKNOWN;
6690 		dst_interface->main = 0;
6691 	}
6692 
6693 	dst_interface->addr = (1 == dst_interface->useip ? dst_interface->ip_orig : dst_interface->dns_orig);
6694 	dst_interface->port = 0;
6695 }
6696 
DCget_item(DC_ITEM * dst_item,const ZBX_DC_ITEM * src_item,unsigned int mode)6697 static void	DCget_item(DC_ITEM *dst_item, const ZBX_DC_ITEM *src_item, unsigned int mode)
6698 {
6699 	const ZBX_DC_NUMITEM		*numitem;
6700 	const ZBX_DC_LOGITEM		*logitem;
6701 	const ZBX_DC_SNMPITEM		*snmpitem;
6702 	const ZBX_DC_SNMPINTERFACE	*snmp;
6703 	const ZBX_DC_TRAPITEM		*trapitem;
6704 	const ZBX_DC_IPMIITEM		*ipmiitem;
6705 	const ZBX_DC_DBITEM		*dbitem;
6706 	const ZBX_DC_SSHITEM		*sshitem;
6707 	const ZBX_DC_TELNETITEM		*telnetitem;
6708 	const ZBX_DC_SIMPLEITEM		*simpleitem;
6709 	const ZBX_DC_JMXITEM		*jmxitem;
6710 	const ZBX_DC_CALCITEM		*calcitem;
6711 	const ZBX_DC_INTERFACE		*dc_interface;
6712 	const ZBX_DC_HTTPITEM		*httpitem;
6713 
6714 	dst_item->type = src_item->type;
6715 	dst_item->value_type = src_item->value_type;
6716 
6717 	dst_item->state = src_item->state;
6718 	dst_item->lastlogsize = src_item->lastlogsize;
6719 	dst_item->mtime = src_item->mtime;
6720 
6721 	dst_item->history = src_item->history;
6722 
6723 	dst_item->inventory_link = src_item->inventory_link;
6724 	dst_item->valuemapid = src_item->valuemapid;
6725 	dst_item->status = src_item->status;
6726 
6727 	dst_item->history_sec = src_item->history_sec;
6728 	strscpy(dst_item->key_orig, src_item->key);
6729 
6730 	if (ZBX_ITEM_GET_MISC & mode)
6731 	{
6732 		dst_item->itemid = src_item->itemid;			/* set after lock */
6733 		dst_item->flags = src_item->flags;
6734 		dst_item->nextcheck = src_item->nextcheck;
6735 		dst_item->lastclock = src_item->lastclock;
6736 		dst_item->key = NULL;					/* set during initialization */
6737 	}
6738 
6739 	if (ZBX_ITEM_GET_DELAY & mode)
6740 		dst_item->delay = zbx_strdup(NULL, src_item->delay);	/* not used, should be initialized */
6741 
6742 	if ((ZBX_ITEM_GET_EMPTY_ERROR & mode) || '\0' != *src_item->error)		/* allocate after lock */
6743 		dst_item->error = zbx_strdup(NULL, src_item->error);
6744 
6745 	switch (src_item->value_type)
6746 	{
6747 		case ITEM_VALUE_TYPE_FLOAT:
6748 		case ITEM_VALUE_TYPE_UINT64:
6749 			if (0 != (ZBX_ITEM_GET_NUM & mode))
6750 			{
6751 				numitem = (ZBX_DC_NUMITEM *)zbx_hashset_search(&config->numitems, &src_item->itemid);
6752 
6753 				dst_item->trends = numitem->trends;
6754 				dst_item->trends_sec = numitem->trends_sec;
6755 
6756 				/* allocate after lock */
6757 				if (0 != (ZBX_ITEM_GET_EMPTY_UNITS & mode) || '\0' != *numitem->units)
6758 					dst_item->units = zbx_strdup(NULL, numitem->units);
6759 			}
6760 			break;
6761 		case ITEM_VALUE_TYPE_LOG:
6762 			if (ZBX_ITEM_GET_LOGTIMEFMT & mode)
6763 			{
6764 				if (NULL != (logitem = (ZBX_DC_LOGITEM *)zbx_hashset_search(&config->logitems,
6765 						&src_item->itemid)))
6766 				{
6767 					strscpy(dst_item->logtimefmt, logitem->logtimefmt);
6768 				}
6769 				else
6770 					*dst_item->logtimefmt = '\0';
6771 			}
6772 			break;
6773 	}
6774 
6775 	if (ZBX_ITEM_GET_INTERFACE & mode)	/* not used by history syncer */
6776 	{
6777 		dc_interface = (ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &src_item->interfaceid);
6778 
6779 		DCget_interface(&dst_item->interface, dc_interface);
6780 	}
6781 
6782 	if (0 == (ZBX_ITEM_GET_POLLINFO & mode))	/* not used by history syncer */
6783 		return;
6784 
6785 	switch (src_item->type)
6786 	{
6787 		case ITEM_TYPE_SNMP:
6788 			snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &src_item->itemid);
6789 			snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &src_item->interfaceid);
6790 
6791 			if (NULL != snmpitem && NULL != snmp)
6792 			{
6793 				strscpy(dst_item->snmp_community_orig, snmp->community);
6794 				strscpy(dst_item->snmp_oid_orig, snmpitem->snmp_oid);
6795 				strscpy(dst_item->snmpv3_securityname_orig, snmp->securityname);
6796 				dst_item->snmpv3_securitylevel = snmp->securitylevel;
6797 				strscpy(dst_item->snmpv3_authpassphrase_orig, snmp->authpassphrase);
6798 				strscpy(dst_item->snmpv3_privpassphrase_orig, snmp->privpassphrase);
6799 				dst_item->snmpv3_authprotocol = snmp->authprotocol;
6800 				dst_item->snmpv3_privprotocol = snmp->privprotocol;
6801 				strscpy(dst_item->snmpv3_contextname_orig, snmp->contextname);
6802 				dst_item->snmp_version = snmp->version;
6803 			}
6804 			else
6805 			{
6806 				*dst_item->snmp_community_orig = '\0';
6807 				*dst_item->snmp_oid_orig = '\0';
6808 				*dst_item->snmpv3_securityname_orig = '\0';
6809 				dst_item->snmpv3_securitylevel = ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV;
6810 				*dst_item->snmpv3_authpassphrase_orig = '\0';
6811 				*dst_item->snmpv3_privpassphrase_orig = '\0';
6812 				dst_item->snmpv3_authprotocol = 0;
6813 				dst_item->snmpv3_privprotocol = 0;
6814 				*dst_item->snmpv3_contextname_orig = '\0';
6815 				dst_item->snmp_version = ZBX_IF_SNMP_VERSION_2;
6816 			}
6817 
6818 			dst_item->snmp_community = NULL;
6819 			dst_item->snmp_oid = NULL;
6820 			dst_item->snmpv3_securityname = NULL;
6821 			dst_item->snmpv3_authpassphrase = NULL;
6822 			dst_item->snmpv3_privpassphrase = NULL;
6823 			dst_item->snmpv3_contextname = NULL;
6824 			break;
6825 		case ITEM_TYPE_TRAPPER:
6826 			if (NULL != (trapitem = (ZBX_DC_TRAPITEM *)zbx_hashset_search(&config->trapitems, &src_item->itemid)))
6827 				strscpy(dst_item->trapper_hosts, trapitem->trapper_hosts);
6828 			else
6829 				*dst_item->trapper_hosts = '\0';
6830 			break;
6831 		case ITEM_TYPE_IPMI:
6832 			if (NULL != (ipmiitem = (ZBX_DC_IPMIITEM *)zbx_hashset_search(&config->ipmiitems, &src_item->itemid)))
6833 				strscpy(dst_item->ipmi_sensor, ipmiitem->ipmi_sensor);
6834 			else
6835 				*dst_item->ipmi_sensor = '\0';
6836 			break;
6837 		case ITEM_TYPE_DB_MONITOR:
6838 			if (NULL != (dbitem = (ZBX_DC_DBITEM *)zbx_hashset_search(&config->dbitems, &src_item->itemid)))
6839 			{
6840 				dst_item->params = zbx_strdup(NULL, dbitem->params);
6841 				strscpy(dst_item->username_orig, dbitem->username);
6842 				strscpy(dst_item->password_orig, dbitem->password);
6843 			}
6844 			else
6845 			{
6846 				dst_item->params = zbx_strdup(NULL, "");
6847 				*dst_item->username_orig = '\0';
6848 				*dst_item->password_orig = '\0';
6849 			}
6850 			dst_item->username = NULL;
6851 			dst_item->password = NULL;
6852 
6853 			break;
6854 		case ITEM_TYPE_SSH:
6855 			if (NULL != (sshitem = (ZBX_DC_SSHITEM *)zbx_hashset_search(&config->sshitems, &src_item->itemid)))
6856 			{
6857 				dst_item->authtype = sshitem->authtype;
6858 				strscpy(dst_item->username_orig, sshitem->username);
6859 				strscpy(dst_item->publickey_orig, sshitem->publickey);
6860 				strscpy(dst_item->privatekey_orig, sshitem->privatekey);
6861 				strscpy(dst_item->password_orig, sshitem->password);
6862 				dst_item->params = zbx_strdup(NULL, sshitem->params);
6863 			}
6864 			else
6865 			{
6866 				dst_item->authtype = 0;
6867 				*dst_item->username_orig = '\0';
6868 				*dst_item->publickey_orig = '\0';
6869 				*dst_item->privatekey_orig = '\0';
6870 				*dst_item->password_orig = '\0';
6871 				dst_item->params = zbx_strdup(NULL, "");
6872 			}
6873 			dst_item->username = NULL;
6874 			dst_item->publickey = NULL;
6875 			dst_item->privatekey = NULL;
6876 			dst_item->password = NULL;
6877 			break;
6878 		case ITEM_TYPE_HTTPAGENT:
6879 			if (NULL != (httpitem = (ZBX_DC_HTTPITEM *)zbx_hashset_search(&config->httpitems, &src_item->itemid)))
6880 			{
6881 				strscpy(dst_item->timeout_orig, httpitem->timeout);
6882 				strscpy(dst_item->url_orig, httpitem->url);
6883 				strscpy(dst_item->query_fields_orig, httpitem->query_fields);
6884 				strscpy(dst_item->status_codes_orig, httpitem->status_codes);
6885 				dst_item->follow_redirects = httpitem->follow_redirects;
6886 				dst_item->post_type = httpitem->post_type;
6887 				strscpy(dst_item->http_proxy_orig, httpitem->http_proxy);
6888 				dst_item->headers = zbx_strdup(NULL, httpitem->headers);
6889 				dst_item->retrieve_mode = httpitem->retrieve_mode;
6890 				dst_item->request_method = httpitem->request_method;
6891 				dst_item->output_format = httpitem->output_format;
6892 				strscpy(dst_item->ssl_cert_file_orig, httpitem->ssl_cert_file);
6893 				strscpy(dst_item->ssl_key_file_orig, httpitem->ssl_key_file);
6894 				strscpy(dst_item->ssl_key_password_orig, httpitem->ssl_key_password);
6895 				dst_item->verify_peer = httpitem->verify_peer;
6896 				dst_item->verify_host = httpitem->verify_host;
6897 				dst_item->authtype = httpitem->authtype;
6898 				strscpy(dst_item->username_orig, httpitem->username);
6899 				strscpy(dst_item->password_orig, httpitem->password);
6900 				dst_item->posts = zbx_strdup(NULL, httpitem->posts);
6901 				dst_item->allow_traps = httpitem->allow_traps;
6902 				strscpy(dst_item->trapper_hosts, httpitem->trapper_hosts);
6903 			}
6904 			else
6905 			{
6906 				*dst_item->timeout_orig = '\0';
6907 				*dst_item->url_orig = '\0';
6908 				*dst_item->query_fields_orig = '\0';
6909 				*dst_item->status_codes_orig = '\0';
6910 				dst_item->follow_redirects = 0;
6911 				dst_item->post_type = 0;
6912 				*dst_item->http_proxy_orig = '\0';
6913 				dst_item->headers = zbx_strdup(NULL, "");
6914 				dst_item->retrieve_mode = 0;
6915 				dst_item->request_method = 0;
6916 				dst_item->output_format = 0;
6917 				*dst_item->ssl_cert_file_orig = '\0';
6918 				*dst_item->ssl_key_file_orig = '\0';
6919 				*dst_item->ssl_key_password_orig = '\0';
6920 				dst_item->verify_peer = 0;
6921 				dst_item->verify_host = 0;
6922 				dst_item->authtype = 0;
6923 				*dst_item->username_orig = '\0';
6924 				*dst_item->password_orig = '\0';
6925 				dst_item->posts = zbx_strdup(NULL, "");
6926 				dst_item->allow_traps = 0;
6927 				*dst_item->trapper_hosts = '\0';
6928 			}
6929 			dst_item->timeout = NULL;
6930 			dst_item->url = NULL;
6931 			dst_item->query_fields = NULL;
6932 			dst_item->status_codes = NULL;
6933 			dst_item->http_proxy = NULL;
6934 			dst_item->ssl_cert_file = NULL;
6935 			dst_item->ssl_key_file = NULL;
6936 			dst_item->ssl_key_password = NULL;
6937 			dst_item->username = NULL;
6938 			dst_item->password = NULL;
6939 			break;
6940 		case ITEM_TYPE_TELNET:
6941 			if (NULL != (telnetitem = (ZBX_DC_TELNETITEM *)zbx_hashset_search(&config->telnetitems, &src_item->itemid)))
6942 			{
6943 				strscpy(dst_item->username_orig, telnetitem->username);
6944 				strscpy(dst_item->password_orig, telnetitem->password);
6945 				dst_item->params = zbx_strdup(NULL, telnetitem->params);
6946 			}
6947 			else
6948 			{
6949 				*dst_item->username_orig = '\0';
6950 				*dst_item->password_orig = '\0';
6951 				dst_item->params = zbx_strdup(NULL, "");
6952 			}
6953 			dst_item->username = NULL;
6954 			dst_item->password = NULL;
6955 			break;
6956 		case ITEM_TYPE_SIMPLE:
6957 			if (NULL != (simpleitem = (ZBX_DC_SIMPLEITEM *)zbx_hashset_search(&config->simpleitems, &src_item->itemid)))
6958 			{
6959 				strscpy(dst_item->username_orig, simpleitem->username);
6960 				strscpy(dst_item->password_orig, simpleitem->password);
6961 			}
6962 			else
6963 			{
6964 				*dst_item->username_orig = '\0';
6965 				*dst_item->password_orig = '\0';
6966 			}
6967 			dst_item->username = NULL;
6968 			dst_item->password = NULL;
6969 			break;
6970 		case ITEM_TYPE_JMX:
6971 			if (NULL != (jmxitem = (ZBX_DC_JMXITEM *)zbx_hashset_search(&config->jmxitems, &src_item->itemid)))
6972 			{
6973 				strscpy(dst_item->username_orig, jmxitem->username);
6974 				strscpy(dst_item->password_orig, jmxitem->password);
6975 				strscpy(dst_item->jmx_endpoint_orig, jmxitem->jmx_endpoint);
6976 			}
6977 			else
6978 			{
6979 				*dst_item->username_orig = '\0';
6980 				*dst_item->password_orig = '\0';
6981 				*dst_item->jmx_endpoint_orig = '\0';
6982 			}
6983 			dst_item->username = NULL;
6984 			dst_item->password = NULL;
6985 			dst_item->jmx_endpoint = NULL;
6986 			break;
6987 		case ITEM_TYPE_CALCULATED:
6988 			calcitem = (ZBX_DC_CALCITEM *)zbx_hashset_search(&config->calcitems, &src_item->itemid);
6989 			dst_item->params = zbx_strdup(NULL, NULL != calcitem ? calcitem->params : "");
6990 			break;
6991 		default:
6992 			/* nothing to do */;
6993 	}
6994 }
6995 
DCconfig_clean_items(DC_ITEM * items,int * errcodes,size_t num)6996 void	DCconfig_clean_items(DC_ITEM *items, int *errcodes, size_t num)
6997 {
6998 	size_t	i;
6999 
7000 	for (i = 0; i < num; i++)
7001 	{
7002 		if (NULL != errcodes && SUCCEED != errcodes[i])
7003 			continue;
7004 
7005 		if (ITEM_VALUE_TYPE_FLOAT == items[i].value_type || ITEM_VALUE_TYPE_UINT64 == items[i].value_type)
7006 		{
7007 			zbx_free(items[i].units);
7008 		}
7009 
7010 		switch (items[i].type)
7011 		{
7012 			case ITEM_TYPE_HTTPAGENT:
7013 				zbx_free(items[i].headers);
7014 				zbx_free(items[i].posts);
7015 				break;
7016 			case ITEM_TYPE_DB_MONITOR:
7017 			case ITEM_TYPE_SSH:
7018 			case ITEM_TYPE_TELNET:
7019 			case ITEM_TYPE_CALCULATED:
7020 				zbx_free(items[i].params);
7021 				break;
7022 		}
7023 
7024 		zbx_free(items[i].delay);
7025 		zbx_free(items[i].error);
7026 	}
7027 }
7028 
DCget_function(DC_FUNCTION * dst_function,const ZBX_DC_FUNCTION * src_function)7029 static void	DCget_function(DC_FUNCTION *dst_function, const ZBX_DC_FUNCTION *src_function)
7030 {
7031 	size_t	sz_function, sz_parameter;
7032 
7033 	dst_function->functionid = src_function->functionid;
7034 	dst_function->triggerid = src_function->triggerid;
7035 	dst_function->itemid = src_function->itemid;
7036 
7037 	sz_function = strlen(src_function->function) + 1;
7038 	sz_parameter = strlen(src_function->parameter) + 1;
7039 	dst_function->function = (char *)zbx_malloc(NULL, sz_function + sz_parameter);
7040 	dst_function->parameter = dst_function->function + sz_function;
7041 	memcpy(dst_function->function, src_function->function, sz_function);
7042 	memcpy(dst_function->parameter, src_function->parameter, sz_parameter);
7043 }
7044 
DCget_trigger(DC_TRIGGER * dst_trigger,const ZBX_DC_TRIGGER * src_trigger)7045 static void	DCget_trigger(DC_TRIGGER *dst_trigger, const ZBX_DC_TRIGGER *src_trigger)
7046 {
7047 	int	i;
7048 
7049 	dst_trigger->triggerid = src_trigger->triggerid;
7050 	dst_trigger->description = zbx_strdup(NULL, src_trigger->description);
7051 	dst_trigger->expression_orig = zbx_strdup(NULL, src_trigger->expression);
7052 	dst_trigger->recovery_expression_orig = zbx_strdup(NULL, src_trigger->recovery_expression);
7053 	dst_trigger->error = zbx_strdup(NULL, src_trigger->error);
7054 	dst_trigger->timespec.sec = 0;
7055 	dst_trigger->timespec.ns = 0;
7056 	dst_trigger->priority = src_trigger->priority;
7057 	dst_trigger->type = src_trigger->type;
7058 	dst_trigger->value = src_trigger->value;
7059 	dst_trigger->state = src_trigger->state;
7060 	dst_trigger->new_value = TRIGGER_VALUE_UNKNOWN;
7061 	dst_trigger->lastchange = src_trigger->lastchange;
7062 	dst_trigger->topoindex = src_trigger->topoindex;
7063 	dst_trigger->status = src_trigger->status;
7064 	dst_trigger->recovery_mode = src_trigger->recovery_mode;
7065 	dst_trigger->correlation_mode = src_trigger->correlation_mode;
7066 	dst_trigger->correlation_tag = zbx_strdup(NULL, src_trigger->correlation_tag);
7067 	dst_trigger->opdata = zbx_strdup(NULL, src_trigger->opdata);
7068 	dst_trigger->flags = 0;
7069 
7070 	dst_trigger->expression = NULL;
7071 	dst_trigger->recovery_expression = NULL;
7072 	dst_trigger->new_error = NULL;
7073 
7074 	dst_trigger->expression = zbx_strdup(NULL, src_trigger->expression);
7075 	dst_trigger->recovery_expression = zbx_strdup(NULL, src_trigger->recovery_expression);
7076 
7077 	zbx_vector_ptr_create(&dst_trigger->tags);
7078 
7079 	if (0 != src_trigger->tags.values_num)
7080 	{
7081 		zbx_vector_ptr_reserve(&dst_trigger->tags, src_trigger->tags.values_num);
7082 
7083 		for (i = 0; i < src_trigger->tags.values_num; i++)
7084 		{
7085 			const zbx_dc_trigger_tag_t	*dc_trigger_tag = (const zbx_dc_trigger_tag_t *)src_trigger->tags.values[i];
7086 			zbx_tag_t			*tag;
7087 
7088 			tag = (zbx_tag_t *)zbx_malloc(NULL, sizeof(zbx_tag_t));
7089 			tag->tag = zbx_strdup(NULL, dc_trigger_tag->tag);
7090 			tag->value = zbx_strdup(NULL, dc_trigger_tag->value);
7091 
7092 			zbx_vector_ptr_append(&dst_trigger->tags, tag);
7093 		}
7094 	}
7095 }
7096 
zbx_free_tag(zbx_tag_t * tag)7097 void	zbx_free_tag(zbx_tag_t *tag)
7098 {
7099 	zbx_free(tag->tag);
7100 	zbx_free(tag->value);
7101 	zbx_free(tag);
7102 }
7103 
zbx_free_item_tag(zbx_item_tag_t * item_tag)7104 void	zbx_free_item_tag(zbx_item_tag_t *item_tag)
7105 {
7106 	zbx_free(item_tag->tag.tag);
7107 	zbx_free(item_tag->tag.value);
7108 	zbx_free(item_tag);
7109 }
7110 
DCclean_trigger(DC_TRIGGER * trigger)7111 static void	DCclean_trigger(DC_TRIGGER *trigger)
7112 {
7113 	zbx_free(trigger->new_error);
7114 	zbx_free(trigger->error);
7115 	zbx_free(trigger->expression_orig);
7116 	zbx_free(trigger->recovery_expression_orig);
7117 	zbx_free(trigger->expression);
7118 	zbx_free(trigger->recovery_expression);
7119 	zbx_free(trigger->description);
7120 	zbx_free(trigger->correlation_tag);
7121 	zbx_free(trigger->opdata);
7122 
7123 	zbx_vector_ptr_clear_ext(&trigger->tags, (zbx_clean_func_t)zbx_free_tag);
7124 	zbx_vector_ptr_destroy(&trigger->tags);
7125 }
7126 
7127 /******************************************************************************
7128  *                                                                            *
7129  * Function: DCconfig_get_items_by_keys                                       *
7130  *                                                                            *
7131  * Purpose: locate item in configuration cache by host and key                *
7132  *                                                                            *
7133  * Parameters: items    - [OUT] pointer to array of DC_ITEM structures        *
7134  *             keys     - [IN] list of item keys with host names              *
7135  *             errcodes - [OUT] SUCCEED if record located and FAIL otherwise  *
7136  *             num      - [IN] number of elements in items, keys, errcodes    *
7137  *                                                                            *
7138  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
7139  *                                                                            *
7140  ******************************************************************************/
DCconfig_get_items_by_keys(DC_ITEM * items,zbx_host_key_t * keys,int * errcodes,size_t num)7141 void	DCconfig_get_items_by_keys(DC_ITEM *items, zbx_host_key_t *keys, int *errcodes, size_t num)
7142 {
7143 	size_t			i;
7144 	const ZBX_DC_ITEM	*dc_item;
7145 	const ZBX_DC_HOST	*dc_host;
7146 
7147 	RDLOCK_CACHE;
7148 
7149 	for (i = 0; i < num; i++)
7150 	{
7151 		if (NULL == (dc_host = DCfind_host(keys[i].host)) ||
7152 				NULL == (dc_item = DCfind_item(dc_host->hostid, keys[i].key)))
7153 		{
7154 			errcodes[i] = FAIL;
7155 			continue;
7156 		}
7157 
7158 		DCget_host(&items[i].host, dc_host, ZBX_ITEM_GET_ALL);
7159 		DCget_item(&items[i], dc_item, ZBX_ITEM_GET_ALL);
7160 		errcodes[i] = SUCCEED;
7161 	}
7162 
7163 	UNLOCK_CACHE;
7164 }
7165 
DCconfig_get_hostid_by_name(const char * host,zbx_uint64_t * hostid)7166 int	DCconfig_get_hostid_by_name(const char *host, zbx_uint64_t *hostid)
7167 {
7168 	const ZBX_DC_HOST	*dc_host;
7169 	int			ret;
7170 
7171 	RDLOCK_CACHE;
7172 
7173 	if (NULL != (dc_host = DCfind_host(host)))
7174 	{
7175 		*hostid = dc_host->hostid;
7176 		ret = SUCCEED;
7177 	}
7178 	else
7179 		ret = FAIL;
7180 
7181 	UNLOCK_CACHE;
7182 
7183 	return ret;
7184 }
7185 
7186 /******************************************************************************
7187  *                                                                            *
7188  * Function: DCconfig_get_items_by_itemids                                    *
7189  *                                                                            *
7190  * Purpose: Get item with specified ID                                        *
7191  *                                                                            *
7192  * Parameters: items    - [OUT] pointer to DC_ITEM structures                 *
7193  *             itemids  - [IN] array of item IDs                              *
7194  *             errcodes - [OUT] SUCCEED if item found, otherwise FAIL         *
7195  *             num      - [IN] number of elements                             *
7196  *                                                                            *
7197  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
7198  *                                                                            *
7199  ******************************************************************************/
DCconfig_get_items_by_itemids(DC_ITEM * items,const zbx_uint64_t * itemids,int * errcodes,size_t num)7200 void	DCconfig_get_items_by_itemids(DC_ITEM *items, const zbx_uint64_t *itemids, int *errcodes, size_t num)
7201 {
7202 	size_t			i;
7203 	const ZBX_DC_ITEM	*dc_item;
7204 	const ZBX_DC_HOST	*dc_host;
7205 
7206 	RDLOCK_CACHE;
7207 
7208 	for (i = 0; i < num; i++)
7209 	{
7210 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])) ||
7211 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
7212 		{
7213 			errcodes[i] = FAIL;
7214 			continue;
7215 		}
7216 
7217 		DCget_host(&items[i].host, dc_host, ZBX_ITEM_GET_ALL);
7218 		DCget_item(&items[i], dc_item, ZBX_ITEM_GET_ALL);
7219 		errcodes[i] = SUCCEED;
7220 	}
7221 
7222 	UNLOCK_CACHE;
7223 }
7224 
DCconfig_get_items_by_itemids_partial(DC_ITEM * items,const zbx_uint64_t * itemids,int * errcodes,size_t num,unsigned int mode)7225 void	DCconfig_get_items_by_itemids_partial(DC_ITEM *items, const zbx_uint64_t *itemids, int *errcodes, size_t num,
7226 		unsigned int mode)
7227 {
7228 	size_t			i;
7229 	const ZBX_DC_ITEM	*dc_item;
7230 	const ZBX_DC_HOST	*dc_host = NULL;
7231 
7232 	memset(items, 0, sizeof(DC_ITEM) * (size_t)num);
7233 	memset(errcodes, 0, sizeof(int) * (size_t)num);
7234 
7235 	RDLOCK_CACHE;
7236 
7237 	for (i = 0; i < num; i++)
7238 	{
7239 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])))
7240 		{
7241 			errcodes[i] = FAIL;
7242 			continue;
7243 		}
7244 
7245 		if (NULL == dc_host || dc_host->hostid != dc_item->hostid)
7246 		{
7247 			if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
7248 			{
7249 				errcodes[i] = FAIL;
7250 				continue;
7251 			}
7252 		}
7253 
7254 		DCget_host(&items[i].host, dc_host, mode);
7255 		DCget_item(&items[i], dc_item, mode);
7256 	}
7257 
7258 	UNLOCK_CACHE;
7259 
7260 	/* avoid unnecessary allocations inside lock if there are no error or units */
7261 	for (i = 0; i < num; i++)
7262 	{
7263 		if (FAIL == errcodes[i])
7264 			continue;
7265 
7266 		items[i].itemid = itemids[i];
7267 
7268 		if (NULL == items[i].error)
7269 			items[i].error = zbx_strdup(NULL, "");
7270 
7271 		if (ITEM_VALUE_TYPE_FLOAT == items[i].value_type || ITEM_VALUE_TYPE_UINT64 == items[i].value_type)
7272 		{
7273 			if (NULL == items[i].units)
7274 				items[i].units = zbx_strdup(NULL, "");
7275 		}
7276 	}
7277 }
7278 
7279 /******************************************************************************
7280  *                                                                            *
7281  * Function: dc_preproc_item_init                                             *
7282  *                                                                            *
7283  * Purpose: initialize new preprocessor item from configuration cache         *
7284  *                                                                            *
7285  * Parameters: item   - [OUT] the item to initialize                          *
7286  *             itemid - [IN] the item identifier                              *
7287  *                                                                            *
7288  * Return value: SUCCEED - the item was initialized successfully              *
7289  *               FAIL    - item with the specified itemid is not cached or    *
7290  *                         monitored                                          *
7291  *                                                                            *
7292  ******************************************************************************/
dc_preproc_item_init(zbx_preproc_item_t * item,zbx_uint64_t itemid)7293 static int	dc_preproc_item_init(zbx_preproc_item_t *item, zbx_uint64_t itemid)
7294 {
7295 	const ZBX_DC_ITEM	*dc_item;
7296 	const ZBX_DC_HOST	*dc_host;
7297 
7298 	if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
7299 		return FAIL;
7300 
7301 	if (ITEM_STATUS_ACTIVE != dc_item->status)
7302 		return FAIL;
7303 
7304 	if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
7305 		return FAIL;
7306 
7307 	if (HOST_STATUS_MONITORED != dc_host->status)
7308 		return FAIL;
7309 
7310 	item->itemid = itemid;
7311 	item->type = dc_item->type;
7312 	item->value_type = dc_item->value_type;
7313 
7314 	item->dep_itemids = NULL;
7315 	item->dep_itemids_num = 0;
7316 
7317 	item->preproc_ops = NULL;
7318 	item->preproc_ops_num = 0;
7319 	item->update_time = 0;
7320 
7321 	return SUCCEED;
7322 }
7323 
7324 /******************************************************************************
7325  *                                                                            *
7326  * Function: DCconfig_get_preprocessable_items                                *
7327  *                                                                            *
7328  * Purpose: get preprocessable items:                                         *
7329  *              * items with preprocessing steps                              *
7330  *              * items with dependent items                                  *
7331  *              * internal items                                              *
7332  *                                                                            *
7333  * Parameters: items       - [IN/OUT] hashset with DC_ITEMs                   *
7334  *             timestamp   - [IN/OUT] timestamp of a last update              *
7335  *                                                                            *
7336  ******************************************************************************/
DCconfig_get_preprocessable_items(zbx_hashset_t * items,int * timestamp)7337 void	DCconfig_get_preprocessable_items(zbx_hashset_t *items, int *timestamp)
7338 {
7339 	const ZBX_DC_PREPROCITEM	*dc_preprocitem;
7340 	const ZBX_DC_MASTERITEM		*dc_masteritem;
7341 	const ZBX_DC_ITEM		*dc_item;
7342 	const zbx_dc_preproc_op_t	*dc_op;
7343 	zbx_preproc_item_t		*item, item_local;
7344 	zbx_hashset_iter_t		iter;
7345 	zbx_preproc_op_t		*op;
7346 	int				i;
7347 
7348 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
7349 
7350 	/* no changes */
7351 	if (0 != *timestamp && *timestamp == config->item_sync_ts)
7352 		goto out;
7353 
7354 	zbx_hashset_clear(items);
7355 	*timestamp = config->item_sync_ts;
7356 
7357 	RDLOCK_CACHE;
7358 
7359 	zbx_hashset_iter_reset(&config->preprocitems, &iter);
7360 	while (NULL != (dc_preprocitem = (const ZBX_DC_PREPROCITEM *)zbx_hashset_iter_next(&iter)))
7361 	{
7362 		if (FAIL == dc_preproc_item_init(&item_local, dc_preprocitem->itemid))
7363 			continue;
7364 
7365 		item = (zbx_preproc_item_t *)zbx_hashset_insert(items, &item_local, sizeof(item_local));
7366 
7367 		item->preproc_ops_num = dc_preprocitem->preproc_ops.values_num;
7368 		item->preproc_ops = (zbx_preproc_op_t *)zbx_malloc(NULL, sizeof(zbx_preproc_op_t) * item->preproc_ops_num);
7369 		item->update_time = dc_preprocitem->update_time;
7370 
7371 		for (i = 0; i < dc_preprocitem->preproc_ops.values_num; i++)
7372 		{
7373 			dc_op = (const zbx_dc_preproc_op_t *)dc_preprocitem->preproc_ops.values[i];
7374 			op = &item->preproc_ops[i];
7375 			op->type = dc_op->type;
7376 			op->params = zbx_strdup(NULL, dc_op->params);
7377 			op->error_handler = dc_op->error_handler;
7378 			op->error_handler_params = zbx_strdup(NULL, dc_op->error_handler_params);
7379 		}
7380 	}
7381 
7382 	zbx_hashset_iter_reset(&config->masteritems, &iter);
7383 	while (NULL != (dc_masteritem = (const ZBX_DC_MASTERITEM *)zbx_hashset_iter_next(&iter)))
7384 	{
7385 		if (NULL == (item = (zbx_preproc_item_t *)zbx_hashset_search(items, &dc_masteritem->itemid)))
7386 		{
7387 			if (FAIL == dc_preproc_item_init(&item_local, dc_masteritem->itemid))
7388 				continue;
7389 
7390 			item = (zbx_preproc_item_t *)zbx_hashset_insert(items, &item_local, sizeof(item_local));
7391 		}
7392 
7393 		item->dep_itemids_num = 0;
7394 		item->dep_itemids = (zbx_uint64_pair_t *)zbx_malloc(NULL, sizeof(zbx_uint64_pair_t) *
7395 				dc_masteritem->dep_itemids.values_num);
7396 
7397 		for (i = 0; i < dc_masteritem->dep_itemids.values_num; i++)
7398 		{
7399 			if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items,
7400 					&dc_masteritem->dep_itemids.values[i].first)) ||
7401 					ITEM_STATUS_ACTIVE != dc_item->status)
7402 			{
7403 				continue;
7404 			}
7405 			item->dep_itemids[item->dep_itemids_num++] = dc_masteritem->dep_itemids.values[i];
7406 		}
7407 	}
7408 
7409 	zbx_hashset_iter_reset(&config->items, &iter);
7410 	while (NULL != (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_iter_next(&iter)))
7411 	{
7412 		if (ITEM_TYPE_INTERNAL != dc_item->type)
7413 			continue;
7414 
7415 		if (NULL == zbx_hashset_search(items, &dc_item->itemid))
7416 		{
7417 			if (FAIL == dc_preproc_item_init(&item_local, dc_item->itemid))
7418 				continue;
7419 
7420 			zbx_hashset_insert(items, &item_local, sizeof(item_local));
7421 		}
7422 	}
7423 
7424 	UNLOCK_CACHE;
7425 out:
7426 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() items:%d", __func__, items->num_data);
7427 }
7428 
DCconfig_get_hosts_by_itemids(DC_HOST * hosts,const zbx_uint64_t * itemids,int * errcodes,size_t num)7429 void	DCconfig_get_hosts_by_itemids(DC_HOST *hosts, const zbx_uint64_t *itemids, int *errcodes, size_t num)
7430 {
7431 	size_t			i;
7432 	const ZBX_DC_ITEM	*dc_item;
7433 	const ZBX_DC_HOST	*dc_host;
7434 
7435 	RDLOCK_CACHE;
7436 
7437 	for (i = 0; i < num; i++)
7438 	{
7439 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])) ||
7440 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
7441 		{
7442 			errcodes[i] = FAIL;
7443 			continue;
7444 		}
7445 
7446 		DCget_host(&hosts[i], dc_host, ZBX_ITEM_GET_ALL);
7447 		errcodes[i] = SUCCEED;
7448 	}
7449 
7450 	UNLOCK_CACHE;
7451 }
7452 
DCconfig_trigger_exists(zbx_uint64_t triggerid)7453 int	DCconfig_trigger_exists(zbx_uint64_t triggerid)
7454 {
7455 	int	ret = SUCCEED;
7456 
7457 	RDLOCK_CACHE;
7458 
7459 	if (NULL == zbx_hashset_search(&config->triggers, &triggerid))
7460 		ret = FAIL;
7461 
7462 	UNLOCK_CACHE;
7463 
7464 	return ret;
7465 }
7466 
DCconfig_get_triggers_by_triggerids(DC_TRIGGER * triggers,const zbx_uint64_t * triggerids,int * errcode,size_t num)7467 void	DCconfig_get_triggers_by_triggerids(DC_TRIGGER *triggers, const zbx_uint64_t *triggerids, int *errcode,
7468 		size_t num)
7469 {
7470 	size_t			i;
7471 	const ZBX_DC_TRIGGER	*dc_trigger;
7472 
7473 	RDLOCK_CACHE;
7474 
7475 	for (i = 0; i < num; i++)
7476 	{
7477 		if (NULL == (dc_trigger = (const ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerids[i])))
7478 		{
7479 			errcode[i] = FAIL;
7480 			continue;
7481 		}
7482 
7483 		DCget_trigger(&triggers[i], dc_trigger);
7484 		errcode[i] = SUCCEED;
7485 	}
7486 
7487 	UNLOCK_CACHE;
7488 }
7489 
7490 /******************************************************************************
7491  *                                                                            *
7492  * Function: DCconfig_get_functions_by_functionids                            *
7493  *                                                                            *
7494  * Purpose: Get functions by IDs                                              *
7495  *                                                                            *
7496  * Parameters: functions   - [OUT] pointer to DC_FUNCTION structures          *
7497  *             functionids - [IN] array of function IDs                       *
7498  *             errcodes    - [OUT] SUCCEED if item found, otherwise FAIL      *
7499  *             num         - [IN] number of elements                          *
7500  *                                                                            *
7501  * Author: Aleksandrs Saveljevs, Alexander Vladishev                          *
7502  *                                                                            *
7503  ******************************************************************************/
DCconfig_get_functions_by_functionids(DC_FUNCTION * functions,zbx_uint64_t * functionids,int * errcodes,size_t num)7504 void	DCconfig_get_functions_by_functionids(DC_FUNCTION *functions, zbx_uint64_t *functionids, int *errcodes,
7505 		size_t num)
7506 {
7507 	size_t			i;
7508 	const ZBX_DC_FUNCTION	*dc_function;
7509 
7510 	RDLOCK_CACHE;
7511 
7512 	for (i = 0; i < num; i++)
7513 	{
7514 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids[i])))
7515 		{
7516 			errcodes[i] = FAIL;
7517 			continue;
7518 		}
7519 
7520 		DCget_function(&functions[i], dc_function);
7521 		errcodes[i] = SUCCEED;
7522 	}
7523 
7524 	UNLOCK_CACHE;
7525 }
7526 
7527 /******************************************************************************
7528  *                                                                            *
7529  * Function: DCconfig_clean_functions                                         *
7530  *                                                                            *
7531  * Author: Alexander Vladishev                                                *
7532  *                                                                            *
7533  ******************************************************************************/
DCconfig_clean_functions(DC_FUNCTION * functions,int * errcodes,size_t num)7534 void	DCconfig_clean_functions(DC_FUNCTION *functions, int *errcodes, size_t num)
7535 {
7536 	size_t	i;
7537 
7538 	for (i = 0; i < num; i++)
7539 	{
7540 		if (SUCCEED != errcodes[i])
7541 			continue;
7542 
7543 		zbx_free(functions[i].function);
7544 	}
7545 }
7546 
DCconfig_clean_triggers(DC_TRIGGER * triggers,int * errcodes,size_t num)7547 void	DCconfig_clean_triggers(DC_TRIGGER *triggers, int *errcodes, size_t num)
7548 {
7549 	size_t	i;
7550 
7551 	for (i = 0; i < num; i++)
7552 	{
7553 		if (SUCCEED != errcodes[i])
7554 			continue;
7555 
7556 		DCclean_trigger(&triggers[i]);
7557 	}
7558 }
7559 
7560 /******************************************************************************
7561  *                                                                            *
7562  * Function: DCconfig_lock_triggers_by_history_items                          *
7563  *                                                                            *
7564  * Purpose: Lock triggers for specified items so that multiple processes do   *
7565  *          not process one trigger simultaneously. Otherwise, this leads to  *
7566  *          problems like multiple successive OK events or escalations being  *
7567  *          started and not cancelled, because they are not seen in parallel  *
7568  *          transactions.                                                     *
7569  *                                                                            *
7570  * Parameters: history_items - [IN/OUT] list of history items history syncer  *
7571  *                                    wishes to take for processing; on       *
7572  *                                    output, the item locked field is set    *
7573  *                                    to 0 if the corresponding item cannot   *
7574  *                                    be taken                                *
7575  *             triggerids  - [OUT] list of trigger IDs that this function has *
7576  *                                 locked for processing; unlock those using  *
7577  *                                 DCconfig_unlock_triggers() function        *
7578  *                                                                            *
7579  * Author: Aleksandrs Saveljevs                                               *
7580  *                                                                            *
7581  * Comments: This does not solve the problem fully (e.g., ZBX-7484). There is *
7582  *           a significant time period between the place where we lock the    *
7583  *           triggers and the place where we process them. So it could happen *
7584  *           that a configuration cache update happens after we have locked   *
7585  *           the triggers and it turns out that in the updated configuration  *
7586  *           there is a new trigger for two of the items that two different   *
7587  *           history syncers have taken for processing. In that situation,    *
7588  *           the problem we are solving here might still happen. However,     *
7589  *           locking triggers makes this problem much less likely and only in *
7590  *           case configuration changes. On a stable configuration, it should *
7591  *           work without any problems.                                       *
7592  *                                                                            *
7593  * Return value: the number of items available for processing (unlocked).     *
7594  *                                                                            *
7595  ******************************************************************************/
DCconfig_lock_triggers_by_history_items(zbx_vector_ptr_t * history_items,zbx_vector_uint64_t * triggerids)7596 int	DCconfig_lock_triggers_by_history_items(zbx_vector_ptr_t *history_items, zbx_vector_uint64_t *triggerids)
7597 {
7598 	int			i, j, locked_num = 0;
7599 	const ZBX_DC_ITEM	*dc_item;
7600 	ZBX_DC_TRIGGER		*dc_trigger;
7601 	zbx_hc_item_t		*history_item;
7602 
7603 	WRLOCK_CACHE;
7604 
7605 	for (i = 0; i < history_items->values_num; i++)
7606 	{
7607 		history_item = (zbx_hc_item_t *)history_items->values[i];
7608 
7609 		if (0 != (ZBX_DC_FLAG_NOVALUE & history_item->tail->flags))
7610 			continue;
7611 
7612 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &history_item->itemid)))
7613 			continue;
7614 
7615 		if (NULL == dc_item->triggers)
7616 			continue;
7617 
7618 		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
7619 		{
7620 			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
7621 				continue;
7622 
7623 			if (1 == dc_trigger->locked)
7624 			{
7625 				locked_num++;
7626 				history_item->status = ZBX_HC_ITEM_STATUS_BUSY;
7627 				goto next;
7628 			}
7629 		}
7630 
7631 		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
7632 		{
7633 			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
7634 				continue;
7635 
7636 			dc_trigger->locked = 1;
7637 			zbx_vector_uint64_append(triggerids, dc_trigger->triggerid);
7638 		}
7639 next:;
7640 	}
7641 
7642 	UNLOCK_CACHE;
7643 
7644 	return history_items->values_num - locked_num;
7645 }
7646 
7647 /******************************************************************************
7648  *                                                                            *
7649  * Function: DCconfig_lock_triggers_by_triggerids                             *
7650  *                                                                            *
7651  * Purpose: Lock triggers so that multiple processes do not process one       *
7652  *          trigger simultaneously.                                           *
7653  *                                                                            *
7654  * Parameters: triggerids_in  - [IN] ids of triggers to lock                  *
7655  *             triggerids_out - [OUT] ids of locked triggers                  *
7656  *                                                                            *
7657  ******************************************************************************/
DCconfig_lock_triggers_by_triggerids(zbx_vector_uint64_t * triggerids_in,zbx_vector_uint64_t * triggerids_out)7658 void	DCconfig_lock_triggers_by_triggerids(zbx_vector_uint64_t *triggerids_in, zbx_vector_uint64_t *triggerids_out)
7659 {
7660 	int		i;
7661 	ZBX_DC_TRIGGER	*dc_trigger;
7662 
7663 	if (0 == triggerids_in->values_num)
7664 		return;
7665 
7666 	WRLOCK_CACHE;
7667 
7668 	for (i = 0; i < triggerids_in->values_num; i++)
7669 	{
7670 		if (NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerids_in->values[i])))
7671 			continue;
7672 
7673 		if (1 == dc_trigger->locked)
7674 			continue;
7675 
7676 		dc_trigger->locked = 1;
7677 		zbx_vector_uint64_append(triggerids_out, dc_trigger->triggerid);
7678 	}
7679 
7680 	UNLOCK_CACHE;
7681 }
7682 
7683 /******************************************************************************
7684  *                                                                            *
7685  * Function: DCconfig_unlock_triggers                                         *
7686  *                                                                            *
7687  * Author: Aleksandrs Saveljevs                                               *
7688  *                                                                            *
7689  ******************************************************************************/
DCconfig_unlock_triggers(const zbx_vector_uint64_t * triggerids)7690 void	DCconfig_unlock_triggers(const zbx_vector_uint64_t *triggerids)
7691 {
7692 	int		i;
7693 	ZBX_DC_TRIGGER	*dc_trigger;
7694 
7695 	/* no other process can modify already locked triggers without write lock */
7696 	RDLOCK_CACHE;
7697 
7698 	for (i = 0; i < triggerids->values_num; i++)
7699 	{
7700 		if (NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &triggerids->values[i])))
7701 			continue;
7702 
7703 		dc_trigger->locked = 0;
7704 	}
7705 
7706 	UNLOCK_CACHE;
7707 }
7708 
7709 /******************************************************************************
7710  *                                                                            *
7711  * Function: DCconfig_unlock_all_triggers                                     *
7712  *                                                                            *
7713  * Purpose: Unlocks all locked triggers before doing full history sync at     *
7714  *          program exit                                                      *
7715  *                                                                            *
7716  ******************************************************************************/
DCconfig_unlock_all_triggers(void)7717 void	DCconfig_unlock_all_triggers(void)
7718 {
7719 	ZBX_DC_TRIGGER		*dc_trigger;
7720 	zbx_hashset_iter_t	iter;
7721 
7722 	WRLOCK_CACHE;
7723 
7724 	zbx_hashset_iter_reset(&config->triggers, &iter);
7725 
7726 	while (NULL != (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
7727 		dc_trigger->locked = 0;
7728 
7729 	UNLOCK_CACHE;
7730 }
7731 
7732 /******************************************************************************
7733  *                                                                            *
7734  * Function: DCconfig_get_triggers_by_itemids                                 *
7735  *                                                                            *
7736  * Purpose: get enabled triggers for specified items                          *
7737  *                                                                            *
7738  * Author: Aleksandrs Saveljevs                                               *
7739  *                                                                            *
7740  ******************************************************************************/
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)7741 void	DCconfig_get_triggers_by_itemids(zbx_hashset_t *trigger_info, zbx_vector_ptr_t *trigger_order,
7742 		const zbx_uint64_t *itemids, const zbx_timespec_t *timespecs, int itemids_num)
7743 {
7744 	int			i, j, found;
7745 	const ZBX_DC_ITEM	*dc_item;
7746 	const ZBX_DC_TRIGGER	*dc_trigger;
7747 	DC_TRIGGER		*trigger;
7748 
7749 	RDLOCK_CACHE;
7750 
7751 	for (i = 0; i < itemids_num; i++)
7752 	{
7753 		/* skip items which are not in configuration cache and items without triggers */
7754 
7755 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])) || NULL == dc_item->triggers)
7756 			continue;
7757 
7758 		/* process all triggers for the specified item */
7759 
7760 		for (j = 0; NULL != (dc_trigger = dc_item->triggers[j]); j++)
7761 		{
7762 			if (TRIGGER_STATUS_ENABLED != dc_trigger->status)
7763 				continue;
7764 
7765 			/* find trigger by id or create a new record in hashset if not found */
7766 			trigger = (DC_TRIGGER *)DCfind_id(trigger_info, dc_trigger->triggerid, sizeof(DC_TRIGGER), &found);
7767 
7768 			if (0 == found)
7769 			{
7770 				DCget_trigger(trigger, dc_trigger);
7771 				zbx_vector_ptr_append(trigger_order, trigger);
7772 			}
7773 
7774 			/* copy latest change timestamp */
7775 
7776 			if (trigger->timespec.sec < timespecs[i].sec ||
7777 					(trigger->timespec.sec == timespecs[i].sec &&
7778 					trigger->timespec.ns < timespecs[i].ns))
7779 			{
7780 				/* DCconfig_get_triggers_by_itemids() function is called during trigger processing */
7781 				/* when syncing history cache. A trigger cannot be processed by two syncers at the */
7782 				/* same time, so its safe to update trigger timespec within read lock.             */
7783 				trigger->timespec = timespecs[i];
7784 			}
7785 		}
7786 	}
7787 
7788 	UNLOCK_CACHE;
7789 }
7790 
7791 /******************************************************************************
7792  *                                                                            *
7793  * Function: DCconfig_find_active_time_function                               *
7794  *                                                                            *
7795  * Purpose: checks if the expression contains time based functions            *
7796  *                                                                            *
7797  ******************************************************************************/
DCconfig_find_active_time_function(const char * expression)7798 static int	DCconfig_find_active_time_function(const char *expression)
7799 {
7800 	zbx_uint64_t		functionid;
7801 	const ZBX_DC_FUNCTION	*dc_function;
7802 	const ZBX_DC_HOST	*dc_host;
7803 	const ZBX_DC_ITEM	*dc_item;
7804 
7805 	while (SUCCEED == get_N_functionid(expression, 1, &functionid, &expression))
7806 	{
7807 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionid)))
7808 			continue;
7809 
7810 		if (1 == dc_function->timer)
7811 		{
7812 			if (NULL == (dc_item = zbx_hashset_search(&config->items, &dc_function->itemid)))
7813 				continue;
7814 
7815 			if (NULL == (dc_host = zbx_hashset_search(&config->hosts, &dc_item->hostid)))
7816 				continue;
7817 
7818 			if (SUCCEED != DCin_maintenance_without_data_collection(dc_host, dc_item))
7819 				return SUCCEED;
7820 		}
7821 	}
7822 
7823 	return FAIL;
7824 }
7825 
7826 /******************************************************************************
7827  *                                                                            *
7828  * Function: zbx_dc_get_timer_triggers_by_triggerids                          *
7829  *                                                                            *
7830  * Purpose: gets timer triggers from cache                                    *
7831  *                                                                            *
7832  * Parameters: trigger_info  - [IN/OUT] triggers                              *
7833  *             trigger_order - [IN/OUT] triggers in processing order          *
7834  *             triggerids    - [IN] identifiers of the triggers to retrieve   *
7835  *             ts            - [IN] current timestamp                         *
7836  *                                                                            *
7837  ******************************************************************************/
zbx_dc_get_timer_triggers_by_triggerids(zbx_hashset_t * trigger_info,zbx_vector_ptr_t * trigger_order,const zbx_vector_uint64_t * triggerids,const zbx_timespec_t * ts)7838 void	zbx_dc_get_timer_triggers_by_triggerids(zbx_hashset_t *trigger_info, zbx_vector_ptr_t *trigger_order,
7839 		const zbx_vector_uint64_t *triggerids, const zbx_timespec_t *ts)
7840 {
7841 	int		i;
7842 	ZBX_DC_TRIGGER	*dc_trigger;
7843 
7844 	RDLOCK_CACHE;
7845 
7846 	for (i = 0; i < triggerids->values_num; i++)
7847 	{
7848 		if (NULL != (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers,
7849 				&triggerids->values[i])))
7850 		{
7851 			DC_TRIGGER	*trigger, trigger_local;
7852 			unsigned char	flags;
7853 
7854 			if (SUCCEED == DCconfig_find_active_time_function(dc_trigger->expression))
7855 			{
7856 				flags = ZBX_DC_TRIGGER_PROBLEM_EXPRESSION;
7857 			}
7858 			else
7859 			{
7860 				if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION != dc_trigger->recovery_mode)
7861 					continue;
7862 
7863 				if (TRIGGER_VALUE_PROBLEM != dc_trigger->value)
7864 					continue;
7865 
7866 				if (SUCCEED != DCconfig_find_active_time_function(dc_trigger->recovery_expression))
7867 					continue;
7868 
7869 				flags = 0;
7870 			}
7871 
7872 			trigger_local.triggerid = dc_trigger->triggerid;
7873 			trigger = (DC_TRIGGER *)zbx_hashset_insert(trigger_info, &trigger_local, sizeof(trigger_local));
7874 			DCget_trigger(trigger, dc_trigger);
7875 
7876 			/* DCconfig_get_triggers_by_itemids() function is called during trigger processing */
7877 			/* when syncing history cache. A trigger cannot be processed by two syncers at the */
7878 			/* same time, so its safe to update trigger timespec within read lock.             */
7879 			trigger->timespec = *ts;
7880 			trigger->flags = flags;
7881 
7882 			zbx_vector_ptr_append(trigger_order, trigger);
7883 		}
7884 	}
7885 
7886 	UNLOCK_CACHE;
7887 }
7888 
7889 /******************************************************************************
7890  *                                                                            *
7891  * Function: zbx_dc_get_timer_triggerids                                      *
7892  *                                                                            *
7893  * Purpose: gets triggerids from timer queue                                  *
7894  *                                                                            *
7895  * Parameters: triggerids - [OUT] timer tirggerids to process                 *
7896  *             now        - [IN] current time                                 *
7897  *             limit      - [IN] the maximum number of triggerids to return   *
7898  *                                                                            *
7899  * Comments: This function locks returned triggerids in configuration cache.  *
7900  *                                                                            *
7901  ******************************************************************************/
zbx_dc_get_timer_triggerids(zbx_vector_uint64_t * triggerids,int now,int limit)7902 void	zbx_dc_get_timer_triggerids(zbx_vector_uint64_t *triggerids, int now, int limit)
7903 {
7904 	zbx_binary_heap_elem_t	*elem;
7905 	ZBX_DC_TRIGGER		*dc_trigger;
7906 	int			found = 0;
7907 
7908 	RDLOCK_CACHE;
7909 
7910 	if (SUCCEED != zbx_binary_heap_empty(&config->timer_queue))
7911 	{
7912 		elem = zbx_binary_heap_find_min(&config->timer_queue);
7913 		dc_trigger = (ZBX_DC_TRIGGER *)elem->data;
7914 
7915 		if (dc_trigger->nextcheck <= now)
7916 			found = 1;
7917 	}
7918 
7919 	UNLOCK_CACHE;
7920 
7921 	if (0 == found)
7922 		return;
7923 
7924 	WRLOCK_CACHE;
7925 
7926 	while (SUCCEED != zbx_binary_heap_empty(&config->timer_queue) && 0 != limit)
7927 	{
7928 		elem = zbx_binary_heap_find_min(&config->timer_queue);
7929 		dc_trigger = (ZBX_DC_TRIGGER *)elem->data;
7930 
7931 		if (dc_trigger->nextcheck > now)
7932 			break;
7933 
7934 		/* locked triggers are already being processed by other processes, we can skip them */
7935 		if (0 == dc_trigger->locked)
7936 		{
7937 			zbx_vector_uint64_append(triggerids, dc_trigger->triggerid);
7938 			dc_trigger->locked = 1;
7939 			limit--;
7940 		}
7941 
7942 		dc_trigger->nextcheck = dc_timer_calculate_nextcheck(now, dc_trigger->triggerid);
7943 		zbx_binary_heap_update_direct(&config->timer_queue, elem);
7944 	}
7945 
7946 	UNLOCK_CACHE;
7947 }
7948 
7949 /******************************************************************************
7950  *                                                                            *
7951  * Function: zbx_dc_clear_timer_queue                                         *
7952  *                                                                            *
7953  * Purpose: clears timer trigger queue                                        *
7954  *                                                                            *
7955  ******************************************************************************/
zbx_dc_clear_timer_queue(void)7956 void	zbx_dc_clear_timer_queue(void)
7957 {
7958 	WRLOCK_CACHE;
7959 	zbx_binary_heap_clear(&config->timer_queue);
7960 	UNLOCK_CACHE;
7961 }
7962 
DCfree_triggers(zbx_vector_ptr_t * triggers)7963 void	DCfree_triggers(zbx_vector_ptr_t *triggers)
7964 {
7965 	int	i;
7966 
7967 	for (i = 0; i < triggers->values_num; i++)
7968 		DCclean_trigger((DC_TRIGGER *)triggers->values[i]);
7969 
7970 	zbx_vector_ptr_clear(triggers);
7971 }
7972 
DCconfig_update_interface_snmp_stats(zbx_uint64_t interfaceid,int max_snmp_succeed,int min_snmp_fail)7973 void	DCconfig_update_interface_snmp_stats(zbx_uint64_t interfaceid, int max_snmp_succeed, int min_snmp_fail)
7974 {
7975 	ZBX_DC_SNMPINTERFACE	*dc_snmp;
7976 
7977 	WRLOCK_CACHE;
7978 
7979 	if (NULL != (dc_snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid)) &&
7980 			SNMP_BULK_ENABLED == dc_snmp->bulk)
7981 	{
7982 		if (dc_snmp->max_succeed < max_snmp_succeed)
7983 			dc_snmp->max_succeed = (unsigned char)max_snmp_succeed;
7984 
7985 		if (dc_snmp->min_fail > min_snmp_fail)
7986 			dc_snmp->min_fail = (unsigned char)min_snmp_fail;
7987 	}
7988 
7989 	UNLOCK_CACHE;
7990 }
7991 
DCconfig_get_suggested_snmp_vars_nolock(zbx_uint64_t interfaceid,int * bulk)7992 static int	DCconfig_get_suggested_snmp_vars_nolock(zbx_uint64_t interfaceid, int *bulk)
7993 {
7994 	int				num;
7995 	const ZBX_DC_SNMPINTERFACE	*dc_snmp;
7996 
7997 	dc_snmp = (const ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp, &interfaceid);
7998 
7999 	if (NULL != bulk)
8000 		*bulk = (NULL == dc_snmp ? SNMP_BULK_DISABLED : dc_snmp->bulk);
8001 
8002 	if (NULL == dc_snmp || SNMP_BULK_ENABLED != dc_snmp->bulk)
8003 		return 1;
8004 
8005 	/* The general strategy is to multiply request size by 3/2 in order to approach the limit faster. */
8006 	/* However, once we are over the limit, we change the strategy to increasing the value by 1. This */
8007 	/* is deemed better than going backwards from the error because less timeouts are going to occur. */
8008 
8009 	if (1 >= dc_snmp->max_succeed || MAX_SNMP_ITEMS + 1 != dc_snmp->min_fail)
8010 		num = dc_snmp->max_succeed + 1;
8011 	else
8012 		num = dc_snmp->max_succeed * 3 / 2;
8013 
8014 	if (num < dc_snmp->min_fail)
8015 		return num;
8016 
8017 	/* If we have already found the optimal number of variables to query, we wish to base our suggestion on that */
8018 	/* number. If we occasionally get a timeout in this area, it can mean two things: either the device's actual */
8019 	/* limit is a bit lower than that (it can process requests above it, but only sometimes) or a UDP packet in  */
8020 	/* one of the directions was lost. In order to account for the former, we allow ourselves to lower the count */
8021 	/* of variables, but only up to two times. Otherwise, performance will gradually degrade due to the latter.  */
8022 
8023 	return MAX(dc_snmp->max_succeed - 2, dc_snmp->min_fail - 1);
8024 }
8025 
DCconfig_get_suggested_snmp_vars(zbx_uint64_t interfaceid,int * bulk)8026 int	DCconfig_get_suggested_snmp_vars(zbx_uint64_t interfaceid, int *bulk)
8027 {
8028 	int	ret;
8029 
8030 	RDLOCK_CACHE;
8031 
8032 	ret = DCconfig_get_suggested_snmp_vars_nolock(interfaceid, bulk);
8033 
8034 	UNLOCK_CACHE;
8035 
8036 	return ret;
8037 }
8038 
dc_get_interface_by_type(DC_INTERFACE * interface,zbx_uint64_t hostid,unsigned char type)8039 static int	dc_get_interface_by_type(DC_INTERFACE *interface, zbx_uint64_t hostid, unsigned char type)
8040 {
8041 	int				res = FAIL;
8042 	const ZBX_DC_INTERFACE		*dc_interface;
8043 	const ZBX_DC_INTERFACE_HT	*interface_ht;
8044 	ZBX_DC_INTERFACE_HT		interface_ht_local;
8045 
8046 	interface_ht_local.hostid = hostid;
8047 	interface_ht_local.type = type;
8048 
8049 	if (NULL != (interface_ht = (const ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local)))
8050 	{
8051 		dc_interface = interface_ht->interface_ptr;
8052 		DCget_interface(interface, dc_interface);
8053 		res = SUCCEED;
8054 	}
8055 
8056 	return res;
8057 }
8058 
8059 /******************************************************************************
8060  *                                                                            *
8061  * Function: DCconfig_get_interface_by_type                                   *
8062  *                                                                            *
8063  * Purpose: Locate main interface of specified type in configuration cache    *
8064  *                                                                            *
8065  * Parameters: interface - [OUT] pointer to DC_INTERFACE structure            *
8066  *             hostid - [IN] host ID                                          *
8067  *             type - [IN] interface type                                     *
8068  *                                                                            *
8069  * Return value: SUCCEED if record located and FAIL otherwise                 *
8070  *                                                                            *
8071  ******************************************************************************/
DCconfig_get_interface_by_type(DC_INTERFACE * interface,zbx_uint64_t hostid,unsigned char type)8072 int	DCconfig_get_interface_by_type(DC_INTERFACE *interface, zbx_uint64_t hostid, unsigned char type)
8073 {
8074 	int	res;
8075 
8076 	RDLOCK_CACHE;
8077 
8078 	res = dc_get_interface_by_type(interface, hostid, type);
8079 
8080 	UNLOCK_CACHE;
8081 
8082 	return res;
8083 }
8084 
8085 /******************************************************************************
8086  *                                                                            *
8087  * Function: DCconfig_get_interface                                           *
8088  *                                                                            *
8089  * Purpose: Locate interface in configuration cache                           *
8090  *                                                                            *
8091  * Parameters: interface - [OUT] pointer to DC_INTERFACE structure            *
8092  *             hostid - [IN] host ID                                          *
8093  *             itemid - [IN] item ID                                          *
8094  *                                                                            *
8095  * Return value: SUCCEED if record located and FAIL otherwise                 *
8096  *                                                                            *
8097  ******************************************************************************/
DCconfig_get_interface(DC_INTERFACE * interface,zbx_uint64_t hostid,zbx_uint64_t itemid)8098 int	DCconfig_get_interface(DC_INTERFACE *interface, zbx_uint64_t hostid, zbx_uint64_t itemid)
8099 {
8100 	int			res = FAIL, i;
8101 	const ZBX_DC_ITEM	*dc_item;
8102 	const ZBX_DC_INTERFACE	*dc_interface;
8103 
8104 	RDLOCK_CACHE;
8105 
8106 	if (0 != itemid)
8107 	{
8108 		if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
8109 			goto unlock;
8110 
8111 		if (0 != dc_item->interfaceid)
8112 		{
8113 			if (NULL == (dc_interface = (const ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces,
8114 					&dc_item->interfaceid)))
8115 			{
8116 				goto unlock;
8117 			}
8118 
8119 			DCget_interface(interface, dc_interface);
8120 			res = SUCCEED;
8121 			goto unlock;
8122 		}
8123 
8124 		hostid = dc_item->hostid;
8125 	}
8126 
8127 	if (0 == hostid)
8128 		goto unlock;
8129 
8130 	for (i = 0; i < (int)ARRSIZE(INTERFACE_TYPE_PRIORITY); i++)
8131 	{
8132 		if (SUCCEED == (res = dc_get_interface_by_type(interface, hostid, INTERFACE_TYPE_PRIORITY[i])))
8133 			break;
8134 	}
8135 
8136 unlock:
8137 	UNLOCK_CACHE;
8138 
8139 	return res;
8140 }
8141 
8142 /******************************************************************************
8143  *                                                                            *
8144  * Function: dc_config_get_queue_nextcheck                                    *
8145  *                                                                            *
8146  * Purpose: Get nextcheck for selected queue                                  *
8147  *                                                                            *
8148  * Parameters: queue - [IN] the queue                                         *
8149  *                                                                            *
8150  * Return value: nextcheck or FAIL if no items for the specified queue        *
8151  *                                                                            *
8152  ******************************************************************************/
dc_config_get_queue_nextcheck(zbx_binary_heap_t * queue)8153 static int	dc_config_get_queue_nextcheck(zbx_binary_heap_t *queue)
8154 {
8155 	int				nextcheck;
8156 	const zbx_binary_heap_elem_t	*min;
8157 	const ZBX_DC_ITEM		*dc_item;
8158 
8159 	if (FAIL == zbx_binary_heap_empty(queue))
8160 	{
8161 		min = zbx_binary_heap_find_min(queue);
8162 		dc_item = (const ZBX_DC_ITEM *)min->data;
8163 
8164 		nextcheck = dc_item->nextcheck;
8165 	}
8166 	else
8167 		nextcheck = FAIL;
8168 
8169 	return nextcheck;
8170 }
8171 
8172 /******************************************************************************
8173  *                                                                            *
8174  * Function: DCconfig_get_poller_nextcheck                                    *
8175  *                                                                            *
8176  * Purpose: Get nextcheck for selected poller                                 *
8177  *                                                                            *
8178  * Parameters: poller_type - [IN] poller type (ZBX_POLLER_TYPE_...)           *
8179  *                                                                            *
8180  * Return value: nextcheck or FAIL if no items for selected poller            *
8181  *                                                                            *
8182  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
8183  *                                                                            *
8184  ******************************************************************************/
DCconfig_get_poller_nextcheck(unsigned char poller_type)8185 int	DCconfig_get_poller_nextcheck(unsigned char poller_type)
8186 {
8187 	int			nextcheck;
8188 	zbx_binary_heap_t	*queue;
8189 
8190 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() poller_type:%d", __func__, (int)poller_type);
8191 
8192 	queue = &config->queues[poller_type];
8193 
8194 	RDLOCK_CACHE;
8195 
8196 	nextcheck = dc_config_get_queue_nextcheck(queue);
8197 
8198 	UNLOCK_CACHE;
8199 
8200 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, nextcheck);
8201 
8202 	return nextcheck;
8203 }
8204 
dc_requeue_item(ZBX_DC_ITEM * dc_item,const ZBX_DC_HOST * dc_host,unsigned char new_state,int flags,int lastclock)8205 static void	dc_requeue_item(ZBX_DC_ITEM *dc_item, const ZBX_DC_HOST *dc_host, unsigned char new_state, int flags,
8206 		int lastclock)
8207 {
8208 	unsigned char	old_poller_type;
8209 	int		old_nextcheck;
8210 
8211 	old_nextcheck = dc_item->nextcheck;
8212 	DCitem_nextcheck_update(dc_item, dc_host, new_state, flags, lastclock, NULL);
8213 
8214 	old_poller_type = dc_item->poller_type;
8215 	DCitem_poller_type_update(dc_item, dc_host, flags);
8216 
8217 	DCupdate_item_queue(dc_item, old_poller_type, old_nextcheck);
8218 }
8219 
8220 /******************************************************************************
8221  *                                                                            *
8222  * Function: dc_requeue_item_at                                               *
8223  *                                                                            *
8224  * Purpose: requeues items at the specified time                              *
8225  *                                                                            *
8226  * Parameters: dc_item   - [IN] the item to reque                             *
8227  *             dc_host   - [IN] item's host                                   *
8228  *             nextcheck - [IN] the scheduled time                            *
8229  *                                                                            *
8230  ******************************************************************************/
dc_requeue_item_at(ZBX_DC_ITEM * dc_item,ZBX_DC_HOST * dc_host,int nextcheck)8231 static void	dc_requeue_item_at(ZBX_DC_ITEM *dc_item, ZBX_DC_HOST *dc_host, int nextcheck)
8232 {
8233 	unsigned char	old_poller_type;
8234 	int		old_nextcheck;
8235 
8236 	dc_item->queue_priority = ZBX_QUEUE_PRIORITY_HIGH;
8237 
8238 	old_nextcheck = dc_item->nextcheck;
8239 	dc_item->nextcheck = nextcheck;
8240 
8241 	old_poller_type = dc_item->poller_type;
8242 	DCitem_poller_type_update(dc_item, dc_host, ZBX_ITEM_COLLECTED);
8243 
8244 	DCupdate_item_queue(dc_item, old_poller_type, old_nextcheck);
8245 }
8246 
8247 /******************************************************************************
8248  *                                                                            *
8249  * Function: DCconfig_get_poller_items                                        *
8250  *                                                                            *
8251  * Purpose: Get array of items for selected poller                            *
8252  *                                                                            *
8253  * Parameters: poller_type - [IN] poller type (ZBX_POLLER_TYPE_...)           *
8254  *             items       - [OUT] array of items                             *
8255  *                                                                            *
8256  * Return value: number of items in items array                               *
8257  *                                                                            *
8258  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
8259  *                                                                            *
8260  * Comments: Items leave the queue only through this function. Pollers must   *
8261  *           always return the items they have taken using DCrequeue_items()  *
8262  *           or DCpoller_requeue_items().                                     *
8263  *                                                                            *
8264  *           Currently batch polling is supported only for JMX, SNMP and      *
8265  *           icmpping* simple checks. In other cases only single item is      *
8266  *           retrieved.                                                       *
8267  *                                                                            *
8268  *           IPMI poller queue are handled by DCconfig_get_ipmi_poller_items()*
8269  *           function.                                                        *
8270  *                                                                            *
8271  ******************************************************************************/
DCconfig_get_poller_items(unsigned char poller_type,DC_ITEM ** items)8272 int	DCconfig_get_poller_items(unsigned char poller_type, DC_ITEM **items)
8273 {
8274 	int			now, num = 0, max_items;
8275 	zbx_binary_heap_t	*queue;
8276 
8277 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() poller_type:%d", __func__, (int)poller_type);
8278 
8279 	now = time(NULL);
8280 
8281 	queue = &config->queues[poller_type];
8282 
8283 	switch (poller_type)
8284 	{
8285 		case ZBX_POLLER_TYPE_JAVA:
8286 			max_items = MAX_JAVA_ITEMS;
8287 			break;
8288 		case ZBX_POLLER_TYPE_PINGER:
8289 			max_items = MAX_PINGER_ITEMS;
8290 			break;
8291 		default:
8292 			max_items = 1;
8293 	}
8294 
8295 	WRLOCK_CACHE;
8296 
8297 	while (num < max_items && FAIL == zbx_binary_heap_empty(queue))
8298 	{
8299 		int				disable_until;
8300 		const zbx_binary_heap_elem_t	*min;
8301 		ZBX_DC_HOST			*dc_host;
8302 		ZBX_DC_ITEM			*dc_item;
8303 		static const ZBX_DC_ITEM	*dc_item_prev = NULL;
8304 
8305 		min = zbx_binary_heap_find_min(queue);
8306 		dc_item = (ZBX_DC_ITEM *)min->data;
8307 
8308 		if (dc_item->nextcheck > now)
8309 			break;
8310 
8311 		if (0 != num)
8312 		{
8313 			if (ITEM_TYPE_SNMP == dc_item_prev->type)
8314 			{
8315 				if (0 != __config_snmp_item_compare(dc_item_prev, dc_item))
8316 					break;
8317 			}
8318 			else if (ITEM_TYPE_JMX == dc_item_prev->type)
8319 			{
8320 				if (0 != __config_java_item_compare(dc_item_prev, dc_item))
8321 					break;
8322 			}
8323 		}
8324 
8325 		zbx_binary_heap_remove_min(queue);
8326 		dc_item->location = ZBX_LOC_NOWHERE;
8327 
8328 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8329 			continue;
8330 
8331 		if (HOST_STATUS_MONITORED != dc_host->status)
8332 			continue;
8333 
8334 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
8335 		{
8336 			dc_requeue_item(dc_item, dc_host, dc_item->state, ZBX_ITEM_COLLECTED, now);
8337 			continue;
8338 		}
8339 
8340 		/* don't apply unreachable item/host throttling for prioritized items */
8341 		if (ZBX_QUEUE_PRIORITY_HIGH != dc_item->queue_priority)
8342 		{
8343 			if (0 == (disable_until = DCget_disable_until(dc_item, dc_host)))
8344 			{
8345 				/* move reachable items on reachable hosts to normal pollers */
8346 				if (ZBX_POLLER_TYPE_UNREACHABLE == poller_type &&
8347 						ZBX_QUEUE_PRIORITY_LOW != dc_item->queue_priority)
8348 				{
8349 					dc_requeue_item(dc_item, dc_host, dc_item->state, ZBX_ITEM_COLLECTED, now);
8350 					continue;
8351 				}
8352 			}
8353 			else
8354 			{
8355 				/* move items on unreachable hosts to unreachable pollers or    */
8356 				/* postpone checks on hosts that have been checked recently and */
8357 				/* are still unreachable                                        */
8358 				if (ZBX_POLLER_TYPE_NORMAL == poller_type || ZBX_POLLER_TYPE_JAVA == poller_type ||
8359 						disable_until > now)
8360 				{
8361 					dc_requeue_item(dc_item, dc_host, dc_item->state,
8362 							ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE, now);
8363 					continue;
8364 				}
8365 
8366 				DCincrease_disable_until(dc_item, dc_host, now);
8367 			}
8368 		}
8369 
8370 		if (0 == num)
8371 		{
8372 			if (ZBX_POLLER_TYPE_NORMAL == poller_type && ITEM_TYPE_SNMP == dc_item->type &&
8373 					0 == (ZBX_FLAG_DISCOVERY_RULE & dc_item->flags))
8374 			{
8375 				ZBX_DC_SNMPITEM	*snmpitem;
8376 
8377 				snmpitem = (ZBX_DC_SNMPITEM *)zbx_hashset_search(&config->snmpitems, &dc_item->itemid);
8378 
8379 				if (ZBX_SNMP_OID_TYPE_NORMAL == snmpitem->snmp_oid_type ||
8380 						ZBX_SNMP_OID_TYPE_DYNAMIC == snmpitem->snmp_oid_type)
8381 				{
8382 					max_items = DCconfig_get_suggested_snmp_vars_nolock(dc_item->interfaceid, NULL);
8383 				}
8384 			}
8385 
8386 			if (1 < max_items)
8387 				*items = zbx_malloc(NULL, sizeof(DC_ITEM) * max_items);
8388 		}
8389 
8390 		dc_item_prev = dc_item;
8391 		dc_item->location = ZBX_LOC_POLLER;
8392 		DCget_host(&(*items)[num].host, dc_host, ZBX_ITEM_GET_ALL);
8393 		DCget_item(&(*items)[num], dc_item, ZBX_ITEM_GET_ALL);
8394 		num++;
8395 	}
8396 
8397 	UNLOCK_CACHE;
8398 
8399 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, num);
8400 
8401 	return num;
8402 }
8403 
8404 /******************************************************************************
8405  *                                                                            *
8406  * Function: DCconfig_get_ipmi_poller_items                                   *
8407  *                                                                            *
8408  * Purpose: Get array of items for IPMI poller                                *
8409  *                                                                            *
8410  * Parameters: now       - [IN] current timestamp                             *
8411  *             items     - [OUT] array of items                               *
8412  *             items_num - [IN] the number of items to get                    *
8413  *             nextcheck - [OUT] the next scheduled check                     *
8414  *                                                                            *
8415  * Return value: number of items in items array                               *
8416  *                                                                            *
8417  * Comments: IPMI items leave the queue only through this function. IPMI      *
8418  *           manager must always return the items they have taken using       *
8419  *           DCrequeue_items() or DCpoller_requeue_items().                   *
8420  *                                                                            *
8421  ******************************************************************************/
DCconfig_get_ipmi_poller_items(int now,DC_ITEM * items,int items_num,int * nextcheck)8422 int	DCconfig_get_ipmi_poller_items(int now, DC_ITEM *items, int items_num, int *nextcheck)
8423 {
8424 	int			num = 0;
8425 	zbx_binary_heap_t	*queue;
8426 
8427 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
8428 
8429 	queue = &config->queues[ZBX_POLLER_TYPE_IPMI];
8430 
8431 	WRLOCK_CACHE;
8432 
8433 	while (num < items_num && FAIL == zbx_binary_heap_empty(queue))
8434 	{
8435 		int				disable_until;
8436 		const zbx_binary_heap_elem_t	*min;
8437 		ZBX_DC_HOST			*dc_host;
8438 		ZBX_DC_ITEM			*dc_item;
8439 
8440 		min = zbx_binary_heap_find_min(queue);
8441 		dc_item = (ZBX_DC_ITEM *)min->data;
8442 
8443 		if (dc_item->nextcheck > now)
8444 			break;
8445 
8446 		zbx_binary_heap_remove_min(queue);
8447 		dc_item->location = ZBX_LOC_NOWHERE;
8448 
8449 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8450 			continue;
8451 
8452 		if (HOST_STATUS_MONITORED != dc_host->status)
8453 			continue;
8454 
8455 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
8456 		{
8457 			dc_requeue_item(dc_item, dc_host, dc_item->state, ZBX_ITEM_COLLECTED, now);
8458 			continue;
8459 		}
8460 
8461 		/* don't apply unreachable item/host throttling for prioritized items */
8462 		if (ZBX_QUEUE_PRIORITY_HIGH != dc_item->queue_priority)
8463 		{
8464 			if (0 != (disable_until = DCget_disable_until(dc_item, dc_host)))
8465 			{
8466 				if (disable_until > now)
8467 				{
8468 					dc_requeue_item(dc_item, dc_host, dc_item->state,
8469 							ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE, now);
8470 					continue;
8471 				}
8472 
8473 				DCincrease_disable_until(dc_item, dc_host, now);
8474 			}
8475 		}
8476 
8477 		dc_item->location = ZBX_LOC_POLLER;
8478 		DCget_host(&items[num].host, dc_host, ZBX_ITEM_GET_ALL);
8479 		DCget_item(&items[num], dc_item, ZBX_ITEM_GET_ALL);
8480 		num++;
8481 	}
8482 
8483 	*nextcheck = dc_config_get_queue_nextcheck(&config->queues[ZBX_POLLER_TYPE_IPMI]);
8484 
8485 	UNLOCK_CACHE;
8486 
8487 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, num);
8488 
8489 	return num;
8490 }
8491 
8492 
8493 /******************************************************************************
8494  *                                                                            *
8495  * Function: DCconfig_get_snmp_interfaceids_by_addr                           *
8496  *                                                                            *
8497  * Purpose: get array of interface IDs for the specified address              *
8498  *                                                                            *
8499  * Return value: number of interface IDs returned                             *
8500  *                                                                            *
8501  * Author: Rudolfs Kreicbergs                                                 *
8502  *                                                                            *
8503  ******************************************************************************/
DCconfig_get_snmp_interfaceids_by_addr(const char * addr,zbx_uint64_t ** interfaceids)8504 int	DCconfig_get_snmp_interfaceids_by_addr(const char *addr, zbx_uint64_t **interfaceids)
8505 {
8506 	int				count = 0, i;
8507 	const ZBX_DC_INTERFACE_ADDR	*dc_interface_snmpaddr;
8508 	ZBX_DC_INTERFACE_ADDR		dc_interface_snmpaddr_local;
8509 
8510 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() addr:'%s'", __func__, addr);
8511 
8512 	dc_interface_snmpaddr_local.addr = addr;
8513 
8514 	RDLOCK_CACHE;
8515 
8516 	if (NULL == (dc_interface_snmpaddr = (const ZBX_DC_INTERFACE_ADDR *)zbx_hashset_search(&config->interface_snmpaddrs, &dc_interface_snmpaddr_local)))
8517 		goto unlock;
8518 
8519 	*interfaceids = (zbx_uint64_t *)zbx_malloc(*interfaceids, dc_interface_snmpaddr->interfaceids.values_num * sizeof(zbx_uint64_t));
8520 
8521 	for (i = 0; i < dc_interface_snmpaddr->interfaceids.values_num; i++)
8522 		(*interfaceids)[i] = dc_interface_snmpaddr->interfaceids.values[i];
8523 
8524 	count = i;
8525 unlock:
8526 	UNLOCK_CACHE;
8527 
8528 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, count);
8529 
8530 	return count;
8531 }
8532 
8533 /******************************************************************************
8534  *                                                                            *
8535  * Function: DCconfig_get_snmp_items_by_interfaceid                           *
8536  *                                                                            *
8537  * Purpose: get array of snmp trap items for the specified interfaceid        *
8538  *                                                                            *
8539  * Return value: number of items returned                                     *
8540  *                                                                            *
8541  * Author: Rudolfs Kreicbergs                                                 *
8542  *                                                                            *
8543  ******************************************************************************/
DCconfig_get_snmp_items_by_interfaceid(zbx_uint64_t interfaceid,DC_ITEM ** items)8544 size_t	DCconfig_get_snmp_items_by_interfaceid(zbx_uint64_t interfaceid, DC_ITEM **items)
8545 {
8546 	size_t				items_num = 0, items_alloc = 8;
8547 	int				i;
8548 	const ZBX_DC_ITEM		*dc_item;
8549 	const ZBX_DC_INTERFACE_ITEM	*dc_interface_snmpitem;
8550 	const ZBX_DC_INTERFACE		*dc_interface;
8551 	const ZBX_DC_HOST		*dc_host;
8552 
8553 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() interfaceid:" ZBX_FS_UI64, __func__, interfaceid);
8554 
8555 	RDLOCK_CACHE;
8556 
8557 	if (NULL == (dc_interface = (const ZBX_DC_INTERFACE *)zbx_hashset_search(&config->interfaces, &interfaceid)))
8558 		goto unlock;
8559 
8560 	if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_interface->hostid)))
8561 		goto unlock;
8562 
8563 	if (HOST_STATUS_MONITORED != dc_host->status)
8564 		goto unlock;
8565 
8566 	if (NULL == (dc_interface_snmpitem = (const ZBX_DC_INTERFACE_ITEM *)zbx_hashset_search(&config->interface_snmpitems, &interfaceid)))
8567 		goto unlock;
8568 
8569 	*items = (DC_ITEM *)zbx_malloc(*items, items_alloc * sizeof(DC_ITEM));
8570 
8571 	for (i = 0; i < dc_interface_snmpitem->itemids.values_num; i++)
8572 	{
8573 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_interface_snmpitem->itemids.values[i])))
8574 			continue;
8575 
8576 		if (ITEM_STATUS_ACTIVE != dc_item->status)
8577 			continue;
8578 
8579 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
8580 			continue;
8581 
8582 		if (0 == config->config->refresh_unsupported && ITEM_STATE_NOTSUPPORTED == dc_item->state)
8583 			continue;
8584 
8585 		if (items_num == items_alloc)
8586 		{
8587 			items_alloc += 8;
8588 			*items = (DC_ITEM *)zbx_realloc(*items, items_alloc * sizeof(DC_ITEM));
8589 		}
8590 
8591 		DCget_host(&(*items)[items_num].host, dc_host, ZBX_ITEM_GET_ALL);
8592 		DCget_item(&(*items)[items_num], dc_item, ZBX_ITEM_GET_ALL);
8593 		items_num++;
8594 	}
8595 unlock:
8596 	UNLOCK_CACHE;
8597 
8598 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():" ZBX_FS_SIZE_T, __func__, (zbx_fs_size_t)items_num);
8599 
8600 	return items_num;
8601 }
8602 
dc_requeue_items(const zbx_uint64_t * itemids,const unsigned char * states,const int * lastclocks,const int * errcodes,size_t num)8603 static void	dc_requeue_items(const zbx_uint64_t *itemids, const unsigned char *states, const int *lastclocks,
8604 		const int *errcodes, size_t num)
8605 {
8606 	size_t		i;
8607 	ZBX_DC_ITEM	*dc_item;
8608 	ZBX_DC_HOST	*dc_host;
8609 
8610 	for (i = 0; i < num; i++)
8611 	{
8612 		if (FAIL == errcodes[i])
8613 			continue;
8614 
8615 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])))
8616 			continue;
8617 
8618 		if (ZBX_LOC_POLLER == dc_item->location)
8619 			dc_item->location = ZBX_LOC_NOWHERE;
8620 
8621 		if (ITEM_STATUS_ACTIVE != dc_item->status)
8622 			continue;
8623 
8624 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8625 			continue;
8626 
8627 		if (HOST_STATUS_MONITORED != dc_host->status)
8628 			continue;
8629 
8630 		if (SUCCEED != zbx_is_counted_in_item_queue(dc_item->type, dc_item->key))
8631 			continue;
8632 
8633 		switch (errcodes[i])
8634 		{
8635 			case SUCCEED:
8636 			case NOTSUPPORTED:
8637 			case AGENT_ERROR:
8638 			case CONFIG_ERROR:
8639 				dc_item->queue_priority = ZBX_QUEUE_PRIORITY_NORMAL;
8640 				dc_requeue_item(dc_item, dc_host, states[i], ZBX_ITEM_COLLECTED, lastclocks[i]);
8641 				break;
8642 			case NETWORK_ERROR:
8643 			case GATEWAY_ERROR:
8644 			case TIMEOUT_ERROR:
8645 				dc_item->queue_priority = ZBX_QUEUE_PRIORITY_LOW;
8646 				dc_requeue_item(dc_item, dc_host, states[i], ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE,
8647 						time(NULL));
8648 				break;
8649 			default:
8650 				THIS_SHOULD_NEVER_HAPPEN;
8651 		}
8652 	}
8653 }
8654 
DCrequeue_items(const zbx_uint64_t * itemids,const unsigned char * states,const int * lastclocks,const int * errcodes,size_t num)8655 void	DCrequeue_items(const zbx_uint64_t *itemids, const unsigned char *states, const int *lastclocks,
8656 		const int *errcodes, size_t num)
8657 {
8658 	WRLOCK_CACHE;
8659 
8660 	dc_requeue_items(itemids, states, lastclocks, errcodes, num);
8661 
8662 	UNLOCK_CACHE;
8663 }
8664 
DCpoller_requeue_items(const zbx_uint64_t * itemids,const unsigned char * states,const int * lastclocks,const int * errcodes,size_t num,unsigned char poller_type,int * nextcheck)8665 void	DCpoller_requeue_items(const zbx_uint64_t *itemids, const unsigned char *states, const int *lastclocks,
8666 		const int *errcodes, size_t num, unsigned char poller_type, int *nextcheck)
8667 {
8668 	WRLOCK_CACHE;
8669 
8670 	dc_requeue_items(itemids, states, lastclocks, errcodes, num);
8671 	*nextcheck = dc_config_get_queue_nextcheck(&config->queues[poller_type]);
8672 
8673 	UNLOCK_CACHE;
8674 }
8675 
8676 /******************************************************************************
8677  *                                                                            *
8678  * Function: zbx_dc_requeue_unreachable_items                                 *
8679  *                                                                            *
8680  * Purpose: requeue unreachable items                                         *
8681  *                                                                            *
8682  * Parameters: itemids     - [IN] the item id array                           *
8683  *             itemids_num - [IN] the number of values in itemids array       *
8684  *                                                                            *
8685  * Comments: This function is used when items must be put back in the queue   *
8686  *           without polling them. For example if a poller has taken a batch  *
8687  *           of items from queue, host becomes unreachable during while       *
8688  *           polling the items, so the unpolled items of the same host must   *
8689  *           be returned to queue without updating their status.              *
8690  *                                                                            *
8691  ******************************************************************************/
zbx_dc_requeue_unreachable_items(zbx_uint64_t * itemids,size_t itemids_num)8692 void	zbx_dc_requeue_unreachable_items(zbx_uint64_t *itemids, size_t itemids_num)
8693 {
8694 	size_t		i;
8695 	ZBX_DC_ITEM	*dc_item;
8696 	ZBX_DC_HOST	*dc_host;
8697 
8698 	WRLOCK_CACHE;
8699 
8700 	for (i = 0; i < itemids_num; i++)
8701 	{
8702 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids[i])))
8703 			continue;
8704 
8705 		if (ZBX_LOC_POLLER == dc_item->location)
8706 			dc_item->location = ZBX_LOC_NOWHERE;
8707 
8708 		if (ITEM_STATUS_ACTIVE != dc_item->status)
8709 			continue;
8710 
8711 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
8712 			continue;
8713 
8714 		if (HOST_STATUS_MONITORED != dc_host->status)
8715 			continue;
8716 
8717 		dc_requeue_item(dc_item, dc_host, dc_item->state, ZBX_ITEM_COLLECTED | ZBX_HOST_UNREACHABLE,
8718 				time(NULL));
8719 	}
8720 
8721 	UNLOCK_CACHE;
8722 }
8723 
8724 /******************************************************************************
8725  *                                                                            *
8726  * Function: DChost_get_agent_availability                                    *
8727  *                                                                            *
8728  * Purpose: get host availability data for the specified agent                *
8729  *                                                                            *
8730  * Parameters: dc_host      - [IN] the host                                   *
8731  *             agent        - [IN] the agent (see ZBX_FLAGS_AGENT_STATUS_*    *
8732  *                                 defines                                    *
8733  *             availability - [OUT] the host availability data                *
8734  *                                                                            *
8735  * Comments: The configuration cache must be locked already.                  *
8736  *                                                                            *
8737  ******************************************************************************/
DChost_get_agent_availability(const ZBX_DC_HOST * dc_host,unsigned char agent_type,zbx_agent_availability_t * agent)8738 static void	DChost_get_agent_availability(const ZBX_DC_HOST *dc_host, unsigned char agent_type,
8739 		zbx_agent_availability_t *agent)
8740 {
8741 
8742 	agent->flags = ZBX_FLAGS_AGENT_STATUS;
8743 
8744 	switch (agent_type)
8745 	{
8746 		case ZBX_AGENT_ZABBIX:
8747 			agent->available = dc_host->available;
8748 			agent->error = zbx_strdup(agent->error, dc_host->error);
8749 			agent->errors_from = dc_host->errors_from;
8750 			agent->disable_until = dc_host->disable_until;
8751 			break;
8752 		case ZBX_AGENT_SNMP:
8753 			agent->available = dc_host->snmp_available;
8754 			agent->error = zbx_strdup(agent->error, dc_host->snmp_error);
8755 			agent->errors_from = dc_host->snmp_errors_from;
8756 			agent->disable_until = dc_host->snmp_disable_until;
8757 			break;
8758 		case ZBX_AGENT_IPMI:
8759 			agent->available = dc_host->ipmi_available;
8760 			agent->error = zbx_strdup(agent->error, dc_host->ipmi_error);
8761 			agent->errors_from = dc_host->ipmi_errors_from;
8762 			agent->disable_until = dc_host->ipmi_disable_until;
8763 			break;
8764 		case ZBX_AGENT_JMX:
8765 			agent->available = dc_host->jmx_available;
8766 			agent->error = zbx_strdup(agent->error, dc_host->jmx_error);
8767 			agent->errors_from = dc_host->jmx_errors_from;
8768 			agent->disable_until = dc_host->jmx_disable_until;
8769 			break;
8770 	}
8771 }
8772 
DCagent_set_availability(zbx_agent_availability_t * av,unsigned char * available,const char ** error,int * errors_from,int * disable_until)8773 static void	DCagent_set_availability(zbx_agent_availability_t *av,  unsigned char *available, const char **error,
8774 		int *errors_from, int *disable_until)
8775 {
8776 #define AGENT_AVAILABILITY_ASSIGN(flags, mask, dst, src)	\
8777 	if (0 != (flags & mask))				\
8778 	{							\
8779 		if (dst != src)					\
8780 			dst = src;				\
8781 		else						\
8782 			flags &= (~(mask));			\
8783 	}
8784 
8785 #define AGENT_AVAILABILITY_ASSIGN_STR(flags, mask, dst, src)	\
8786 	if (0 != (flags & mask))				\
8787 	{							\
8788 		if (0 != strcmp(dst, src))			\
8789 			DCstrpool_replace(1, &dst, src);	\
8790 		else						\
8791 			flags &= (~(mask));			\
8792 	}
8793 
8794 	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_AVAILABLE, *available, av->available);
8795 	AGENT_AVAILABILITY_ASSIGN_STR(av->flags, ZBX_FLAGS_AGENT_STATUS_ERROR, *error, av->error);
8796 	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_ERRORS_FROM, *errors_from, av->errors_from);
8797 	AGENT_AVAILABILITY_ASSIGN(av->flags, ZBX_FLAGS_AGENT_STATUS_DISABLE_UNTIL, *disable_until, av->disable_until);
8798 
8799 #undef AGENT_AVAILABILITY_ASSIGN_STR
8800 #undef AGENT_AVAILABILITY_ASSIGN
8801 }
8802 
8803 /******************************************************************************
8804  *                                                                            *
8805  * Function: DChost_set_agent_availability                                    *
8806  *                                                                            *
8807  * Purpose: set host availability data in configuration cache                 *
8808  *                                                                            *
8809  * Parameters: dc_host      - [OUT] the host                                  *
8810  *             availability - [IN/OUT] the host availability data             *
8811  *                                                                            *
8812  * Return value: SUCCEED - at least one availability field was updated        *
8813  *               FAIL    - no availability fields were updated                *
8814  *                                                                            *
8815  * Comments: The configuration cache must be locked already.                  *
8816  *                                                                            *
8817  *           This function clears availability flags of non updated fields    *
8818  *           updated leaving only flags identifying changed fields.           *
8819  *                                                                            *
8820  ******************************************************************************/
DChost_set_agent_availability(ZBX_DC_HOST * dc_host,int now,unsigned char agent_type,zbx_agent_availability_t * agent)8821 static int	DChost_set_agent_availability(ZBX_DC_HOST *dc_host, int now, unsigned char agent_type,
8822 		zbx_agent_availability_t *agent)
8823 {
8824 	switch (agent_type)
8825 	{
8826 		case ZBX_AGENT_ZABBIX:
8827 			DCagent_set_availability(agent, &dc_host->available,
8828 					&dc_host->error, &dc_host->errors_from, &dc_host->disable_until);
8829 			break;
8830 		case ZBX_AGENT_SNMP:
8831 			DCagent_set_availability(agent, &dc_host->snmp_available,
8832 					&dc_host->snmp_error, &dc_host->snmp_errors_from, &dc_host->snmp_disable_until);
8833 			break;
8834 		case ZBX_AGENT_IPMI:
8835 			DCagent_set_availability(agent, &dc_host->ipmi_available,
8836 					&dc_host->ipmi_error, &dc_host->ipmi_errors_from, &dc_host->ipmi_disable_until);
8837 			break;
8838 		case ZBX_AGENT_JMX:
8839 			DCagent_set_availability(agent, &dc_host->jmx_available,
8840 					&dc_host->jmx_error, &dc_host->jmx_errors_from, &dc_host->jmx_disable_until);
8841 			break;
8842 	}
8843 
8844 	if (ZBX_FLAGS_AGENT_STATUS_NONE == agent->flags)
8845 		return FAIL;
8846 
8847 	if (0 != (agent->flags & (ZBX_FLAGS_AGENT_STATUS_AVAILABLE | ZBX_FLAGS_AGENT_STATUS_ERROR)))
8848 		dc_host->availability_ts = now;
8849 
8850 	return SUCCEED;
8851 }
8852 
8853 /******************************************************************************
8854  *                                                                            *
8855  * Function: DChost_set_availability                                          *
8856  *                                                                            *
8857  * Purpose: set host availability data in configuration cache                 *
8858  *                                                                            *
8859  * Parameters: dc_host      - [OUT] the host                                  *
8860  *             availability - [IN/OUT] the host availability data             *
8861  *                                                                            *
8862  * Return value: SUCCEED - at least one availability field was updated        *
8863  *               FAIL    - no availability fields were updated                *
8864  *                                                                            *
8865  * Comments: The configuration cache must be locked already.                  *
8866  *                                                                            *
8867  *           This function clears availability flags of non updated fields    *
8868  *           updated leaving only flags identifying changed fields.           *
8869  *                                                                            *
8870  ******************************************************************************/
DChost_set_availability(ZBX_DC_HOST * dc_host,int now,zbx_host_availability_t * ha)8871 static int	DChost_set_availability(ZBX_DC_HOST *dc_host, int now, zbx_host_availability_t *ha)
8872 {
8873 	int		i;
8874 	unsigned char	flags = ZBX_FLAGS_AGENT_STATUS_NONE;
8875 
8876 	DCagent_set_availability(&ha->agents[ZBX_AGENT_ZABBIX], &dc_host->available, &dc_host->error,
8877 			&dc_host->errors_from, &dc_host->disable_until);
8878 	DCagent_set_availability(&ha->agents[ZBX_AGENT_SNMP], &dc_host->snmp_available, &dc_host->snmp_error,
8879 			&dc_host->snmp_errors_from, &dc_host->snmp_disable_until);
8880 	DCagent_set_availability(&ha->agents[ZBX_AGENT_IPMI], &dc_host->ipmi_available, &dc_host->ipmi_error,
8881 			&dc_host->ipmi_errors_from, &dc_host->ipmi_disable_until);
8882 	DCagent_set_availability(&ha->agents[ZBX_AGENT_JMX], &dc_host->jmx_available, &dc_host->jmx_error,
8883 			&dc_host->jmx_errors_from, &dc_host->jmx_disable_until);
8884 
8885 	for (i = 0; i < ZBX_AGENT_MAX; i++)
8886 		flags |= ha->agents[i].flags;
8887 
8888 	if (ZBX_FLAGS_AGENT_STATUS_NONE == flags)
8889 		return FAIL;
8890 
8891 	if (0 != (flags & (ZBX_FLAGS_AGENT_STATUS_AVAILABLE | ZBX_FLAGS_AGENT_STATUS_ERROR)))
8892 		dc_host->availability_ts = now;
8893 
8894 	return SUCCEED;
8895 }
8896 
8897 /******************************************************************************
8898  *                                                                            *
8899  * Function: zbx_host_availability_init                                       *
8900  *                                                                            *
8901  * Purpose: initializes host availability data                                *
8902  *                                                                            *
8903  * Parameters: availability - [IN/OUT] host availability data                 *
8904  *                                                                            *
8905  ******************************************************************************/
zbx_host_availability_init(zbx_host_availability_t * availability,zbx_uint64_t hostid)8906 void	zbx_host_availability_init(zbx_host_availability_t *availability, zbx_uint64_t hostid)
8907 {
8908 	memset(availability, 0, sizeof(zbx_host_availability_t));
8909 	availability->hostid = hostid;
8910 }
8911 
8912 /******************************************************************************
8913  *                                                                            *
8914  * Function: zbx_host_availability_clean                                      *
8915  *                                                                            *
8916  * Purpose: releases resources allocated to store host availability data      *
8917  *                                                                            *
8918  * Parameters: ha - [IN] host availability data                               *
8919  *                                                                            *
8920  ******************************************************************************/
zbx_host_availability_clean(zbx_host_availability_t * ha)8921 void	zbx_host_availability_clean(zbx_host_availability_t *ha)
8922 {
8923 	int	i;
8924 
8925 	for (i = 0; i < ZBX_AGENT_MAX; i++)
8926 		zbx_free(ha->agents[i].error);
8927 }
8928 
8929 /******************************************************************************
8930  *                                                                            *
8931  * Function: zbx_host_availability_free                                       *
8932  *                                                                            *
8933  * Purpose: frees host availability data                                      *
8934  *                                                                            *
8935  * Parameters: availability - [IN] host availability data                     *
8936  *                                                                            *
8937  ******************************************************************************/
zbx_host_availability_free(zbx_host_availability_t * availability)8938 void	zbx_host_availability_free(zbx_host_availability_t *availability)
8939 {
8940 	zbx_host_availability_clean(availability);
8941 	zbx_free(availability);
8942 }
8943 
8944 /******************************************************************************
8945  *                                                                            *
8946  * Function: zbx_agent_availability_init                                      *
8947  *                                                                            *
8948  * Purpose: initializes agent availability with the specified data            *
8949  *                                                                            *
8950  * Parameters: availability  - [IN/OUT] agent availability data               *
8951  *             hostid        - [IN] the host identifier                       *
8952  *             flags         - [IN] the availability flags indicating which   *
8953  *                                  availability fields to set                *
8954  *             available     - [IN] the availability data                     *
8955  *             error         - [IN]                                           *
8956  *             errors_from   - [IN]                                           *
8957  *             disable_until - [IN]                                           *
8958  *                                                                            *
8959  ******************************************************************************/
zbx_agent_availability_init(zbx_agent_availability_t * agent,unsigned char available,const char * error,int errors_from,int disable_until)8960 static void	zbx_agent_availability_init(zbx_agent_availability_t *agent, unsigned char available, const char *error,
8961 		int errors_from, int disable_until)
8962 {
8963 	agent->flags = ZBX_FLAGS_AGENT_STATUS;
8964 	agent->available = available;
8965 	agent->error = zbx_strdup(agent->error, error);
8966 	agent->errors_from = errors_from;
8967 	agent->disable_until = disable_until;
8968 }
8969 
8970 /******************************************************************************
8971  *                                                                            *
8972  * Function: zbx_host_availability_is_set                                     *
8973  *                                                                            *
8974  * Purpose: checks host availability if any agent availability field is set   *
8975  *                                                                            *
8976  * Parameters: availability - [IN] host availability data                     *
8977  *                                                                            *
8978  * Return value: SUCCEED - an agent availability field is set                 *
8979  *               FAIL - no agent availability fields are set                  *
8980  *                                                                            *
8981  ******************************************************************************/
zbx_host_availability_is_set(const zbx_host_availability_t * ha)8982 int	zbx_host_availability_is_set(const zbx_host_availability_t *ha)
8983 {
8984 	int	i;
8985 
8986 	for (i = 0; i < ZBX_AGENT_MAX; i++)
8987 	{
8988 		if (ZBX_FLAGS_AGENT_STATUS_NONE != ha->agents[i].flags)
8989 			return SUCCEED;
8990 	}
8991 
8992 	return FAIL;
8993 }
8994 
8995 /**************************************************************************************
8996  *                                                                                    *
8997  * Host availability update example                                                   *
8998  *                                                                                    *
8999  *                                                                                    *
9000  *               |            UnreachablePeriod                                       *
9001  *               |               (conf file)                                          *
9002  *               |              ______________                                        *
9003  *               |             /              \                                       *
9004  *               |             p     p     p     p       p       p                    *
9005  *               |             o     o     o     o       o       o                    *
9006  *               |             l     l     l     l       l       l                    *
9007  *               |             l     l     l     l       l       l                    *
9008  *               | n                                                                  *
9009  *               | e           e     e     e     e       e       e                    *
9010  *     agent     | w   p   p   r     r     r     r       r       r       p   p   p    *
9011  *       polls   |     o   o   r     r     r     r       r       r       o   o   o    *
9012  *               | h   l   l   o     o     o     o       o       o       l   l   l    *
9013  *               | o   l   l   r     r     r     r       r       r       l   l   l    *
9014  *               | s                                                                  *
9015  *               | t   ok  ok  E1    E1    E2    E1      E1      E2      ok  ok  ok   *
9016  *  --------------------------------------------------------------------------------  *
9017  *  available    | 0   1   1   1     1     1     2       2       2       0   0   0    *
9018  *               |                                                                    *
9019  *  error        | ""  ""  ""  ""    ""    ""    E1      E1      E2      ""  ""  ""   *
9020  *               |                                                                    *
9021  *  errors_from  | 0   0   0   T4    T4    T4    T4      T4      T4      0   0   0    *
9022  *               |                                                                    *
9023  *  disable_until| 0   0   0   T5    T6    T7    T8      T9      T10     0   0   0    *
9024  *  --------------------------------------------------------------------------------  *
9025  *   timestamps  | T1  T2  T3  T4    T5    T6    T7      T8      T9     T10 T11 T12   *
9026  *               |  \_/ \_/ \_/ \___/ \___/ \___/ \_____/ \_____/ \_____/ \_/ \_/     *
9027  *               |   |   |   |    |     |     |      |       |       |     |   |      *
9028  *  polling      |  item delay   UnreachableDelay    UnavailableDelay     item |      *
9029  *      periods  |                 (conf file)         (conf file)         delay      *
9030  *                                                                                    *
9031  *                                                                                    *
9032  **************************************************************************************/
9033 
9034 /******************************************************************************
9035  *                                                                            *
9036  * Function: DChost_activate                                                  *
9037  *                                                                            *
9038  * Purpose: set host as available based on the agent availability data        *
9039  *                                                                            *
9040  * Parameters: hostid     - [IN] the host identifier                          *
9041  *             agent_type - [IN] the agent type (see ZBX_AGENT_* defines)     *
9042  *             ts         - [IN] the last timestamp                           *
9043  *             in         - [IN/OUT] IN: the caller's agent availability data *
9044  *                                  OUT: the agent availability data in cache *
9045  *                                       before changes                       *
9046  *             out        - [OUT] the agent availability data after changes   *
9047  *                                                                            *
9048  * Return value: SUCCEED - the host was activated successfully                *
9049  *               FAIL    - the host was already activated or activation       *
9050  *                         failed                                             *
9051  *                                                                            *
9052  * Comments: The host availability fields are updated according to the above  *
9053  *           schema.                                                          *
9054  *                                                                            *
9055  ******************************************************************************/
DChost_activate(zbx_uint64_t hostid,unsigned char agent_type,const zbx_timespec_t * ts,zbx_agent_availability_t * in,zbx_agent_availability_t * out)9056 int	DChost_activate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_timespec_t *ts,
9057 		zbx_agent_availability_t *in, zbx_agent_availability_t *out)
9058 {
9059 	int		ret = FAIL;
9060 	ZBX_DC_HOST	*dc_host;
9061 
9062 	/* don't try activating host if there were no errors detected */
9063 	if (0 == in->errors_from && HOST_AVAILABLE_TRUE == in->available)
9064 		goto out;
9065 
9066 	WRLOCK_CACHE;
9067 
9068 	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
9069 		goto unlock;
9070 
9071 	/* Don't try activating host if:                  */
9072 	/* - (server, proxy) it's not monitored any more; */
9073 	/* - (server) it's monitored by proxy.            */
9074 	if ((0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != dc_host->proxy_hostid) ||
9075 			HOST_STATUS_MONITORED != dc_host->status)
9076 	{
9077 		goto unlock;
9078 	}
9079 
9080 	DChost_get_agent_availability(dc_host, agent_type, in);
9081 	zbx_agent_availability_init(out, HOST_AVAILABLE_TRUE, "", 0, 0);
9082 	DChost_set_agent_availability(dc_host, ts->sec, agent_type, out);
9083 
9084 	if (ZBX_FLAGS_AGENT_STATUS_NONE != out->flags)
9085 		ret = SUCCEED;
9086 unlock:
9087 	UNLOCK_CACHE;
9088 out:
9089 	return ret;
9090 }
9091 
9092 /******************************************************************************
9093  *                                                                            *
9094  * Function: DChost_deactivate                                                *
9095  *                                                                            *
9096  * Purpose: attempt to set host as unavailable based on agent availability    *
9097  *                                                                            *
9098  * Parameters: hostid     - [IN] the host identifier                          *
9099  *             agent_type - [IN] the agent type (see ZBX_AGENT_* defines)     *
9100  *             ts         - [IN] the last timestamp                           *
9101  *             in         - [IN/OUT] IN: the caller's host availability data  *
9102  *                                  OUT: the host availability data in cache  *
9103  *                                       before changes                       *
9104  *             out        - [OUT] the host availability data after changes    *
9105  *             error_msg  - [IN] the error message                            *
9106  *                                                                            *
9107  * Return value: SUCCEED - the host was deactivated successfully              *
9108  *               FAIL    - the host was already deactivated or deactivation   *
9109  *                         failed                                             *
9110  *                                                                            *
9111  * Comments: The host availability fields are updated according to the above  *
9112  *           schema.                                                          *
9113  *                                                                            *
9114  ******************************************************************************/
DChost_deactivate(zbx_uint64_t hostid,unsigned char agent_type,const zbx_timespec_t * ts,zbx_agent_availability_t * in,zbx_agent_availability_t * out,const char * error_msg)9115 int	DChost_deactivate(zbx_uint64_t hostid, unsigned char agent_type, const zbx_timespec_t *ts,
9116 		zbx_agent_availability_t *in, zbx_agent_availability_t *out, const char *error_msg)
9117 {
9118 	int		ret = FAIL, errors_from,disable_until;
9119 	const char	*error;
9120 	unsigned char	available;
9121 	ZBX_DC_HOST	*dc_host;
9122 
9123 
9124 	/* don't try deactivating host if the unreachable delay has not passed since the first error */
9125 	if (CONFIG_UNREACHABLE_DELAY > ts->sec - in->errors_from)
9126 		goto out;
9127 
9128 	WRLOCK_CACHE;
9129 
9130 	if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
9131 		goto unlock;
9132 
9133 	/* Don't try deactivating host if:                */
9134 	/* - (server, proxy) it's not monitored any more; */
9135 	/* - (server) it's monitored by proxy.            */
9136 	if ((0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != dc_host->proxy_hostid) ||
9137 			HOST_STATUS_MONITORED != dc_host->status)
9138 	{
9139 		goto unlock;
9140 	}
9141 
9142 	DChost_get_agent_availability(dc_host, agent_type, in);
9143 
9144 	available = in->available;
9145 	error = in->error;
9146 
9147 	if (0 == in->errors_from)
9148 	{
9149 		/* first error, schedule next unreachable check */
9150 		errors_from = ts->sec;
9151 		disable_until = ts->sec + CONFIG_UNREACHABLE_DELAY;
9152 	}
9153 	else
9154 	{
9155 		errors_from = in->errors_from;
9156 		disable_until = in->disable_until;
9157 
9158 		/* Check if other pollers haven't already attempted deactivating host. */
9159 		/* In that case should wait the initial unreachable delay before       */
9160 		/* trying to make it unavailable.                                      */
9161 		if (CONFIG_UNREACHABLE_DELAY <= ts->sec - errors_from)
9162 		{
9163 			/* repeating error */
9164 			if (CONFIG_UNREACHABLE_PERIOD > ts->sec - errors_from)
9165 			{
9166 				/* leave host available, schedule next unreachable check */
9167 				disable_until = ts->sec + CONFIG_UNREACHABLE_DELAY;
9168 			}
9169 			else
9170 			{
9171 				/* make host unavailable, schedule next unavailable check */
9172 				disable_until = ts->sec + CONFIG_UNAVAILABLE_DELAY;
9173 				available = HOST_AVAILABLE_FALSE;
9174 				error = error_msg;
9175 			}
9176 		}
9177 	}
9178 
9179 	zbx_agent_availability_init(out, available, error, errors_from, disable_until);
9180 	DChost_set_agent_availability(dc_host, ts->sec, agent_type, out);
9181 
9182 	if (ZBX_FLAGS_AGENT_STATUS_NONE != out->flags)
9183 		ret = SUCCEED;
9184 unlock:
9185 	UNLOCK_CACHE;
9186 out:
9187 	return ret;
9188 }
9189 
9190 /******************************************************************************
9191  *                                                                            *
9192  * Function: DCset_hosts_availability                                         *
9193  *                                                                            *
9194  * Purpose: update availability of hosts in configuration cache and return    *
9195  *          the updated field flags                                           *
9196  *                                                                            *
9197  * Parameters: availabilities - [IN/OUT] the hosts availability data          *
9198  *                                                                            *
9199  * Return value: SUCCEED - at least one host availability data was updated    *
9200  *               FAIL    - no hosts were updated                              *
9201  *                                                                            *
9202  ******************************************************************************/
DCset_hosts_availability(zbx_vector_ptr_t * availabilities)9203 int	DCset_hosts_availability(zbx_vector_ptr_t *availabilities)
9204 {
9205 	int			i;
9206 	ZBX_DC_HOST		*dc_host;
9207 	zbx_host_availability_t	*ha;
9208 	int			ret = FAIL, now;
9209 
9210 	now = time(NULL);
9211 
9212 	WRLOCK_CACHE;
9213 
9214 	for (i = 0; i < availabilities->values_num; i++)
9215 	{
9216 		ha = (zbx_host_availability_t *)availabilities->values[i];
9217 
9218 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &ha->hostid)))
9219 		{
9220 			int	j;
9221 
9222 			/* reset availability flags so this host is ignored when saving availability diff to DB */
9223 			for (j = 0; j < ZBX_AGENT_MAX; j++)
9224 				ha->agents[j].flags = ZBX_FLAGS_AGENT_STATUS_NONE;
9225 
9226 			continue;
9227 		}
9228 
9229 		if (SUCCEED == DChost_set_availability(dc_host, now, ha))
9230 			ret = SUCCEED;
9231 	}
9232 
9233 	UNLOCK_CACHE;
9234 
9235 	return ret;
9236 }
9237 
9238 /******************************************************************************
9239  *                                                                            *
9240  * Comments: helper function for trigger dependency checking                  *
9241  *                                                                            *
9242  * Parameters: trigdep        - [IN] the trigger dependency data              *
9243  *             level          - [IN] the trigger dependency level             *
9244  *             triggerids     - [IN] the currently processing trigger ids     *
9245  *                                   for bulk trigger operations              *
9246  *                                   (optional, can be NULL)                  *
9247  *             master_triggerids - [OUT] unresolved master trigger ids        *
9248  *                                   for bulk trigger operations              *
9249  *                                   (optional together with triggerids       *
9250  *                                   parameter)                               *
9251  *                                                                            *
9252  * Return value: SUCCEED - trigger dependency check succeed / was unresolved  *
9253  *               FAIL    - otherwise                                          *
9254  *                                                                            *
9255  * Comments: With bulk trigger processing a master trigger can be in the same *
9256  *           batch as dependent trigger. In this case it might be impossible  *
9257  *           to perform dependency check based on cashed trigger values. The  *
9258  *           unresolved master trigger ids will be added to master_triggerids *
9259  *           vector, so the dependency check can be performed after a new     *
9260  *           master trigger value has been calculated.                        *
9261  *                                                                            *
9262  ******************************************************************************/
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)9263 static int	DCconfig_check_trigger_dependencies_rec(const ZBX_DC_TRIGGER_DEPLIST *trigdep, int level,
9264 		const zbx_vector_uint64_t *triggerids, zbx_vector_uint64_t *master_triggerids)
9265 {
9266 	int				i;
9267 	const ZBX_DC_TRIGGER		*next_trigger;
9268 	const ZBX_DC_TRIGGER_DEPLIST	*next_trigdep;
9269 
9270 	if (ZBX_TRIGGER_DEPENDENCY_LEVELS_MAX < level)
9271 	{
9272 		zabbix_log(LOG_LEVEL_CRIT, "recursive trigger dependency is too deep (triggerid:" ZBX_FS_UI64 ")",
9273 				trigdep->triggerid);
9274 		return SUCCEED;
9275 	}
9276 
9277 	if (0 != trigdep->dependencies.values_num)
9278 	{
9279 		for (i = 0; i < trigdep->dependencies.values_num; i++)
9280 		{
9281 			next_trigdep = (const ZBX_DC_TRIGGER_DEPLIST *)trigdep->dependencies.values[i];
9282 
9283 			if (NULL != (next_trigger = next_trigdep->trigger) &&
9284 					TRIGGER_STATUS_ENABLED == next_trigger->status &&
9285 					TRIGGER_FUNCTIONAL_TRUE == next_trigger->functional)
9286 			{
9287 
9288 				if (NULL == triggerids || FAIL == zbx_vector_uint64_bsearch(triggerids,
9289 						next_trigger->triggerid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
9290 				{
9291 					if (TRIGGER_VALUE_PROBLEM == next_trigger->value)
9292 						return FAIL;
9293 				}
9294 				else
9295 					zbx_vector_uint64_append(master_triggerids, next_trigger->triggerid);
9296 			}
9297 
9298 			if (FAIL == DCconfig_check_trigger_dependencies_rec(next_trigdep, level + 1, triggerids,
9299 					master_triggerids))
9300 			{
9301 				return FAIL;
9302 			}
9303 		}
9304 	}
9305 
9306 	return SUCCEED;
9307 }
9308 
9309 /******************************************************************************
9310  *                                                                            *
9311  * Function: DCconfig_check_trigger_dependencies                              *
9312  *                                                                            *
9313  * Purpose: check whether any of trigger dependencies have value PROBLEM      *
9314  *                                                                            *
9315  * Return value: SUCCEED - trigger can change its value                       *
9316  *               FAIL - otherwise                                             *
9317  *                                                                            *
9318  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
9319  *                                                                            *
9320  ******************************************************************************/
DCconfig_check_trigger_dependencies(zbx_uint64_t triggerid)9321 int	DCconfig_check_trigger_dependencies(zbx_uint64_t triggerid)
9322 {
9323 	int				ret = SUCCEED;
9324 	const ZBX_DC_TRIGGER_DEPLIST	*trigdep;
9325 
9326 	RDLOCK_CACHE;
9327 
9328 	if (NULL != (trigdep = (const ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps, &triggerid)))
9329 		ret = DCconfig_check_trigger_dependencies_rec(trigdep, 0, NULL, NULL);
9330 
9331 	UNLOCK_CACHE;
9332 
9333 	return ret;
9334 }
9335 
9336 /******************************************************************************
9337  *                                                                            *
9338  * Comments: helper function for DCconfig_sort_triggers_topologically()       *
9339  *                                                                            *
9340  ******************************************************************************/
DCconfig_sort_triggers_topologically_rec(const ZBX_DC_TRIGGER_DEPLIST * trigdep,int level)9341 static unsigned char	DCconfig_sort_triggers_topologically_rec(const ZBX_DC_TRIGGER_DEPLIST *trigdep, int level)
9342 {
9343 	int				i;
9344 	unsigned char			topoindex = 2, next_topoindex;
9345 	const ZBX_DC_TRIGGER_DEPLIST	*next_trigdep;
9346 
9347 	if (32 < level)
9348 	{
9349 		zabbix_log(LOG_LEVEL_CRIT, "recursive trigger dependency is too deep (triggerid:" ZBX_FS_UI64 ")",
9350 				trigdep->triggerid);
9351 		goto exit;
9352 	}
9353 
9354 	if (0 == trigdep->trigger->topoindex)
9355 	{
9356 		zabbix_log(LOG_LEVEL_CRIT, "trigger dependencies contain a cycle (triggerid:" ZBX_FS_UI64 ")",
9357 				trigdep->triggerid);
9358 		goto exit;
9359 	}
9360 
9361 	trigdep->trigger->topoindex = 0;
9362 
9363 	for (i = 0; i < trigdep->dependencies.values_num; i++)
9364 	{
9365 		next_trigdep = (const ZBX_DC_TRIGGER_DEPLIST *)trigdep->dependencies.values[i];
9366 
9367 		if (1 < (next_topoindex = next_trigdep->trigger->topoindex))
9368 			goto next;
9369 
9370 		if (0 == next_trigdep->dependencies.values_num)
9371 			continue;
9372 
9373 		next_topoindex = DCconfig_sort_triggers_topologically_rec(next_trigdep, level + 1);
9374 next:
9375 		if (topoindex < next_topoindex + 1)
9376 			topoindex = next_topoindex + 1;
9377 	}
9378 
9379 	trigdep->trigger->topoindex = topoindex;
9380 exit:
9381 	return topoindex;
9382 }
9383 
9384 /******************************************************************************
9385  *                                                                            *
9386  * Function: DCconfig_sort_triggers_topologically                             *
9387  *                                                                            *
9388  * Purpose: assign each trigger an index based on trigger dependency topology *
9389  *                                                                            *
9390  * Author: Aleksandrs Saveljevs                                               *
9391  *                                                                            *
9392  ******************************************************************************/
DCconfig_sort_triggers_topologically(void)9393 static void	DCconfig_sort_triggers_topologically(void)
9394 {
9395 	zbx_hashset_iter_t		iter;
9396 	ZBX_DC_TRIGGER			*trigger;
9397 	const ZBX_DC_TRIGGER_DEPLIST	*trigdep;
9398 
9399 	zbx_hashset_iter_reset(&config->trigdeps, &iter);
9400 
9401 	while (NULL != (trigdep = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_iter_next(&iter)))
9402 	{
9403 		trigger = trigdep->trigger;
9404 
9405 		if (NULL == trigger || 1 < trigger->topoindex || 0 == trigdep->dependencies.values_num)
9406 			continue;
9407 
9408 		DCconfig_sort_triggers_topologically_rec(trigdep, 0);
9409 	}
9410 }
9411 
9412 /******************************************************************************
9413  *                                                                            *
9414  * Function: DCconfig_triggers_apply_changes                                  *
9415  *                                                                            *
9416  * Purpose: apply trigger value,state,lastchange or error changes to          *
9417  *          configuration cache after committed to database                   *
9418  *                                                                            *
9419  ******************************************************************************/
DCconfig_triggers_apply_changes(zbx_vector_ptr_t * trigger_diff)9420 void	DCconfig_triggers_apply_changes(zbx_vector_ptr_t *trigger_diff)
9421 {
9422 	int			i;
9423 	zbx_trigger_diff_t	*diff;
9424 	ZBX_DC_TRIGGER		*dc_trigger;
9425 
9426 	if (0 == trigger_diff->values_num)
9427 		return;
9428 
9429 	WRLOCK_CACHE;
9430 
9431 	for (i = 0; i < trigger_diff->values_num; i++)
9432 	{
9433 		diff = (zbx_trigger_diff_t *)trigger_diff->values[i];
9434 
9435 		if (NULL == (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_search(&config->triggers, &diff->triggerid)))
9436 			continue;
9437 
9438 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_LASTCHANGE))
9439 			dc_trigger->lastchange = diff->lastchange;
9440 
9441 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE))
9442 			dc_trigger->value = diff->value;
9443 
9444 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_STATE))
9445 			dc_trigger->state = diff->state;
9446 
9447 		if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_ERROR))
9448 			DCstrpool_replace(1, &dc_trigger->error, diff->error);
9449 	}
9450 
9451 	UNLOCK_CACHE;
9452 }
9453 
9454 /******************************************************************************
9455  *                                                                            *
9456  * Function: DCconfig_get_stats                                               *
9457  *                                                                            *
9458  * Purpose: get statistics of the database cache                              *
9459  *                                                                            *
9460  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
9461  *                                                                            *
9462  ******************************************************************************/
DCconfig_get_stats(int request)9463 void	*DCconfig_get_stats(int request)
9464 {
9465 	static zbx_uint64_t	value_uint;
9466 	static double		value_double;
9467 
9468 	switch (request)
9469 	{
9470 		case ZBX_CONFSTATS_BUFFER_TOTAL:
9471 			value_uint = config_mem->orig_size;
9472 			return &value_uint;
9473 		case ZBX_CONFSTATS_BUFFER_USED:
9474 			value_uint = config_mem->orig_size - config_mem->free_size;
9475 			return &value_uint;
9476 		case ZBX_CONFSTATS_BUFFER_FREE:
9477 			value_uint = config_mem->free_size;
9478 			return &value_uint;
9479 		case ZBX_CONFSTATS_BUFFER_PUSED:
9480 			value_double = 100 * (double)(config_mem->orig_size - config_mem->free_size) /
9481 					config_mem->orig_size;
9482 			return &value_double;
9483 		case ZBX_CONFSTATS_BUFFER_PFREE:
9484 			value_double = 100 * (double)config_mem->free_size / config_mem->orig_size;
9485 			return &value_double;
9486 		default:
9487 			return NULL;
9488 	}
9489 }
9490 
DCget_proxy(DC_PROXY * dst_proxy,const ZBX_DC_PROXY * src_proxy)9491 static void	DCget_proxy(DC_PROXY *dst_proxy, const ZBX_DC_PROXY *src_proxy)
9492 {
9493 	const ZBX_DC_HOST	*host;
9494 	ZBX_DC_INTERFACE_HT	*interface_ht, interface_ht_local;
9495 
9496 	dst_proxy->hostid = src_proxy->hostid;
9497 	dst_proxy->proxy_config_nextcheck = src_proxy->proxy_config_nextcheck;
9498 	dst_proxy->proxy_data_nextcheck = src_proxy->proxy_data_nextcheck;
9499 	dst_proxy->proxy_tasks_nextcheck = src_proxy->proxy_tasks_nextcheck;
9500 	dst_proxy->last_cfg_error_time = src_proxy->last_cfg_error_time;
9501 	dst_proxy->version = src_proxy->version;
9502 	dst_proxy->lastaccess = src_proxy->lastaccess;
9503 	dst_proxy->auto_compress = src_proxy->auto_compress;
9504 	dst_proxy->last_version_error_time = src_proxy->last_version_error_time;
9505 
9506 	if (NULL != (host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &src_proxy->hostid)))
9507 	{
9508 		strscpy(dst_proxy->host, host->host);
9509 		strscpy(dst_proxy->proxy_address, src_proxy->proxy_address);
9510 
9511 		dst_proxy->tls_connect = host->tls_connect;
9512 		dst_proxy->tls_accept = host->tls_accept;
9513 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
9514 		strscpy(dst_proxy->tls_issuer, host->tls_issuer);
9515 		strscpy(dst_proxy->tls_subject, host->tls_subject);
9516 
9517 		if (NULL == host->tls_dc_psk)
9518 		{
9519 			*dst_proxy->tls_psk_identity = '\0';
9520 			*dst_proxy->tls_psk = '\0';
9521 		}
9522 		else
9523 		{
9524 			strscpy(dst_proxy->tls_psk_identity, host->tls_dc_psk->tls_psk_identity);
9525 			strscpy(dst_proxy->tls_psk, host->tls_dc_psk->tls_psk);
9526 		}
9527 #endif
9528 	}
9529 	else
9530 	{
9531 		/* DCget_proxy() is called only from DCconfig_get_proxypoller_hosts(), which is called only from */
9532 		/* process_proxy(). So, this branch should never happen. */
9533 		*dst_proxy->host = '\0';
9534 		*dst_proxy->proxy_address = '\0';
9535 		dst_proxy->tls_connect = ZBX_TCP_SEC_TLS_PSK;	/* set PSK to deliberately fail in this case */
9536 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
9537 		*dst_proxy->tls_psk_identity = '\0';
9538 		*dst_proxy->tls_psk = '\0';
9539 #endif
9540 		THIS_SHOULD_NEVER_HAPPEN;
9541 	}
9542 
9543 	interface_ht_local.hostid = src_proxy->hostid;
9544 	interface_ht_local.type = INTERFACE_TYPE_UNKNOWN;
9545 
9546 	if (NULL != (interface_ht = (ZBX_DC_INTERFACE_HT *)zbx_hashset_search(&config->interfaces_ht, &interface_ht_local)))
9547 	{
9548 		const ZBX_DC_INTERFACE	*interface = interface_ht->interface_ptr;
9549 
9550 		strscpy(dst_proxy->addr_orig, interface->useip ? interface->ip : interface->dns);
9551 		strscpy(dst_proxy->port_orig, interface->port);
9552 	}
9553 	else
9554 	{
9555 		*dst_proxy->addr_orig = '\0';
9556 		*dst_proxy->port_orig = '\0';
9557 	}
9558 
9559 	dst_proxy->addr = NULL;
9560 	dst_proxy->port = 0;
9561 }
9562 
DCconfig_get_last_sync_time(void)9563 int	DCconfig_get_last_sync_time(void)
9564 {
9565 	return config->sync_ts;
9566 }
9567 
DCconfig_wait_sync(void)9568 void	DCconfig_wait_sync(void)
9569 {
9570 	struct timespec	ts = {0, 1e8};
9571 
9572 	while (0 == config->sync_ts)
9573 		nanosleep(&ts, NULL);
9574 }
9575 
9576 /******************************************************************************
9577  *                                                                            *
9578  * Function: DCconfig_get_proxypoller_hosts                                   *
9579  *                                                                            *
9580  * Purpose: Get array of proxies for proxy poller                             *
9581  *                                                                            *
9582  * Parameters: hosts - [OUT] array of hosts                                   *
9583  *             max_hosts - [IN] elements in hosts array                       *
9584  *                                                                            *
9585  * Return value: number of proxies in hosts array                             *
9586  *                                                                            *
9587  * Author: Alexander Vladishev                                                *
9588  *                                                                            *
9589  * Comments: Proxies leave the queue only through this function. Pollers must *
9590  *           always return the proxies they have taken using DCrequeue_proxy. *
9591  *                                                                            *
9592  ******************************************************************************/
DCconfig_get_proxypoller_hosts(DC_PROXY * proxies,int max_hosts)9593 int	DCconfig_get_proxypoller_hosts(DC_PROXY *proxies, int max_hosts)
9594 {
9595 	int			now, num = 0;
9596 	zbx_binary_heap_t	*queue;
9597 
9598 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
9599 
9600 	now = time(NULL);
9601 
9602 	queue = &config->pqueue;
9603 
9604 	WRLOCK_CACHE;
9605 
9606 	while (num < max_hosts && FAIL == zbx_binary_heap_empty(queue))
9607 	{
9608 		const zbx_binary_heap_elem_t	*min;
9609 		ZBX_DC_PROXY			*dc_proxy;
9610 
9611 		min = zbx_binary_heap_find_min(queue);
9612 		dc_proxy = (ZBX_DC_PROXY *)min->data;
9613 
9614 		if (dc_proxy->nextcheck > now)
9615 			break;
9616 
9617 		zbx_binary_heap_remove_min(queue);
9618 		dc_proxy->location = ZBX_LOC_POLLER;
9619 
9620 		DCget_proxy(&proxies[num], dc_proxy);
9621 		num++;
9622 	}
9623 
9624 	UNLOCK_CACHE;
9625 
9626 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, num);
9627 
9628 	return num;
9629 }
9630 
9631 /******************************************************************************
9632  *                                                                            *
9633  * Function: DCconfig_get_proxypoller_nextcheck                               *
9634  *                                                                            *
9635  * Purpose: Get nextcheck for passive proxies                                 *
9636  *                                                                            *
9637  * Return value: nextcheck or FAIL if no passive proxies in queue             *
9638  *                                                                            *
9639  * Author: Alexander Vladishev                                                *
9640  *                                                                            *
9641  ******************************************************************************/
DCconfig_get_proxypoller_nextcheck(void)9642 int	DCconfig_get_proxypoller_nextcheck(void)
9643 {
9644 	int			nextcheck;
9645 	zbx_binary_heap_t	*queue;
9646 
9647 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
9648 
9649 	queue = &config->pqueue;
9650 
9651 	RDLOCK_CACHE;
9652 
9653 	if (FAIL == zbx_binary_heap_empty(queue))
9654 	{
9655 		const zbx_binary_heap_elem_t	*min;
9656 		const ZBX_DC_PROXY		*dc_proxy;
9657 
9658 		min = zbx_binary_heap_find_min(queue);
9659 		dc_proxy = (const ZBX_DC_PROXY *)min->data;
9660 
9661 		nextcheck = dc_proxy->nextcheck;
9662 	}
9663 	else
9664 		nextcheck = FAIL;
9665 
9666 	UNLOCK_CACHE;
9667 
9668 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, nextcheck);
9669 
9670 	return nextcheck;
9671 }
9672 
DCrequeue_proxy(zbx_uint64_t hostid,unsigned char update_nextcheck,int proxy_conn_err)9673 void	DCrequeue_proxy(zbx_uint64_t hostid, unsigned char update_nextcheck, int proxy_conn_err)
9674 {
9675 	time_t		now;
9676 	ZBX_DC_HOST	*dc_host;
9677 	ZBX_DC_PROXY	*dc_proxy;
9678 
9679 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() update_nextcheck:%d", __func__, (int)update_nextcheck);
9680 
9681 	now = time(NULL);
9682 
9683 	WRLOCK_CACHE;
9684 
9685 	if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)) &&
9686 			NULL != (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
9687 	{
9688 		if (ZBX_LOC_POLLER == dc_proxy->location)
9689 			dc_proxy->location = ZBX_LOC_NOWHERE;
9690 
9691 		/* set or clear passive proxy misconfiguration error timestamp */
9692 		if (SUCCEED == proxy_conn_err)
9693 			dc_proxy->last_cfg_error_time = 0;
9694 		else if (CONFIG_ERROR == proxy_conn_err)
9695 			dc_proxy->last_cfg_error_time = (int)now;
9696 
9697 		if (HOST_STATUS_PROXY_PASSIVE == dc_host->status)
9698 		{
9699 			if (0 != (update_nextcheck & ZBX_PROXY_CONFIG_NEXTCHECK))
9700 			{
9701 				dc_proxy->proxy_config_nextcheck = (int)calculate_proxy_nextcheck(
9702 						hostid, CONFIG_PROXYCONFIG_FREQUENCY, now);
9703 			}
9704 
9705 			if (0 != (update_nextcheck & ZBX_PROXY_DATA_NEXTCHECK))
9706 			{
9707 				dc_proxy->proxy_data_nextcheck = (int)calculate_proxy_nextcheck(
9708 						hostid, CONFIG_PROXYDATA_FREQUENCY, now);
9709 			}
9710 			if (0 != (update_nextcheck & ZBX_PROXY_TASKS_NEXTCHECK))
9711 			{
9712 				dc_proxy->proxy_tasks_nextcheck = (int)calculate_proxy_nextcheck(
9713 						hostid, ZBX_TASK_UPDATE_FREQUENCY, now);
9714 			}
9715 
9716 			DCupdate_proxy_queue(dc_proxy);
9717 		}
9718 	}
9719 
9720 	UNLOCK_CACHE;
9721 
9722 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
9723 }
9724 
dc_get_host_macro_value(const ZBX_DC_HMACRO * macro,char ** value)9725 static void	dc_get_host_macro_value(const ZBX_DC_HMACRO *macro, char **value)
9726 {
9727 	if (ZBX_MACRO_ENV_NONSECURE == macro_env && ZBX_MACRO_VALUE_SECRET == macro->type)
9728 		*value = zbx_strdup(*value, ZBX_MACRO_SECRET_MASK);
9729 	else
9730 		*value = zbx_strdup(*value, macro->value);
9731 }
9732 
dc_match_macro_context(const char * context,const char * pattern,unsigned char op)9733 static int	dc_match_macro_context(const char *context, const char *pattern, unsigned char op)
9734 {
9735 	switch (op)
9736 	{
9737 		case CONDITION_OPERATOR_EQUAL:
9738 			return 0 == zbx_strcmp_null(context, pattern) ? SUCCEED : FAIL;
9739 		case CONDITION_OPERATOR_REGEXP:
9740 			if (NULL == context)
9741 				return FAIL;
9742 			return NULL != zbx_regexp_match(context, pattern, NULL) ? SUCCEED : FAIL;
9743 		default:
9744 			THIS_SHOULD_NEVER_HAPPEN;
9745 			return FAIL;
9746 	}
9747 }
9748 
dc_get_host_macro(const zbx_uint64_t * hostids,int host_num,const char * macro,const char * context,char ** value,char ** value_default)9749 static void	dc_get_host_macro(const zbx_uint64_t *hostids, int host_num, const char *macro, const char *context,
9750 		char **value, char **value_default)
9751 {
9752 	int			i, j;
9753 	const ZBX_DC_HMACRO_HM	*hmacro_hm;
9754 	ZBX_DC_HMACRO_HM	hmacro_hm_local;
9755 	const ZBX_DC_HTMPL	*htmpl;
9756 	zbx_vector_uint64_t	templateids;
9757 	const ZBX_DC_HMACRO	*hmacro;
9758 
9759 	if (0 == host_num)
9760 		return;
9761 
9762 	hmacro_hm_local.macro = macro;
9763 
9764 	for (i = 0; i < host_num; i++)
9765 	{
9766 		hmacro_hm_local.hostid = hostids[i];
9767 
9768 		if (NULL != (hmacro_hm = (const ZBX_DC_HMACRO_HM *)zbx_hashset_search(&config->hmacros_hm, &hmacro_hm_local)))
9769 		{
9770 			for (j = 0; j < hmacro_hm->hmacros.values_num; j++)
9771 			{
9772 				hmacro = (const ZBX_DC_HMACRO *)hmacro_hm->hmacros.values[j];
9773 
9774 				if (SUCCEED == dc_match_macro_context(context, hmacro->context, hmacro->context_op))
9775 				{
9776 					dc_get_host_macro_value(hmacro, value);
9777 					return;
9778 				}
9779 			}
9780 			/* Check for the default (without context) macro value. If macro has a value without */
9781 			/* context it will be the first element in the macro index vector.                   */
9782 			hmacro = (const ZBX_DC_HMACRO *)hmacro_hm->hmacros.values[0];
9783 			if (NULL == *value_default && NULL != context && NULL == hmacro->context)
9784 				dc_get_host_macro_value(hmacro, value_default);
9785 		}
9786 	}
9787 
9788 	zbx_vector_uint64_create(&templateids);
9789 	zbx_vector_uint64_reserve(&templateids, 32);
9790 
9791 	for (i = 0; i < host_num; i++)
9792 	{
9793 		if (NULL != (htmpl = (const ZBX_DC_HTMPL *)zbx_hashset_search(&config->htmpls, &hostids[i])))
9794 		{
9795 			for (j = 0; j < htmpl->templateids.values_num; j++)
9796 				zbx_vector_uint64_append(&templateids, htmpl->templateids.values[j]);
9797 		}
9798 	}
9799 
9800 	if (0 != templateids.values_num)
9801 	{
9802 		zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
9803 		dc_get_host_macro(templateids.values, templateids.values_num, macro, context, value, value_default);
9804 	}
9805 
9806 	zbx_vector_uint64_destroy(&templateids);
9807 }
9808 
dc_get_global_macro_value(const ZBX_DC_GMACRO * macro,char ** value)9809 static void	dc_get_global_macro_value(const ZBX_DC_GMACRO *macro, char **value)
9810 {
9811 	if (ZBX_MACRO_ENV_NONSECURE == macro_env && ZBX_MACRO_VALUE_SECRET == macro->type)
9812 		*value = zbx_strdup(*value, ZBX_MACRO_SECRET_MASK);
9813 	else
9814 		*value = zbx_strdup(*value, macro->value);
9815 }
9816 
dc_get_global_macro(const char * macro,const char * context,char ** value,char ** value_default)9817 static void	dc_get_global_macro(const char *macro, const char *context, char **value, char **value_default)
9818 {
9819 	int			i;
9820 	const ZBX_DC_GMACRO_M	*gmacro_m;
9821 	ZBX_DC_GMACRO_M		gmacro_m_local;
9822 	const ZBX_DC_GMACRO	*gmacro;
9823 
9824 	gmacro_m_local.macro = macro;
9825 
9826 	if (NULL != (gmacro_m = (const ZBX_DC_GMACRO_M *)zbx_hashset_search(&config->gmacros_m, &gmacro_m_local)))
9827 	{
9828 		for (i = 0; i < gmacro_m->gmacros.values_num; i++)
9829 		{
9830 			gmacro = (const ZBX_DC_GMACRO *)gmacro_m->gmacros.values[i];
9831 
9832 			if (SUCCEED == dc_match_macro_context(context, gmacro->context, gmacro->context_op))
9833 			{
9834 				dc_get_global_macro_value(gmacro, value);
9835 				break;
9836 			}
9837 		}
9838 
9839 		/* Check for the default (without context) macro value. If macro has a value without */
9840 		/* context it will be the first element in the macro index vector.                   */
9841 		gmacro = (const ZBX_DC_GMACRO *)gmacro_m->gmacros.values[0];
9842 		if (NULL == *value_default && NULL != context && NULL == gmacro->context)
9843 			dc_get_global_macro_value(gmacro, value_default);
9844 	}
9845 }
9846 
dc_get_user_macro(const zbx_uint64_t * hostids,int hostids_num,const char * macro,const char * context,char ** replace_to)9847 static void	dc_get_user_macro(const zbx_uint64_t *hostids, int hostids_num, const char *macro, const char *context,
9848 		char **replace_to)
9849 {
9850 	char	*value = NULL, *value_default = NULL;
9851 
9852 	/* User macros should be expanded according to the following priority: */
9853 	/*                                                                     */
9854 	/*  1) host context macro                                              */
9855 	/*  2) global context macro                                            */
9856 	/*  3) host base (default) macro                                       */
9857 	/*  4) global base (default) macro                                     */
9858 	/*                                                                     */
9859 	/* We try to expand host macros first. If there is no perfect match on */
9860 	/* the host level, we try to expand global macros, passing the default */
9861 	/* macro value found on the host level, if any.                        */
9862 
9863 	dc_get_host_macro(hostids, hostids_num, macro, context, &value, &value_default);
9864 
9865 	if (NULL == value)
9866 		dc_get_global_macro(macro, context, &value, &value_default);
9867 
9868 	if (NULL != value)
9869 	{
9870 		zbx_free(*replace_to);
9871 		*replace_to = value;
9872 
9873 		zbx_free(value_default);
9874 	}
9875 	else if (NULL != value_default)
9876 	{
9877 		zbx_free(*replace_to);
9878 		*replace_to = value_default;
9879 	}
9880 }
9881 
DCget_user_macro(const zbx_uint64_t * hostids,int hostids_num,const char * macro,char ** replace_to)9882 void	DCget_user_macro(const zbx_uint64_t *hostids, int hostids_num, const char *macro, char **replace_to)
9883 {
9884 	char	*name = NULL, *context = NULL;
9885 
9886 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() macro:'%s'", __func__, macro);
9887 
9888 	if (SUCCEED != zbx_user_macro_parse_dyn(macro, &name, &context, NULL, NULL))
9889 		goto out;
9890 
9891 	RDLOCK_CACHE;
9892 
9893 	dc_get_user_macro(hostids, hostids_num, name, context, replace_to);
9894 
9895 	UNLOCK_CACHE;
9896 
9897 	zbx_free(context);
9898 	zbx_free(name);
9899 out:
9900 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
9901 }
9902 
9903 /******************************************************************************
9904  *                                                                            *
9905  * Function: dc_expand_user_macros                                            *
9906  *                                                                            *
9907  * Purpose: expand user macros in the specified text value                    *
9908  * WARNING - DO NOT USE FOR TRIGGERS, for triggers use the dedicated function *
9909  *                                                                            *
9910  * Parameters: text           - [IN] the text value to expand                 *
9911  *             hostids        - [IN] an array of related hostids              *
9912  *             hostids_num    - [IN] the number of hostids                    *
9913  *                                                                            *
9914  * Return value: The text value with expanded user macros. Unknown or invalid *
9915  *               macros will be left unresolved.                              *
9916  *                                                                            *
9917  * Comments: The returned value must be freed by the caller.                  *
9918  *           This function must be used only by configuration syncer          *
9919  *                                                                            *
9920  ******************************************************************************/
dc_expand_user_macros(const char * text,zbx_uint64_t * hostids,int hostids_num)9921 char	*dc_expand_user_macros(const char *text, zbx_uint64_t *hostids, int hostids_num)
9922 {
9923 	zbx_token_t	token;
9924 	int		pos = 0, len, last_pos = 0;
9925 	char		*str = NULL, *name = NULL, *context = NULL, *value = NULL;
9926 	size_t		str_alloc = 0, str_offset = 0;
9927 
9928 	if ('\0' == *text)
9929 		return zbx_strdup(NULL, text);
9930 
9931 	for (; SUCCEED == zbx_token_find(text, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
9932 	{
9933 		if (ZBX_TOKEN_USER_MACRO != token.type)
9934 			continue;
9935 
9936 		if (SUCCEED != zbx_user_macro_parse_dyn(text + token.loc.l, &name, &context, &len, NULL))
9937 			continue;
9938 
9939 		zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, token.loc.l - last_pos);
9940 		dc_get_user_macro(hostids, hostids_num, name, context, &value);
9941 
9942 		if (NULL != value)
9943 		{
9944 			zbx_strcpy_alloc(&str, &str_alloc, &str_offset, value);
9945 			zbx_free(value);
9946 
9947 		}
9948 		else
9949 		{
9950 			zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + token.loc.l,
9951 					token.loc.r - token.loc.l + 1);
9952 		}
9953 
9954 		zbx_free(name);
9955 		zbx_free(context);
9956 
9957 		pos = token.loc.r;
9958 		last_pos = pos + 1;
9959 	}
9960 
9961 	zbx_strcpy_alloc(&str, &str_alloc, &str_offset, text + last_pos);
9962 
9963 	return str;
9964 }
9965 
9966 /******************************************************************************
9967  *                                                                            *
9968  * Function: dc_expand_user_macros_in_expression                              *
9969  *                                                                            *
9970  * Purpose: expand user macros for triggers and calculated items in the       *
9971  *          specified text value and autoquote macros that are not already    *
9972  *          quoted that cannot be casted to a double                          *
9973  *                                                                            *
9974  * Parameters: text           - [IN] the text value to expand                 *
9975  *             hostids        - [IN] an array of related hostids              *
9976  *             hostids_num    - [IN] the number of hostids                    *
9977  *                                                                            *
9978  * Return value: The text value with expanded user macros. Unknown or invalid *
9979  *               macros will be left unresolved.                              *
9980  *                                                                            *
9981  * Comments: The returned value must be freed by the caller.                  *
9982  *                                                                            *
9983  ******************************************************************************/
dc_expand_user_macros_in_expression(const char * text,zbx_uint64_t * hostids,int hostids_num)9984 char	*dc_expand_user_macros_in_expression(const char *text, zbx_uint64_t *hostids, int hostids_num)
9985 {
9986 	zbx_token_t	token;
9987 	int		pos = 0, last_pos = 0, cur_token_inside_quote = 0, prev_token_loc_r = -1, len;
9988 	char		*str = NULL, *name = NULL, *context = NULL, *value = NULL;
9989 	size_t		str_alloc = 0, str_offset = 0, i;
9990 
9991 	if ('\0' == *text)
9992 		return zbx_strdup(NULL, text);
9993 
9994 	for (; SUCCEED == zbx_token_find(text, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
9995 	{
9996 		for (i = prev_token_loc_r + 1; i < token.loc.l; i++)
9997 		{
9998 			switch (text[i])
9999 			{
10000 				case '\\':
10001 					if (0 != cur_token_inside_quote)
10002 						i++;
10003 					break;
10004 				case '"':
10005 					cur_token_inside_quote = !cur_token_inside_quote;
10006 					break;
10007 			}
10008 		}
10009 
10010 		if (ZBX_TOKEN_USER_MACRO != token.type)
10011 		{
10012 			prev_token_loc_r = token.loc.r;
10013 			continue;
10014 		}
10015 
10016 		if (SUCCEED != zbx_user_macro_parse_dyn(text + token.loc.l, &name, &context, &len, NULL))
10017 		{
10018 			prev_token_loc_r = token.loc.r;
10019 			continue;
10020 		}
10021 
10022 		zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + last_pos, token.loc.l - last_pos);
10023 		dc_get_user_macro(hostids, hostids_num, name, context, &value);
10024 
10025 		if (NULL != value)
10026 		{
10027 			size_t	sz;
10028 			char	*tmp;
10029 
10030 			sz = zbx_get_escape_string_len(value, "\"\\");
10031 
10032 			if (0 == cur_token_inside_quote && ZBX_INFINITY == evaluate_string_to_double(value))
10033 			{
10034 				/* autoquote */
10035 				tmp = zbx_malloc(NULL, sz + 3);
10036 				tmp[0] = '\"';
10037 				zbx_escape_string(tmp + 1, sz + 1, value, "\"\\");
10038 				tmp[sz + 1] = '\"';
10039 				tmp[sz + 2] = '\0';
10040 				zbx_free(value);
10041 				value = tmp;
10042 			}
10043 			else
10044 			{
10045 				if (sz != strlen(value))
10046 				{
10047 					tmp = zbx_malloc(NULL, sz + 1);
10048 					zbx_escape_string(tmp, sz + 1, value, "\"\\");
10049 					tmp[sz] = '\0';
10050 					zbx_free(value);
10051 					value = tmp;
10052 				}
10053 			}
10054 		}
10055 
10056 		if (NULL != value)
10057 		{
10058 			zbx_strcpy_alloc(&str, &str_alloc, &str_offset, value);
10059 			zbx_free(value);
10060 		}
10061 		else
10062 		{
10063 			zbx_strncpy_alloc(&str, &str_alloc, &str_offset, text + token.loc.l,
10064 					token.loc.r - token.loc.l + 1);
10065 		}
10066 
10067 		zbx_free(name);
10068 		zbx_free(context);
10069 
10070 		pos = token.loc.r;
10071 		last_pos = pos + 1;
10072 		prev_token_loc_r = token.loc.r;
10073 	}
10074 
10075 	zbx_strcpy_alloc(&str, &str_alloc, &str_offset, text + last_pos);
10076 
10077 	return str;
10078 }
10079 
10080 /******************************************************************************
10081  *                                                                            *
10082  * Function: dc_expression_expand_user_macros                                 *
10083  *                                                                            *
10084  * Purpose: expand user macros in trigger expression                          *
10085  *                                                                            *
10086  * Parameters: expression - [IN] the expression to expand                     *
10087  *             error      - [OUT] the error message                           *
10088  *                                                                            *
10089  * Return value: The expanded expression or NULL in the case of error.        *
10090  *               If NULL is returned the error message is set.                *
10091  *                                                                            *
10092  * Comments: The returned expression must be freed by the caller.             *
10093  *                                                                            *
10094  ******************************************************************************/
dc_expression_expand_user_macros(const char * expression)10095 static char	*dc_expression_expand_user_macros(const char *expression)
10096 {
10097 	zbx_vector_uint64_t	functionids, hostids;
10098 	char			*out;
10099 
10100 	zbx_vector_uint64_create(&functionids);
10101 	zbx_vector_uint64_create(&hostids);
10102 
10103 	get_functionids(&functionids, expression);
10104 	dc_get_hostids_by_functionids(functionids.values, functionids.values_num, &hostids);
10105 
10106 	out = dc_expand_user_macros_in_expression(expression, hostids.values, hostids.values_num);
10107 
10108 	if (NULL != strstr(out, "{$"))
10109 	{
10110 		zabbix_log(LOG_LEVEL_DEBUG, "cannot evaluate expression: invalid macro value");
10111 		zbx_free(out);
10112 	}
10113 
10114 	zbx_vector_uint64_destroy(&hostids);
10115 	zbx_vector_uint64_destroy(&functionids);
10116 
10117 	return out;
10118 }
10119 
10120 /******************************************************************************
10121  *                                                                            *
10122  * Function: DCexpression_expand_user_macros                                  *
10123  *                                                                            *
10124  * Purpose: expand user macros in trigger expression                          *
10125  *                                                                            *
10126  * Parameters: expression - [IN] the expression to expand                     *
10127  *                                                                            *
10128  * Return value: The expanded expression or NULL in the case of error.        *
10129  *               If NULL is returned the error message is set.                *
10130  *                                                                            *
10131  * Comments: The returned expression must be freed by the caller.             *
10132  *           This function is a locking wrapper of                            *
10133  *           dc_expression_expand_user_macros() function for external usage.  *
10134  *                                                                            *
10135  ******************************************************************************/
DCexpression_expand_user_macros(const char * expression)10136 char	*DCexpression_expand_user_macros(const char *expression)
10137 {
10138 	char	*expression_ex;
10139 
10140 	RDLOCK_CACHE;
10141 
10142 	expression_ex = dc_expression_expand_user_macros(expression);
10143 
10144 	UNLOCK_CACHE;
10145 
10146 	return expression_ex;
10147 }
10148 
10149 /******************************************************************************
10150  *                                                                            *
10151  * Function: DCfree_item_queue                                                *
10152  *                                                                            *
10153  * Purpose: frees the item queue data vector created by DCget_item_queue()    *
10154  *                                                                            *
10155  * Parameters: queue - [IN] the item queue data vector to free                *
10156  *                                                                            *
10157  ******************************************************************************/
DCfree_item_queue(zbx_vector_ptr_t * queue)10158 void	DCfree_item_queue(zbx_vector_ptr_t *queue)
10159 {
10160 	int	i;
10161 
10162 	for (i = 0; i < queue->values_num; i++)
10163 		zbx_free(queue->values[i]);
10164 }
10165 
10166 /******************************************************************************
10167  *                                                                            *
10168  * Function: DCget_item_queue                                                 *
10169  *                                                                            *
10170  * Purpose: retrieves vector of delayed items                                 *
10171  *                                                                            *
10172  * Parameters: queue - [OUT] the vector of delayed items (optional)           *
10173  *             from  - [IN] the minimum delay time in seconds (non-negative)  *
10174  *             to    - [IN] the maximum delay time in seconds or              *
10175  *                          ZBX_QUEUE_TO_INFINITY if there is no limit        *
10176  *                                                                            *
10177  * Return value: the number of delayed items                                  *
10178  *                                                                            *
10179  ******************************************************************************/
DCget_item_queue(zbx_vector_ptr_t * queue,int from,int to)10180 int	DCget_item_queue(zbx_vector_ptr_t *queue, int from, int to)
10181 {
10182 	zbx_hashset_iter_t	iter;
10183 	const ZBX_DC_ITEM	*dc_item;
10184 	int			now, nitems = 0, data_expected_from, delay;
10185 	zbx_queue_item_t	*queue_item;
10186 
10187 	now = time(NULL);
10188 
10189 	RDLOCK_CACHE;
10190 
10191 	zbx_hashset_iter_reset(&config->items, &iter);
10192 
10193 	while (NULL != (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_iter_next(&iter)))
10194 	{
10195 		const ZBX_DC_HOST	*dc_host;
10196 
10197 		if (ITEM_STATUS_ACTIVE != dc_item->status)
10198 			continue;
10199 
10200 		if (SUCCEED != zbx_is_counted_in_item_queue(dc_item->type, dc_item->key))
10201 			continue;
10202 
10203 		if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
10204 			continue;
10205 
10206 		if (HOST_STATUS_MONITORED != dc_host->status)
10207 			continue;
10208 
10209 		if (SUCCEED == DCin_maintenance_without_data_collection(dc_host, dc_item))
10210 			continue;
10211 
10212 		switch (dc_item->type)
10213 		{
10214 			case ITEM_TYPE_ZABBIX:
10215 				if (HOST_AVAILABLE_TRUE != dc_host->available)
10216 					continue;
10217 				break;
10218 			case ITEM_TYPE_ZABBIX_ACTIVE:
10219 				if (dc_host->data_expected_from > (data_expected_from = dc_item->data_expected_from))
10220 					data_expected_from = dc_host->data_expected_from;
10221 				if (SUCCEED != zbx_interval_preproc(dc_item->delay, &delay, NULL, NULL))
10222 					continue;
10223 				if (data_expected_from + delay > now)
10224 					continue;
10225 				break;
10226 			case ITEM_TYPE_SNMP:
10227 				if (HOST_AVAILABLE_TRUE != dc_host->snmp_available)
10228 					continue;
10229 				break;
10230 			case ITEM_TYPE_IPMI:
10231 				if (HOST_AVAILABLE_TRUE != dc_host->ipmi_available)
10232 					continue;
10233 				break;
10234 			case ITEM_TYPE_JMX:
10235 				if (HOST_AVAILABLE_TRUE != dc_host->jmx_available)
10236 					continue;
10237 				break;
10238 		}
10239 
10240 		if (now - dc_item->nextcheck < from || (ZBX_QUEUE_TO_INFINITY != to && now - dc_item->nextcheck >= to))
10241 			continue;
10242 
10243 		if (NULL != queue)
10244 		{
10245 			queue_item = (zbx_queue_item_t *)zbx_malloc(NULL, sizeof(zbx_queue_item_t));
10246 			queue_item->itemid = dc_item->itemid;
10247 			queue_item->type = dc_item->type;
10248 			queue_item->nextcheck = dc_item->nextcheck;
10249 			queue_item->proxy_hostid = dc_host->proxy_hostid;
10250 
10251 			zbx_vector_ptr_append(queue, queue_item);
10252 		}
10253 		nitems++;
10254 	}
10255 
10256 	UNLOCK_CACHE;
10257 
10258 	return nitems;
10259 }
10260 
10261 /******************************************************************************
10262  *                                                                            *
10263  * Function: dc_trigger_items_hosts_enabled                                   *
10264  *                                                                            *
10265  * Purpose: check that functionids in trigger (recovery) expression           *
10266  *          correspond to enabled items and hosts                             *
10267  *                                                                            *
10268  * Parameters: expression - [IN] trigger (recovery) expression                *
10269  *                                                                            *
10270  * Return value: SUCCEED - all functionids correspond to enabled items and    *
10271  *                           enabled hosts                                    *
10272  *               FAIL    - at least one item or host is disabled              *
10273  *                                                                            *
10274  ******************************************************************************/
dc_trigger_items_hosts_enabled(const char * expression)10275 static int	dc_trigger_items_hosts_enabled(const char *expression)
10276 {
10277 	zbx_uint64_t		functionid;
10278 	const ZBX_DC_ITEM	*dc_item;
10279 	const ZBX_DC_FUNCTION	*dc_function;
10280 	const ZBX_DC_HOST	*dc_host;
10281 	const char		*p, *q;
10282 
10283 	for (p = expression; '\0' != *p; p++)
10284 	{
10285 		if ('{' != *p)
10286 			continue;
10287 
10288 		if ('$' == p[1])
10289 		{
10290 			int	macro_r, context_l, context_r;
10291 
10292 			if (SUCCEED == zbx_user_macro_parse(p, &macro_r, &context_l, &context_r, NULL))
10293 				p += macro_r;
10294 			else
10295 				p++;
10296 
10297 			continue;
10298 		}
10299 
10300 		if (NULL == (q = strchr(p + 1, '}')))
10301 			return FAIL;
10302 
10303 		if (SUCCEED != is_uint64_n(p + 1, q - p - 1, &functionid))
10304 			continue;
10305 
10306 		if (NULL == (dc_function = (ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionid)) ||
10307 				NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_function->itemid)) ||
10308 				ITEM_STATUS_ACTIVE != dc_item->status ||
10309 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)) ||
10310 				HOST_STATUS_MONITORED != dc_host->status)
10311 		{
10312 			return FAIL;
10313 		}
10314 
10315 		p = q;
10316 	}
10317 
10318 	return SUCCEED;
10319 }
10320 
10321 /******************************************************************************
10322  *                                                                            *
10323  * Function: dc_status_update                                                 *
10324  *                                                                            *
10325  * Purpose: check when status information stored in configuration cache was   *
10326  *          updated last time and update it if necessary                      *
10327  *                                                                            *
10328  * Comments: This function gathers the following information:                 *
10329  *             - number of enabled hosts (total and per proxy)                *
10330  *             - number of disabled hosts (total and per proxy)               *
10331  *             - number of enabled and supported items (total, per host and   *
10332  *                                                                 per proxy) *
10333  *             - number of enabled and not supported items (total, per host   *
10334  *                                                             and per proxy) *
10335  *             - number of disabled items (total and per proxy)               *
10336  *             - number of enabled triggers with value OK                     *
10337  *             - number of enabled triggers with value PROBLEM                *
10338  *             - number of disabled triggers                                  *
10339  *             - required performance (total and per proxy)                   *
10340  *           Gathered information can then be displayed in the frontend (see  *
10341  *           "status.get" request) and used in calculation of zabbix[] items. *
10342  *                                                                            *
10343  * NOTE: Always call this function before accessing information stored in     *
10344  *       config->status as well as host and required performance counters     *
10345  *       stored in elements of config->proxies and item counters in elements  *
10346  *       of config->hosts.                                                    *
10347  *                                                                            *
10348  ******************************************************************************/
dc_status_update(void)10349 static void	dc_status_update(void)
10350 {
10351 #define ZBX_STATUS_LIFETIME	SEC_PER_MIN
10352 
10353 	zbx_hashset_iter_t	iter;
10354 	ZBX_DC_PROXY		*dc_proxy;
10355 	ZBX_DC_HOST		*dc_host, *dc_proxy_host;
10356 	const ZBX_DC_ITEM	*dc_item;
10357 	const ZBX_DC_TRIGGER	*dc_trigger;
10358 
10359 	if (0 != config->status->last_update && config->status->last_update + ZBX_STATUS_LIFETIME > time(NULL))
10360 		return;
10361 
10362 	/* reset global counters */
10363 
10364 	config->status->hosts_monitored = 0;
10365 	config->status->hosts_not_monitored = 0;
10366 	config->status->items_active_normal = 0;
10367 	config->status->items_active_notsupported = 0;
10368 	config->status->items_disabled = 0;
10369 	config->status->triggers_enabled_ok = 0;
10370 	config->status->triggers_enabled_problem = 0;
10371 	config->status->triggers_disabled = 0;
10372 	config->status->required_performance = 0.0;
10373 
10374 	/* loop over proxies to reset per-proxy host and required performance counters */
10375 
10376 	zbx_hashset_iter_reset(&config->proxies, &iter);
10377 
10378 	while (NULL != (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_iter_next(&iter)))
10379 	{
10380 		dc_proxy->hosts_monitored = 0;
10381 		dc_proxy->hosts_not_monitored = 0;
10382 		dc_proxy->required_performance = 0.0;
10383 	}
10384 
10385 	/* loop over hosts */
10386 
10387 	zbx_hashset_iter_reset(&config->hosts, &iter);
10388 
10389 	while (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
10390 	{
10391 		/* reset per-host/per-proxy item counters */
10392 
10393 		dc_host->items_active_normal = 0;
10394 		dc_host->items_active_notsupported = 0;
10395 		dc_host->items_disabled = 0;
10396 
10397 		/* gather per-proxy statistics of enabled and disabled hosts */
10398 		switch (dc_host->status)
10399 		{
10400 			case HOST_STATUS_MONITORED:
10401 				config->status->hosts_monitored++;
10402 				if (0 == dc_host->proxy_hostid)
10403 					break;
10404 				if (NULL == (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->proxy_hostid)))
10405 					break;
10406 				dc_proxy->hosts_monitored++;
10407 				break;
10408 			case HOST_STATUS_NOT_MONITORED:
10409 				config->status->hosts_not_monitored++;
10410 				if (0 == dc_host->proxy_hostid)
10411 					break;
10412 				if (NULL == (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->proxy_hostid)))
10413 					break;
10414 				dc_proxy->hosts_not_monitored++;
10415 				break;
10416 		}
10417 	}
10418 
10419 	/* loop over items to gather per-host and per-proxy statistics */
10420 
10421 	zbx_hashset_iter_reset(&config->items, &iter);
10422 
10423 	while (NULL != (dc_item = (ZBX_DC_ITEM *)zbx_hashset_iter_next(&iter)))
10424 	{
10425 		dc_proxy = NULL;
10426 		dc_proxy_host = NULL;
10427 
10428 		if (ZBX_FLAG_DISCOVERY_NORMAL != dc_item->flags && ZBX_FLAG_DISCOVERY_CREATED != dc_item->flags)
10429 			continue;
10430 
10431 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
10432 			continue;
10433 
10434 		if (0 != dc_host->proxy_hostid)
10435 		{
10436 			dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->proxy_hostid);
10437 			dc_proxy_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_host->proxy_hostid);
10438 		}
10439 
10440 		switch (dc_item->status)
10441 		{
10442 			case ITEM_STATUS_ACTIVE:
10443 				if (HOST_STATUS_MONITORED == dc_host->status)
10444 				{
10445 					int	delay;
10446 
10447 					if (SUCCEED == zbx_interval_preproc(dc_item->delay, &delay, NULL, NULL) &&
10448 							0 != delay)
10449 					{
10450 						config->status->required_performance += 1.0 / delay;
10451 
10452 						if (NULL != dc_proxy)
10453 							dc_proxy->required_performance += 1.0 / delay;
10454 					}
10455 
10456 					switch (dc_item->state)
10457 					{
10458 						case ITEM_STATE_NORMAL:
10459 							config->status->items_active_normal++;
10460 							dc_host->items_active_normal++;
10461 							if (NULL != dc_proxy_host)
10462 								dc_proxy_host->items_active_normal++;
10463 							break;
10464 						case ITEM_STATE_NOTSUPPORTED:
10465 							config->status->items_active_notsupported++;
10466 							dc_host->items_active_notsupported++;
10467 							if (NULL != dc_proxy_host)
10468 								dc_proxy_host->items_active_notsupported++;
10469 							break;
10470 						default:
10471 							THIS_SHOULD_NEVER_HAPPEN;
10472 					}
10473 
10474 					break;
10475 				}
10476 				ZBX_FALLTHROUGH;
10477 			case ITEM_STATUS_DISABLED:
10478 				config->status->items_disabled++;
10479 				if (NULL != dc_proxy_host)
10480 					dc_proxy_host->items_disabled++;
10481 				break;
10482 			default:
10483 				THIS_SHOULD_NEVER_HAPPEN;
10484 		}
10485 	}
10486 
10487 	/* loop over triggers to gather enabled and disabled trigger statistics */
10488 
10489 	zbx_hashset_iter_reset(&config->triggers, &iter);
10490 
10491 	while (NULL != (dc_trigger = (ZBX_DC_TRIGGER *)zbx_hashset_iter_next(&iter)))
10492 	{
10493 		switch (dc_trigger->status)
10494 		{
10495 			case TRIGGER_STATUS_ENABLED:
10496 				if (SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->expression) &&
10497 						(TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION != dc_trigger->recovery_mode ||
10498 						SUCCEED == dc_trigger_items_hosts_enabled(dc_trigger->recovery_expression)))
10499 				{
10500 					switch (dc_trigger->value)
10501 					{
10502 						case TRIGGER_VALUE_OK:
10503 							config->status->triggers_enabled_ok++;
10504 							break;
10505 						case TRIGGER_VALUE_PROBLEM:
10506 							config->status->triggers_enabled_problem++;
10507 							break;
10508 						default:
10509 							THIS_SHOULD_NEVER_HAPPEN;
10510 					}
10511 
10512 					break;
10513 				}
10514 				ZBX_FALLTHROUGH;
10515 			case TRIGGER_STATUS_DISABLED:
10516 				config->status->triggers_disabled++;
10517 				break;
10518 			default:
10519 				THIS_SHOULD_NEVER_HAPPEN;
10520 		}
10521 	}
10522 
10523 	config->status->last_update = time(NULL);
10524 
10525 #undef ZBX_STATUS_LIFETIME
10526 }
10527 
10528 /******************************************************************************
10529  *                                                                            *
10530  * Function: DCget_item_count                                                 *
10531  *                                                                            *
10532  * Purpose: return the number of active items                                 *
10533  *                                                                            *
10534  * Parameters: hostid - [IN] the host id, pass 0 to specify all hosts         *
10535  *                                                                            *
10536  * Return value: the number of active items                                   *
10537  *                                                                            *
10538  ******************************************************************************/
DCget_item_count(zbx_uint64_t hostid)10539 zbx_uint64_t	DCget_item_count(zbx_uint64_t hostid)
10540 {
10541 	zbx_uint64_t		count;
10542 	const ZBX_DC_HOST	*dc_host;
10543 
10544 	WRLOCK_CACHE;
10545 
10546 	dc_status_update();
10547 
10548 	if (0 == hostid)
10549 		count = config->status->items_active_normal + config->status->items_active_notsupported;
10550 	else if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
10551 		count = dc_host->items_active_normal + dc_host->items_active_notsupported;
10552 	else
10553 		count = 0;
10554 
10555 	UNLOCK_CACHE;
10556 
10557 	return count;
10558 }
10559 
10560 /******************************************************************************
10561  *                                                                            *
10562  * Function: DCget_item_unsupported_count                                     *
10563  *                                                                            *
10564  * Purpose: return the number of active unsupported items                     *
10565  *                                                                            *
10566  * Parameters: hostid - [IN] the host id, pass 0 to specify all hosts         *
10567  *                                                                            *
10568  * Return value: the number of active unsupported items                       *
10569  *                                                                            *
10570  ******************************************************************************/
DCget_item_unsupported_count(zbx_uint64_t hostid)10571 zbx_uint64_t	DCget_item_unsupported_count(zbx_uint64_t hostid)
10572 {
10573 	zbx_uint64_t		count;
10574 	const ZBX_DC_HOST	*dc_host;
10575 
10576 	WRLOCK_CACHE;
10577 
10578 	dc_status_update();
10579 
10580 	if (0 == hostid)
10581 		count = config->status->items_active_notsupported;
10582 	else if (NULL != (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
10583 		count = dc_host->items_active_notsupported;
10584 	else
10585 		count = 0;
10586 
10587 	UNLOCK_CACHE;
10588 
10589 	return count;
10590 }
10591 
10592 /******************************************************************************
10593  *                                                                            *
10594  * Function: DCget_trigger_count                                              *
10595  *                                                                            *
10596  * Purpose: count active triggers                                             *
10597  *                                                                            *
10598  ******************************************************************************/
DCget_trigger_count(void)10599 zbx_uint64_t	DCget_trigger_count(void)
10600 {
10601 	zbx_uint64_t	count;
10602 
10603 	WRLOCK_CACHE;
10604 
10605 	dc_status_update();
10606 
10607 	count = config->status->triggers_enabled_ok + config->status->triggers_enabled_problem;
10608 
10609 	UNLOCK_CACHE;
10610 
10611 	return count;
10612 }
10613 
10614 /******************************************************************************
10615  *                                                                            *
10616  * Function: DCget_host_count                                                 *
10617  *                                                                            *
10618  * Purpose: count monitored and not monitored hosts                           *
10619  *                                                                            *
10620  ******************************************************************************/
DCget_host_count(void)10621 zbx_uint64_t	DCget_host_count(void)
10622 {
10623 	zbx_uint64_t	nhosts;
10624 
10625 	WRLOCK_CACHE;
10626 
10627 	dc_status_update();
10628 
10629 	nhosts = config->status->hosts_monitored;
10630 
10631 	UNLOCK_CACHE;
10632 
10633 	return nhosts;
10634 }
10635 
10636 /******************************************************************************
10637  *                                                                            *
10638  * Function: DCget_required_performance                                       *
10639  *                                                                            *
10640  * Return value: the required nvps number                                     *
10641  *                                                                            *
10642  ******************************************************************************/
DCget_required_performance(void)10643 double	DCget_required_performance(void)
10644 {
10645 	double	nvps;
10646 
10647 	WRLOCK_CACHE;
10648 
10649 	dc_status_update();
10650 
10651 	nvps = config->status->required_performance;
10652 
10653 	UNLOCK_CACHE;
10654 
10655 	return nvps;
10656 }
10657 
10658 /******************************************************************************
10659  *                                                                            *
10660  * Function: DCget_count_stats_all                                            *
10661  *                                                                            *
10662  * Purpose: retrieves all internal metrics of the configuration cache         *
10663  *                                                                            *
10664  * Parameters: stats - [OUT] the configuration cache statistics               *
10665  *                                                                            *
10666  ******************************************************************************/
DCget_count_stats_all(zbx_config_cache_info_t * stats)10667 void	DCget_count_stats_all(zbx_config_cache_info_t *stats)
10668 {
10669 	WRLOCK_CACHE;
10670 
10671 	dc_status_update();
10672 
10673 	stats->hosts = config->status->hosts_monitored;
10674 	stats->items = config->status->items_active_normal + config->status->items_active_notsupported;
10675 	stats->items_unsupported = config->status->items_active_notsupported;
10676 	stats->requiredperformance = config->status->required_performance;
10677 
10678 	UNLOCK_CACHE;
10679 }
10680 
proxy_counter_ui64_push(zbx_vector_ptr_t * vector,zbx_uint64_t proxyid,zbx_uint64_t counter)10681 static void	proxy_counter_ui64_push(zbx_vector_ptr_t *vector, zbx_uint64_t proxyid, zbx_uint64_t counter)
10682 {
10683 	zbx_proxy_counter_t	*proxy_counter;
10684 
10685 	proxy_counter = (zbx_proxy_counter_t *)zbx_malloc(NULL, sizeof(zbx_proxy_counter_t));
10686 	proxy_counter->proxyid = proxyid;
10687 	proxy_counter->counter_value.ui64 = counter;
10688 	zbx_vector_ptr_append(vector, proxy_counter);
10689 }
10690 
proxy_counter_dbl_push(zbx_vector_ptr_t * vector,zbx_uint64_t proxyid,double counter)10691 static void	proxy_counter_dbl_push(zbx_vector_ptr_t *vector, zbx_uint64_t proxyid, double counter)
10692 {
10693 	zbx_proxy_counter_t	*proxy_counter;
10694 
10695 	proxy_counter = (zbx_proxy_counter_t *)zbx_malloc(NULL, sizeof(zbx_proxy_counter_t));
10696 	proxy_counter->proxyid = proxyid;
10697 	proxy_counter->counter_value.dbl = counter;
10698 	zbx_vector_ptr_append(vector, proxy_counter);
10699 }
10700 
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)10701 void	DCget_status(zbx_vector_ptr_t *hosts_monitored, zbx_vector_ptr_t *hosts_not_monitored,
10702 		zbx_vector_ptr_t *items_active_normal, zbx_vector_ptr_t *items_active_notsupported,
10703 		zbx_vector_ptr_t *items_disabled, zbx_uint64_t *triggers_enabled_ok,
10704 		zbx_uint64_t *triggers_enabled_problem, zbx_uint64_t *triggers_disabled,
10705 		zbx_vector_ptr_t *required_performance)
10706 {
10707 	zbx_hashset_iter_t	iter;
10708 	const ZBX_DC_PROXY	*dc_proxy;
10709 	const ZBX_DC_HOST	*dc_proxy_host;
10710 
10711 	WRLOCK_CACHE;
10712 
10713 	dc_status_update();
10714 
10715 	proxy_counter_ui64_push(hosts_monitored, 0, config->status->hosts_monitored);
10716 	proxy_counter_ui64_push(hosts_not_monitored, 0, config->status->hosts_not_monitored);
10717 	proxy_counter_ui64_push(items_active_normal, 0, config->status->items_active_normal);
10718 	proxy_counter_ui64_push(items_active_notsupported, 0, config->status->items_active_notsupported);
10719 	proxy_counter_ui64_push(items_disabled, 0, config->status->items_disabled);
10720 	*triggers_enabled_ok = config->status->triggers_enabled_ok;
10721 	*triggers_enabled_problem = config->status->triggers_enabled_problem;
10722 	*triggers_disabled = config->status->triggers_disabled;
10723 	proxy_counter_dbl_push(required_performance, 0, config->status->required_performance);
10724 
10725 	zbx_hashset_iter_reset(&config->proxies, &iter);
10726 
10727 	while (NULL != (dc_proxy = (ZBX_DC_PROXY *)zbx_hashset_iter_next(&iter)))
10728 	{
10729 		proxy_counter_ui64_push(hosts_monitored, dc_proxy->hostid, dc_proxy->hosts_monitored);
10730 		proxy_counter_ui64_push(hosts_not_monitored, dc_proxy->hostid, dc_proxy->hosts_not_monitored);
10731 
10732 		if (NULL != (dc_proxy_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_proxy->hostid)))
10733 		{
10734 			proxy_counter_ui64_push(items_active_normal, dc_proxy->hostid,
10735 					dc_proxy_host->items_active_normal);
10736 			proxy_counter_ui64_push(items_active_notsupported, dc_proxy->hostid,
10737 					dc_proxy_host->items_active_notsupported);
10738 			proxy_counter_ui64_push(items_disabled, dc_proxy->hostid, dc_proxy_host->items_disabled);
10739 		}
10740 
10741 		proxy_counter_dbl_push(required_performance, dc_proxy->hostid, dc_proxy->required_performance);
10742 	}
10743 
10744 	UNLOCK_CACHE;
10745 }
10746 
10747 /******************************************************************************
10748  *                                                                            *
10749  * Function: DCget_expressions_by_names                                       *
10750  *                                                                            *
10751  * Purpose: retrieves global expression data from cache                       *
10752  *                                                                            *
10753  * Parameters: expressions  - [OUT] a vector of expression data pointers      *
10754  *             names        - [IN] a vector containing expression names       *
10755  *             names_num    - [IN] the number of items in names vector        *
10756  *                                                                            *
10757  * Comment: The expressions vector contains allocated data, which must be     *
10758  *          freed afterwards with zbx_regexp_clean_expressions() function.    *
10759  *                                                                            *
10760  ******************************************************************************/
DCget_expressions_by_names(zbx_vector_ptr_t * expressions,const char * const * names,int names_num)10761 void	DCget_expressions_by_names(zbx_vector_ptr_t *expressions, const char * const *names, int names_num)
10762 {
10763 	int			i, iname;
10764 	const ZBX_DC_EXPRESSION	*expression;
10765 	const ZBX_DC_REGEXP	*regexp;
10766 	ZBX_DC_REGEXP		search_regexp;
10767 
10768 	RDLOCK_CACHE;
10769 
10770 	for (iname = 0; iname < names_num; iname++)
10771 	{
10772 		search_regexp.name = names[iname];
10773 
10774 		if (NULL != (regexp = (const ZBX_DC_REGEXP *)zbx_hashset_search(&config->regexps, &search_regexp)))
10775 		{
10776 			for (i = 0; i < regexp->expressionids.values_num; i++)
10777 			{
10778 				zbx_uint64_t		expressionid = regexp->expressionids.values[i];
10779 				zbx_expression_t	*rxp;
10780 
10781 				if (NULL == (expression = (const ZBX_DC_EXPRESSION *)zbx_hashset_search(&config->expressions, &expressionid)))
10782 					continue;
10783 
10784 				rxp = (zbx_expression_t *)zbx_malloc(NULL, sizeof(zbx_expression_t));
10785 				rxp->name = zbx_strdup(NULL, regexp->name);
10786 				rxp->expression = zbx_strdup(NULL, expression->expression);
10787 				rxp->exp_delimiter = expression->delimiter;
10788 				rxp->case_sensitive = expression->case_sensitive;
10789 				rxp->expression_type = expression->type;
10790 
10791 				zbx_vector_ptr_append(expressions, rxp);
10792 			}
10793 		}
10794 	}
10795 
10796 	UNLOCK_CACHE;
10797 }
10798 
10799 /******************************************************************************
10800  *                                                                            *
10801  * Function: DCget_expression                                                 *
10802  *                                                                            *
10803  * Purpose: retrieves regular expression data from cache                      *
10804  *                                                                            *
10805  * Parameters: expressions  - [OUT] a vector of expression data pointers      *
10806  *             name         - [IN] the regular expression name                *
10807  *                                                                            *
10808  * Comment: The expressions vector contains allocated data, which must be     *
10809  *          freed afterwards with zbx_regexp_clean_expressions() function.    *
10810  *                                                                            *
10811  ******************************************************************************/
DCget_expressions_by_name(zbx_vector_ptr_t * expressions,const char * name)10812 void	DCget_expressions_by_name(zbx_vector_ptr_t *expressions, const char *name)
10813 {
10814 	DCget_expressions_by_names(expressions, &name, 1);
10815 }
10816 
10817 /******************************************************************************
10818  *                                                                            *
10819  * Function: DCget_data_expected_from                                         *
10820  *                                                                            *
10821  * Purpose: Returns time since which data is expected for the given item. We  *
10822  *          would not mind not having data for the item before that time, but *
10823  *          since that time we expect data to be coming.                      *
10824  *                                                                            *
10825  * Parameters: itemid  - [IN] the item id                                     *
10826  *             seconds - [OUT] the time data is expected as a Unix timestamp  *
10827  *                                                                            *
10828  ******************************************************************************/
DCget_data_expected_from(zbx_uint64_t itemid,int * seconds)10829 int	DCget_data_expected_from(zbx_uint64_t itemid, int *seconds)
10830 {
10831 	const ZBX_DC_ITEM	*dc_item;
10832 	const ZBX_DC_HOST	*dc_host;
10833 	int			ret = FAIL;
10834 
10835 	RDLOCK_CACHE;
10836 
10837 	if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
10838 		goto unlock;
10839 
10840 	if (ITEM_STATUS_ACTIVE != dc_item->status)
10841 		goto unlock;
10842 
10843 	if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
10844 		goto unlock;
10845 
10846 	if (HOST_STATUS_MONITORED != dc_host->status)
10847 		goto unlock;
10848 
10849 	*seconds = MAX(dc_item->data_expected_from, dc_host->data_expected_from);
10850 
10851 	ret = SUCCEED;
10852 unlock:
10853 	UNLOCK_CACHE;
10854 
10855 	return ret;
10856 }
10857 
10858 /******************************************************************************
10859  *                                                                            *
10860  * Function: dc_get_hostids_by_functionids                                    *
10861  *                                                                            *
10862  * Purpose: get host identifiers for the specified list of functions          *
10863  *                                                                            *
10864  * Parameters: functionids     - [IN] the function ids                        *
10865  *             functionids_num - [IN] the number of function ids              *
10866  *             hostids         - [OUT] the host ids                           *
10867  *                                                                            *
10868  * Comments: this function must be used only by configuration syncer          *
10869  *                                                                            *
10870  ******************************************************************************/
dc_get_hostids_by_functionids(const zbx_uint64_t * functionids,int functionids_num,zbx_vector_uint64_t * hostids)10871 void	dc_get_hostids_by_functionids(const zbx_uint64_t *functionids, int functionids_num,
10872 		zbx_vector_uint64_t *hostids)
10873 {
10874 	const ZBX_DC_FUNCTION	*function;
10875 	const ZBX_DC_ITEM	*item;
10876 	int			i;
10877 
10878 	for (i = 0; i < functionids_num; i++)
10879 	{
10880 		if (NULL == (function = (const ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids[i])))
10881 				continue;
10882 
10883 		if (NULL != (item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &function->itemid)))
10884 			zbx_vector_uint64_append(hostids, item->hostid);
10885 	}
10886 
10887 	zbx_vector_uint64_sort(hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
10888 	zbx_vector_uint64_uniq(hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
10889 }
10890 
10891 /******************************************************************************
10892  *                                                                            *
10893  * Function: DCget_hostids_by_functionids                                     *
10894  *                                                                            *
10895  * Purpose: get function host ids grouped by an object (trigger) id           *
10896  *                                                                            *
10897  * Parameters: functionids - [IN] the function ids                            *
10898  *             hostids     - [OUT] the host ids                               *
10899  *                                                                            *
10900  ******************************************************************************/
DCget_hostids_by_functionids(zbx_vector_uint64_t * functionids,zbx_vector_uint64_t * hostids)10901 void	DCget_hostids_by_functionids(zbx_vector_uint64_t *functionids, zbx_vector_uint64_t *hostids)
10902 {
10903 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
10904 
10905 	RDLOCK_CACHE;
10906 
10907 	dc_get_hostids_by_functionids(functionids->values, functionids->values_num, hostids);
10908 
10909 	UNLOCK_CACHE;
10910 
10911 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s(): found %d hosts", __func__, hostids->values_num);
10912 }
10913 
10914 /******************************************************************************
10915  *                                                                            *
10916  * Function: dc_get_hosts_by_functionids                                      *
10917  *                                                                            *
10918  * Purpose: get hosts for the specified list of functions                     *
10919  *                                                                            *
10920  * Parameters: functionids     - [IN] the function ids                        *
10921  *             functionids_num - [IN] the number of function ids              *
10922  *             hosts           - [OUT] hosts                                  *
10923  *                                                                            *
10924  ******************************************************************************/
dc_get_hosts_by_functionids(const zbx_uint64_t * functionids,int functionids_num,zbx_hashset_t * hosts)10925 static void	dc_get_hosts_by_functionids(const zbx_uint64_t *functionids, int functionids_num, zbx_hashset_t *hosts)
10926 {
10927 	const ZBX_DC_FUNCTION	*dc_function;
10928 	const ZBX_DC_ITEM	*dc_item;
10929 	const ZBX_DC_HOST	*dc_host;
10930 	DC_HOST			host;
10931 	int			i;
10932 
10933 	for (i = 0; i < functionids_num; i++)
10934 	{
10935 		if (NULL == (dc_function = (const ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions, &functionids[i])))
10936 			continue;
10937 
10938 		if (NULL == (dc_item = (const ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &dc_function->itemid)))
10939 			continue;
10940 
10941 		if (NULL == (dc_host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
10942 			continue;
10943 
10944 		DCget_host(&host, dc_host, ZBX_ITEM_GET_ALL);
10945 		zbx_hashset_insert(hosts, &host, sizeof(host));
10946 	}
10947 }
10948 
10949 /******************************************************************************
10950  *                                                                            *
10951  * Function: DCget_hosts_by_functionids                                       *
10952  *                                                                            *
10953  * Purpose: get hosts for the specified list of functions                     *
10954  *                                                                            *
10955  * Parameters: functionids - [IN] the function ids                            *
10956  *             hosts       - [OUT] hosts                                      *
10957  *                                                                            *
10958  ******************************************************************************/
DCget_hosts_by_functionids(const zbx_vector_uint64_t * functionids,zbx_hashset_t * hosts)10959 void	DCget_hosts_by_functionids(const zbx_vector_uint64_t *functionids, zbx_hashset_t *hosts)
10960 {
10961 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
10962 
10963 	RDLOCK_CACHE;
10964 
10965 	dc_get_hosts_by_functionids(functionids->values, functionids->values_num, hosts);
10966 
10967 	UNLOCK_CACHE;
10968 
10969 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s(): found %d hosts", __func__, hosts->num_data);
10970 }
10971 
10972 /******************************************************************************
10973  *                                                                            *
10974  * Function: DCget_internal_action_count                                      *
10975  *                                                                            *
10976  * Purpose: get number of enabled internal actions                            *
10977  *                                                                            *
10978  * Return value: number of enabled internal actions                           *
10979  *                                                                            *
10980  ******************************************************************************/
DCget_internal_action_count(void)10981 unsigned int	DCget_internal_action_count(void)
10982 {
10983 	unsigned int count;
10984 
10985 	RDLOCK_CACHE;
10986 
10987 	count = config->internal_actions;
10988 
10989 	UNLOCK_CACHE;
10990 
10991 	return count;
10992 }
10993 
10994 /******************************************************************************
10995  *                                                                            *
10996  * Function: zbx_config_get                                                   *
10997  *                                                                            *
10998  * Purpose: get global configuration data                                     *
10999  *                                                                            *
11000  * Parameters: cfg   - [OUT] the global configuration data                    *
11001  *             flags - [IN] the flags specifying fields to get,               *
11002  *                          see ZBX_CONFIG_FLAGS_ defines                     *
11003  *                                                                            *
11004  * Comments: It's recommended to cleanup 'cfg' structure after use with       *
11005  *           zbx_config_clean() function even if only simple fields were      *
11006  *           requested.                                                       *
11007  *                                                                            *
11008  ******************************************************************************/
zbx_config_get(zbx_config_t * cfg,zbx_uint64_t flags)11009 void	zbx_config_get(zbx_config_t *cfg, zbx_uint64_t flags)
11010 {
11011 	RDLOCK_CACHE;
11012 
11013 	if (0 != (flags & ZBX_CONFIG_FLAGS_SEVERITY_NAME))
11014 	{
11015 		int	i;
11016 
11017 		cfg->severity_name = (char **)zbx_malloc(NULL, TRIGGER_SEVERITY_COUNT * sizeof(char *));
11018 
11019 		for (i = 0; i < TRIGGER_SEVERITY_COUNT; i++)
11020 			cfg->severity_name[i] = zbx_strdup(NULL, config->config->severity_name[i]);
11021 	}
11022 
11023 	if (0 != (flags & ZBX_CONFIG_FLAGS_DISCOVERY_GROUPID))
11024 		cfg->discovery_groupid = config->config->discovery_groupid;
11025 
11026 	if (0 != (flags & ZBX_CONFIG_FLAGS_DEFAULT_INVENTORY_MODE))
11027 		cfg->default_inventory_mode = config->config->default_inventory_mode;
11028 
11029 	if (0 != (flags & ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED))
11030 		cfg->refresh_unsupported = config->config->refresh_unsupported;
11031 
11032 	if (0 != (flags & ZBX_CONFIG_FLAGS_SNMPTRAP_LOGGING))
11033 		cfg->snmptrap_logging = config->config->snmptrap_logging;
11034 
11035 	if (0 != (flags & ZBX_CONFIG_FLAGS_HOUSEKEEPER))
11036 		cfg->hk = config->config->hk;
11037 
11038 	if (0 != (flags & ZBX_CONFIG_FLAGS_DB_EXTENSION))
11039 	{
11040 		cfg->db.extension = zbx_strdup(NULL, config->config->db.extension);
11041 		cfg->db.history_compression_status = config->config->db.history_compression_status;
11042 		cfg->db.history_compression_availability = config->config->db.history_compression_availability;
11043 		cfg->db.history_compress_older = config->config->db.history_compress_older;
11044 	}
11045 
11046 	if (0 != (flags & ZBX_CONFIG_FLAGS_AUTOREG_TLS_ACCEPT))
11047 		cfg->autoreg_tls_accept = config->config->autoreg_tls_accept;
11048 
11049 	UNLOCK_CACHE;
11050 
11051 	cfg->flags = flags;
11052 }
11053 
11054 /******************************************************************************
11055  *                                                                            *
11056  * Function: zbx_config_get_hk_mode                                           *
11057  *                                                                            *
11058  * Purpose: get housekeeping mode for history and trends tables               *
11059  *                                                                            *
11060  * Parameters: history_mode - [OUT] history housekeeping mode, can be either  *
11061  *                                  disabled, enabled or partitioning         *
11062  *             trends_mode  - [OUT] trends housekeeping mode, can be either   *
11063  *                                  disabled, enabled or partitioning         *
11064  *                                                                            *
11065  ******************************************************************************/
zbx_config_get_hk_mode(unsigned char * history_mode,unsigned char * trends_mode)11066 void	zbx_config_get_hk_mode(unsigned char *history_mode, unsigned char *trends_mode)
11067 {
11068 	RDLOCK_CACHE;
11069 	*history_mode = config->config->hk.history_mode;
11070 	*trends_mode = config->config->hk.trends_mode;
11071 	UNLOCK_CACHE;
11072 }
11073 
11074 /******************************************************************************
11075  *                                                                            *
11076  * Function: zbx_config_clean                                                 *
11077  *                                                                            *
11078  * Purpose: cleans global configuration data structure filled                 *
11079  *          by zbx_config_get() function                                      *
11080  *                                                                            *
11081  * Parameters: cfg   - [IN] the global configuration data                     *
11082  *                                                                            *
11083  ******************************************************************************/
zbx_config_clean(zbx_config_t * cfg)11084 void	zbx_config_clean(zbx_config_t *cfg)
11085 {
11086 	if (0 != (cfg->flags & ZBX_CONFIG_FLAGS_SEVERITY_NAME))
11087 	{
11088 		int	i;
11089 
11090 		for (i = 0; i < TRIGGER_SEVERITY_COUNT; i++)
11091 			zbx_free(cfg->severity_name[i]);
11092 
11093 		zbx_free(cfg->severity_name);
11094 	}
11095 
11096 	if (0 != (cfg->flags & ZBX_CONFIG_FLAGS_DB_EXTENSION))
11097 		zbx_free(cfg->db.extension);
11098 }
11099 
11100 /******************************************************************************
11101  *                                                                            *
11102  * Function: DCreset_hosts_availability                                       *
11103  *                                                                            *
11104  * Purpose: resets host availability for disabled hosts and hosts without     *
11105  *          enabled items for the corresponding interface                     *
11106  *                                                                            *
11107  * Parameters: hosts - [OUT] changed host availability data                   *
11108  *                                                                            *
11109  * Return value: SUCCEED - host availability was reset for at least one host  *
11110  *               FAIL    - no hosts required availability reset               *
11111  *                                                                            *
11112  * Comments: This function resets host availability in configuration cache.   *
11113  *           The caller must perform corresponding database updates based     *
11114  *           on returned host availability reset data. On server the function *
11115  *           skips hosts handled by proxies.                                  *
11116  *                                                                            *
11117  ******************************************************************************/
DCreset_hosts_availability(zbx_vector_ptr_t * hosts)11118 int	DCreset_hosts_availability(zbx_vector_ptr_t *hosts)
11119 {
11120 	ZBX_DC_HOST		*host;
11121 	zbx_hashset_iter_t	iter;
11122 	zbx_host_availability_t	*ha = NULL;
11123 	int			now;
11124 
11125 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
11126 
11127 	now = time(NULL);
11128 
11129 	WRLOCK_CACHE;
11130 
11131 	zbx_hashset_iter_reset(&config->hosts, &iter);
11132 
11133 	while (NULL != (host = (ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
11134 	{
11135 		int	items_num = 0, snmp_items_num = 0, ipmi_items_num = 0, jmx_items_num = 0;
11136 
11137 		/* On server skip hosts handled by proxies. They are handled directly */
11138 		/* when receiving hosts' availability data from proxies.              */
11139 		/* Unless a host was just (re)assigned to a proxy or the proxy has    */
11140 		/* not updated its status during the maximum proxy heartbeat period.  */
11141 		/* In this case reset all interfaces to unknown status.               */
11142 		if (0 == host->reset_availability &&
11143 				0 != (program_type & ZBX_PROGRAM_TYPE_SERVER) && 0 != host->proxy_hostid)
11144 		{
11145 			ZBX_DC_PROXY	*proxy;
11146 
11147 			if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &host->proxy_hostid)))
11148 			{
11149 				/* SEC_PER_MIN is a tolerance interval, it was chosen arbitrarily */
11150 				if (ZBX_PROXY_HEARTBEAT_FREQUENCY_MAX + SEC_PER_MIN >= now - proxy->lastaccess)
11151 					continue;
11152 			}
11153 
11154 			host->reset_availability = 1;
11155 		}
11156 
11157 		if (NULL == ha)
11158 			ha = (zbx_host_availability_t *)zbx_malloc(NULL, sizeof(zbx_host_availability_t));
11159 
11160 		zbx_host_availability_init(ha, host->hostid);
11161 
11162 		if (0 == host->reset_availability)
11163 		{
11164 			items_num = host->items_num;
11165 			snmp_items_num = host->snmp_items_num;
11166 			ipmi_items_num = host->ipmi_items_num;
11167 			jmx_items_num = host->jmx_items_num;
11168 		}
11169 
11170 		if (0 == items_num && HOST_AVAILABLE_UNKNOWN != host->available)
11171 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_ZABBIX], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
11172 
11173 		if (0 == snmp_items_num && HOST_AVAILABLE_UNKNOWN != host->snmp_available)
11174 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_SNMP], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
11175 
11176 		if (0 == ipmi_items_num && HOST_AVAILABLE_UNKNOWN != host->ipmi_available)
11177 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_IPMI], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
11178 
11179 		if (0 == jmx_items_num && HOST_AVAILABLE_UNKNOWN != host->jmx_available)
11180 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_JMX], HOST_AVAILABLE_UNKNOWN, "", 0, 0);
11181 
11182 		if (SUCCEED == zbx_host_availability_is_set(ha))
11183 		{
11184 			if (SUCCEED == DChost_set_availability(host, now, ha))
11185 			{
11186 				zbx_vector_ptr_append(hosts, ha);
11187 				ha = NULL;
11188 			}
11189 			else
11190 				zbx_host_availability_clean(ha);
11191 		}
11192 
11193 		host->reset_availability = 0;
11194 	}
11195 	UNLOCK_CACHE;
11196 
11197 	zbx_free(ha);
11198 
11199 	zbx_vector_ptr_sort(hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
11200 
11201 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() hosts:%d", __func__, hosts->values_num);
11202 
11203 	return 0 == hosts->values_num ? FAIL : SUCCEED;
11204 }
11205 
11206 /******************************************************************************
11207  *                                                                            *
11208  * Function: DCget_hosts_availability                                         *
11209  *                                                                            *
11210  * Purpose: gets availability data for hosts with availability data changed   *
11211  *          in period from last availability update to the specified          *
11212  *          timestamp                                                         *
11213  *                                                                            *
11214  * Parameters: hosts - [OUT] changed host availability data                   *
11215  *             ts    - [OUT] the availability diff timestamp                  *
11216  *                                                                            *
11217  * Return value: SUCCEED - availability was changed for at least one host     *
11218  *               FAIL    - no host availability was changed                   *
11219  *                                                                            *
11220  ******************************************************************************/
DCget_hosts_availability(zbx_vector_ptr_t * hosts,int * ts)11221 int	DCget_hosts_availability(zbx_vector_ptr_t *hosts, int *ts)
11222 {
11223 	const ZBX_DC_HOST	*host;
11224 	zbx_hashset_iter_t	iter;
11225 	zbx_host_availability_t	*ha = NULL;
11226 
11227 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
11228 
11229 	RDLOCK_CACHE;
11230 
11231 	*ts = time(NULL);
11232 
11233 	zbx_hashset_iter_reset(&config->hosts, &iter);
11234 
11235 	while (NULL != (host = (const ZBX_DC_HOST *)zbx_hashset_iter_next(&iter)))
11236 	{
11237 		if (config->availability_diff_ts <= host->availability_ts && host->availability_ts < *ts)
11238 		{
11239 			ha = (zbx_host_availability_t *)zbx_malloc(NULL, sizeof(zbx_host_availability_t));
11240 			zbx_host_availability_init(ha, host->hostid);
11241 
11242 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_ZABBIX], host->available, host->error,
11243 					host->errors_from, host->disable_until);
11244 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_SNMP], host->snmp_available, host->snmp_error,
11245 					host->snmp_errors_from, host->snmp_disable_until);
11246 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_IPMI], host->ipmi_available, host->ipmi_error,
11247 					host->ipmi_errors_from, host->ipmi_disable_until);
11248 			zbx_agent_availability_init(&ha->agents[ZBX_AGENT_JMX], host->jmx_available, host->jmx_error,
11249 					host->jmx_errors_from, host->jmx_disable_until);
11250 
11251 			zbx_vector_ptr_append(hosts, ha);
11252 		}
11253 	}
11254 
11255 	UNLOCK_CACHE;
11256 
11257 	zbx_vector_ptr_sort(hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
11258 
11259 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() hosts:%d", __func__, hosts->values_num);
11260 
11261 	return 0 == hosts->values_num ? FAIL : SUCCEED;
11262 }
11263 
11264 /******************************************************************************
11265  *                                                                            *
11266  * Function: DCtouch_hosts_availability                                       *
11267  *                                                                            *
11268  * Purpose: sets availability timestamp to current time for the specified     *
11269  *          hosts                                                             *
11270  *                                                                            *
11271  * Parameters: hostids - [IN] the host identifiers                            *
11272  *                                                                            *
11273  ******************************************************************************/
DCtouch_hosts_availability(const zbx_vector_uint64_t * hostids)11274 void	DCtouch_hosts_availability(const zbx_vector_uint64_t *hostids)
11275 {
11276 	ZBX_DC_HOST	*dc_host;
11277 	int		i, now;
11278 
11279 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() hostids:%d", __func__, hostids->values_num);
11280 
11281 	now = time(NULL);
11282 
11283 	WRLOCK_CACHE;
11284 
11285 	for (i = 0; i < hostids->values_num; i++)
11286 	{
11287 		if (NULL != (dc_host = zbx_hashset_search(&config->hosts, &hostids->values[i])))
11288 			dc_host->availability_ts = now;
11289 	}
11290 
11291 	UNLOCK_CACHE;
11292 
11293 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
11294 }
11295 
11296 /******************************************************************************
11297  *                                                                            *
11298  * Function: dc_action_copy_conditions                                        *
11299  *                                                                            *
11300  * Purpose: copies configuration cache action conditions to the specified     *
11301  *          vector                                                            *
11302  *                                                                            *
11303  * Parameters: dc_action  - [IN] the source action                            *
11304  *             conditions - [OUT] the conditions vector                       *
11305  *                                                                            *
11306  ******************************************************************************/
dc_action_copy_conditions(const zbx_dc_action_t * dc_action,zbx_vector_ptr_t * conditions)11307 static void	dc_action_copy_conditions(const zbx_dc_action_t *dc_action, zbx_vector_ptr_t *conditions)
11308 {
11309 	int				i;
11310 	zbx_condition_t			*condition;
11311 	zbx_dc_action_condition_t	*dc_condition;
11312 
11313 	zbx_vector_ptr_reserve(conditions, dc_action->conditions.values_num);
11314 
11315 	for (i = 0; i < dc_action->conditions.values_num; i++)
11316 	{
11317 		dc_condition = (zbx_dc_action_condition_t *)dc_action->conditions.values[i];
11318 
11319 		condition = (zbx_condition_t *)zbx_malloc(NULL, sizeof(zbx_condition_t));
11320 
11321 		condition->conditionid = dc_condition->conditionid;
11322 		condition->actionid = dc_action->actionid;
11323 		condition->conditiontype = dc_condition->conditiontype;
11324 		condition->op = dc_condition->op;
11325 		condition->value = zbx_strdup(NULL, dc_condition->value);
11326 		condition->value2 = zbx_strdup(NULL, dc_condition->value2);
11327 		zbx_vector_uint64_create(&condition->eventids);
11328 
11329 		zbx_vector_ptr_append(conditions, condition);
11330 	}
11331 }
11332 
11333 /******************************************************************************
11334  *                                                                            *
11335  * Function: dc_action_eval_create                                            *
11336  *                                                                            *
11337  * Purpose: creates action evaluation data from configuration cache action    *
11338  *                                                                            *
11339  * Parameters: dc_action - [IN] the source action                             *
11340  *                                                                            *
11341  * Return value: the action evaluation data                                   *
11342  *                                                                            *
11343  * Comments: The returned value must be freed with zbx_action_eval_free()     *
11344  *           function later.                                                  *
11345  *                                                                            *
11346  ******************************************************************************/
dc_action_eval_create(const zbx_dc_action_t * dc_action)11347 static zbx_action_eval_t	*dc_action_eval_create(const zbx_dc_action_t *dc_action)
11348 {
11349 	zbx_action_eval_t		*action;
11350 
11351 	action = (zbx_action_eval_t *)zbx_malloc(NULL, sizeof(zbx_action_eval_t));
11352 
11353 	action->actionid = dc_action->actionid;
11354 	action->eventsource = dc_action->eventsource;
11355 	action->evaltype = dc_action->evaltype;
11356 	action->opflags = dc_action->opflags;
11357 	action->formula = zbx_strdup(NULL, dc_action->formula);
11358 	zbx_vector_ptr_create(&action->conditions);
11359 
11360 	dc_action_copy_conditions(dc_action, &action->conditions);
11361 
11362 	return action;
11363 }
11364 
11365 /******************************************************************************
11366  *                                                                            *
11367  * Function: zbx_dc_get_actions_eval                                          *
11368  *                                                                            *
11369  * Purpose: gets action evaluation data                                       *
11370  *                                                                            *
11371  * Parameters: actions         - [OUT] the action evaluation data             *
11372  *             uniq_conditions - [OUT] unique conditions that actions         *
11373  *                                     point to (several sources)             *
11374  *             opflags         - [IN] flags specifying which actions to get   *
11375  *                                    based on their operation classes        *
11376  *                                    (see ZBX_ACTION_OPCLASS_* defines)      *
11377  *                                                                            *
11378  * Comments: The returned actions and conditions must be freed with           *
11379  *           zbx_action_eval_free() function later.                           *
11380  *                                                                            *
11381  ******************************************************************************/
zbx_dc_get_actions_eval(zbx_vector_ptr_t * actions,unsigned char opflags)11382 void	zbx_dc_get_actions_eval(zbx_vector_ptr_t *actions, unsigned char opflags)
11383 {
11384 	const zbx_dc_action_t		*dc_action;
11385 	zbx_hashset_iter_t		iter;
11386 
11387 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
11388 
11389 	RDLOCK_CACHE;
11390 
11391 	zbx_hashset_iter_reset(&config->actions, &iter);
11392 
11393 	while (NULL != (dc_action = (const zbx_dc_action_t *)zbx_hashset_iter_next(&iter)))
11394 	{
11395 		if (0 != (opflags & dc_action->opflags))
11396 			zbx_vector_ptr_append(actions, dc_action_eval_create(dc_action));
11397 	}
11398 
11399 	UNLOCK_CACHE;
11400 
11401 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() actions:%d", __func__, actions->values_num);
11402 }
11403 
11404 /******************************************************************************
11405  *                                                                            *
11406  * Function: zbx_set_availability_update_ts                                   *
11407  *                                                                            *
11408  * Purpose: sets timestamp of the last availability update                    *
11409  *                                                                            *
11410  * Parameter: ts - [IN] the last availability update timestamp                *
11411  *                                                                            *
11412  * Comments: This function is used only by proxies when preparing host        *
11413  *           availability data to be sent to server.                          *
11414  *                                                                            *
11415  ******************************************************************************/
zbx_set_availability_diff_ts(int ts)11416 void	zbx_set_availability_diff_ts(int ts)
11417 {
11418 	/* this data can't be accessed simultaneously from multiple processes - locking is not necessary */
11419 	config->availability_diff_ts = ts;
11420 }
11421 
11422 /******************************************************************************
11423  *                                                                            *
11424  * Function: corr_condition_clean                                             *
11425  *                                                                            *
11426  * Purpose: frees correlation condition                                       *
11427  *                                                                            *
11428  * Parameter: condition - [IN] the condition to free                          *
11429  *                                                                            *
11430  ******************************************************************************/
corr_condition_clean(zbx_corr_condition_t * condition)11431 static void	corr_condition_clean(zbx_corr_condition_t *condition)
11432 {
11433 	switch (condition->type)
11434 	{
11435 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
11436 			/* break; is not missing here */
11437 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
11438 			zbx_free(condition->data.tag.tag);
11439 			break;
11440 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
11441 			zbx_free(condition->data.tag_pair.oldtag);
11442 			zbx_free(condition->data.tag_pair.newtag);
11443 			break;
11444 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
11445 			/* break; is not missing here */
11446 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
11447 			zbx_free(condition->data.tag_value.tag);
11448 			zbx_free(condition->data.tag_value.value);
11449 			break;
11450 	}
11451 }
11452 
11453 /******************************************************************************
11454  *                                                                            *
11455  * Function: dc_correlation_free                                              *
11456  *                                                                            *
11457  * Purpose: frees global correlation rule                                     *
11458  *                                                                            *
11459  * Parameter: condition - [IN] the condition to free                          *
11460  *                                                                            *
11461  ******************************************************************************/
dc_correlation_free(zbx_correlation_t * correlation)11462 static void	dc_correlation_free(zbx_correlation_t *correlation)
11463 {
11464 	zbx_free(correlation->name);
11465 	zbx_free(correlation->formula);
11466 
11467 	zbx_vector_ptr_clear_ext(&correlation->operations, zbx_ptr_free);
11468 	zbx_vector_ptr_destroy(&correlation->operations);
11469 	zbx_vector_ptr_destroy(&correlation->conditions);
11470 
11471 	zbx_free(correlation);
11472 }
11473 
11474 /******************************************************************************
11475  *                                                                            *
11476  * Function: dc_corr_condition_copy                                           *
11477  *                                                                            *
11478  * Purpose: copies cached correlation condition to memory                     *
11479  *                                                                            *
11480  * Parameter: dc_condition - [IN] the condition to copy                       *
11481  *            condition    - [OUT] the destination condition                  *
11482  *                                                                            *
11483  * Return value: The cloned correlation condition.                            *
11484  *                                                                            *
11485  ******************************************************************************/
dc_corr_condition_copy(const zbx_dc_corr_condition_t * dc_condition,zbx_corr_condition_t * condition)11486 static void	dc_corr_condition_copy(const zbx_dc_corr_condition_t *dc_condition, zbx_corr_condition_t *condition)
11487 {
11488 	condition->type = dc_condition->type;
11489 
11490 	switch (condition->type)
11491 	{
11492 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG:
11493 			/* break; is not missing here */
11494 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG:
11495 			condition->data.tag.tag = zbx_strdup(NULL, dc_condition->data.tag.tag);
11496 			break;
11497 		case ZBX_CORR_CONDITION_EVENT_TAG_PAIR:
11498 			condition->data.tag_pair.oldtag = zbx_strdup(NULL, dc_condition->data.tag_pair.oldtag);
11499 			condition->data.tag_pair.newtag = zbx_strdup(NULL, dc_condition->data.tag_pair.newtag);
11500 			break;
11501 		case ZBX_CORR_CONDITION_OLD_EVENT_TAG_VALUE:
11502 			/* break; is not missing here */
11503 		case ZBX_CORR_CONDITION_NEW_EVENT_TAG_VALUE:
11504 			condition->data.tag_value.tag = zbx_strdup(NULL, dc_condition->data.tag_value.tag);
11505 			condition->data.tag_value.value = zbx_strdup(NULL, dc_condition->data.tag_value.value);
11506 			condition->data.tag_value.op = dc_condition->data.tag_value.op;
11507 			break;
11508 		case ZBX_CORR_CONDITION_NEW_EVENT_HOSTGROUP:
11509 			condition->data.group.groupid = dc_condition->data.group.groupid;
11510 			condition->data.group.op = dc_condition->data.group.op;
11511 			break;
11512 	}
11513 }
11514 
11515 /******************************************************************************
11516  *                                                                            *
11517  * Function: zbx_dc_corr_operation_dup                                        *
11518  *                                                                            *
11519  * Purpose: clones cached correlation operation to memory                     *
11520  *                                                                            *
11521  * Parameter: operation - [IN] the operation to clone                         *
11522  *                                                                            *
11523  * Return value: The cloned correlation operation.                            *
11524  *                                                                            *
11525  ******************************************************************************/
zbx_dc_corr_operation_dup(const zbx_dc_corr_operation_t * dc_operation)11526 static zbx_corr_operation_t	*zbx_dc_corr_operation_dup(const zbx_dc_corr_operation_t *dc_operation)
11527 {
11528 	zbx_corr_operation_t	*operation;
11529 
11530 	operation = (zbx_corr_operation_t *)zbx_malloc(NULL, sizeof(zbx_corr_operation_t));
11531 	operation->type = dc_operation->type;
11532 
11533 	return operation;
11534 }
11535 
11536 /******************************************************************************
11537  *                                                                            *
11538  * Function: dc_correlation_formula_dup                                       *
11539  *                                                                            *
11540  * Purpose: clones cached correlation formula, generating it if necessary     *
11541  *                                                                            *
11542  * Parameter: correlation - [IN] the correlation                              *
11543  *                                                                            *
11544  * Return value: The cloned correlation formula.                              *
11545  *                                                                            *
11546  ******************************************************************************/
dc_correlation_formula_dup(const zbx_dc_correlation_t * dc_correlation)11547 static char	*dc_correlation_formula_dup(const zbx_dc_correlation_t *dc_correlation)
11548 {
11549 #define ZBX_OPERATION_TYPE_UNKNOWN	0
11550 #define ZBX_OPERATION_TYPE_OR		1
11551 #define ZBX_OPERATION_TYPE_AND		2
11552 
11553 	char				*formula = NULL;
11554 	const char			*op = NULL;
11555 	size_t				formula_alloc = 0, formula_offset = 0;
11556 	int				i, last_type = -1, last_op = ZBX_OPERATION_TYPE_UNKNOWN;
11557 	const zbx_dc_corr_condition_t	*dc_condition;
11558 	zbx_uint64_t			last_id;
11559 
11560 	if (CONDITION_EVAL_TYPE_EXPRESSION == dc_correlation->evaltype || 0 == dc_correlation->conditions.values_num)
11561 		return zbx_strdup(NULL, dc_correlation->formula);
11562 
11563 	dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[0];
11564 
11565 	switch (dc_correlation->evaltype)
11566 	{
11567 		case CONDITION_EVAL_TYPE_OR:
11568 			op = " or";
11569 			break;
11570 		case CONDITION_EVAL_TYPE_AND:
11571 			op = " and";
11572 			break;
11573 	}
11574 
11575 	if (NULL != op)
11576 	{
11577 		zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "}",
11578 				dc_condition->corr_conditionid);
11579 
11580 		for (i = 1; i < dc_correlation->conditions.values_num; i++)
11581 		{
11582 			dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[i];
11583 
11584 			zbx_strcpy_alloc(&formula, &formula_alloc, &formula_offset, op);
11585 			zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, " {" ZBX_FS_UI64 "}",
11586 					dc_condition->corr_conditionid);
11587 		}
11588 
11589 		return formula;
11590 	}
11591 
11592 	last_id = dc_condition->corr_conditionid;
11593 	last_type = dc_condition->type;
11594 
11595 	for (i = 1; i < dc_correlation->conditions.values_num; i++)
11596 	{
11597 		dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[i];
11598 
11599 		if (last_type == dc_condition->type)
11600 		{
11601 			if (last_op != ZBX_OPERATION_TYPE_OR)
11602 				zbx_chrcpy_alloc(&formula, &formula_alloc, &formula_offset, '(');
11603 
11604 			zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "} or ", last_id);
11605 			last_op = ZBX_OPERATION_TYPE_OR;
11606 		}
11607 		else
11608 		{
11609 			zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "}", last_id);
11610 
11611 			if (last_op == ZBX_OPERATION_TYPE_OR)
11612 				zbx_chrcpy_alloc(&formula, &formula_alloc, &formula_offset, ')');
11613 
11614 			zbx_strcpy_alloc(&formula, &formula_alloc, &formula_offset, " and ");
11615 
11616 			last_op = ZBX_OPERATION_TYPE_AND;
11617 		}
11618 
11619 		last_type = dc_condition->type;
11620 		last_id = dc_condition->corr_conditionid;
11621 	}
11622 
11623 	zbx_snprintf_alloc(&formula, &formula_alloc, &formula_offset, "{" ZBX_FS_UI64 "}", last_id);
11624 
11625 	if (last_op == ZBX_OPERATION_TYPE_OR)
11626 		zbx_chrcpy_alloc(&formula, &formula_alloc, &formula_offset, ')');
11627 
11628 	return formula;
11629 
11630 #undef ZBX_OPERATION_TYPE_UNKNOWN
11631 #undef ZBX_OPERATION_TYPE_OR
11632 #undef ZBX_OPERATION_TYPE_AND
11633 }
11634 
zbx_dc_correlation_rules_init(zbx_correlation_rules_t * rules)11635 void	zbx_dc_correlation_rules_init(zbx_correlation_rules_t *rules)
11636 {
11637 	zbx_vector_ptr_create(&rules->correlations);
11638 	zbx_hashset_create_ext(&rules->conditions, 0, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC,
11639 			(zbx_clean_func_t)corr_condition_clean, ZBX_DEFAULT_MEM_MALLOC_FUNC,
11640 			ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
11641 
11642 	rules->sync_ts = 0;
11643 }
11644 
zbx_dc_correlation_rules_clean(zbx_correlation_rules_t * rules)11645 void	zbx_dc_correlation_rules_clean(zbx_correlation_rules_t *rules)
11646 {
11647 	zbx_vector_ptr_clear_ext(&rules->correlations, (zbx_clean_func_t)dc_correlation_free);
11648 	zbx_hashset_clear(&rules->conditions);
11649 }
11650 
zbx_dc_correlation_rules_free(zbx_correlation_rules_t * rules)11651 void	zbx_dc_correlation_rules_free(zbx_correlation_rules_t *rules)
11652 {
11653 	zbx_dc_correlation_rules_clean(rules);
11654 	zbx_vector_ptr_destroy(&rules->correlations);
11655 	zbx_hashset_destroy(&rules->conditions);
11656 }
11657 
11658 /******************************************************************************
11659  *                                                                            *
11660  * Function: zbx_dc_correlation_get_rules                                     *
11661  *                                                                            *
11662  * Purpose: gets correlation rules from configuration cache                   *
11663  *                                                                            *
11664  * Parameter: rules   - [IN/OUT] the correlation rules                        *
11665  *                                                                            *
11666  ******************************************************************************/
zbx_dc_correlation_rules_get(zbx_correlation_rules_t * rules)11667 void	zbx_dc_correlation_rules_get(zbx_correlation_rules_t *rules)
11668 {
11669 	int				i;
11670 	zbx_hashset_iter_t		iter;
11671 	const zbx_dc_correlation_t	*dc_correlation;
11672 	const zbx_dc_corr_condition_t	*dc_condition;
11673 	zbx_correlation_t		*correlation;
11674 	zbx_corr_condition_t		*condition, condition_local;
11675 
11676 	RDLOCK_CACHE;
11677 
11678 	/* The correlation rules are refreshed only if the sync timestamp   */
11679 	/* does not match current configuration cache sync timestamp. This  */
11680 	/* allows to locally cache the correlation rules.                   */
11681 	if (config->sync_ts == rules->sync_ts)
11682 	{
11683 		UNLOCK_CACHE;
11684 		return;
11685 	}
11686 
11687 	zbx_dc_correlation_rules_clean(rules);
11688 
11689 	zbx_hashset_iter_reset(&config->correlations, &iter);
11690 	while (NULL != (dc_correlation = (const zbx_dc_correlation_t *)zbx_hashset_iter_next(&iter)))
11691 	{
11692 		correlation = (zbx_correlation_t *)zbx_malloc(NULL, sizeof(zbx_correlation_t));
11693 		correlation->correlationid = dc_correlation->correlationid;
11694 		correlation->evaltype = dc_correlation->evaltype;
11695 		correlation->name = zbx_strdup(NULL, dc_correlation->name);
11696 		correlation->formula = dc_correlation_formula_dup(dc_correlation);
11697 		zbx_vector_ptr_create(&correlation->conditions);
11698 		zbx_vector_ptr_create(&correlation->operations);
11699 
11700 		for (i = 0; i < dc_correlation->conditions.values_num; i++)
11701 		{
11702 			dc_condition = (const zbx_dc_corr_condition_t *)dc_correlation->conditions.values[i];
11703 			condition_local.corr_conditionid = dc_condition->corr_conditionid;
11704 			condition = (zbx_corr_condition_t *)zbx_hashset_insert(&rules->conditions, &condition_local, sizeof(condition_local));
11705 			dc_corr_condition_copy(dc_condition, condition);
11706 			zbx_vector_ptr_append(&correlation->conditions, condition);
11707 		}
11708 
11709 		for (i = 0; i < dc_correlation->operations.values_num; i++)
11710 		{
11711 			zbx_vector_ptr_append(&correlation->operations,
11712 					zbx_dc_corr_operation_dup((const zbx_dc_corr_operation_t *)dc_correlation->operations.values[i]));
11713 		}
11714 
11715 		zbx_vector_ptr_append(&rules->correlations, correlation);
11716 	}
11717 
11718 	rules->sync_ts = config->sync_ts;
11719 
11720 	UNLOCK_CACHE;
11721 
11722 	zbx_vector_ptr_sort(&rules->correlations, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
11723 }
11724 
11725 /******************************************************************************
11726  *                                                                            *
11727  * Function: dc_hostgroup_cache_nested_groupids                               *
11728  *                                                                            *
11729  * Purpose: cache nested group identifiers                                    *
11730  *                                                                            *
11731  ******************************************************************************/
dc_hostgroup_cache_nested_groupids(zbx_dc_hostgroup_t * parent_group)11732 void	dc_hostgroup_cache_nested_groupids(zbx_dc_hostgroup_t *parent_group)
11733 {
11734 	zbx_dc_hostgroup_t	*group;
11735 
11736 	if (0 == (parent_group->flags & ZBX_DC_HOSTGROUP_FLAGS_NESTED_GROUPIDS))
11737 	{
11738 		int	index, len;
11739 
11740 		zbx_vector_uint64_create_ext(&parent_group->nested_groupids, __config_mem_malloc_func,
11741 				__config_mem_realloc_func, __config_mem_free_func);
11742 
11743 		index = zbx_vector_ptr_bsearch(&config->hostgroups_name, parent_group, dc_compare_hgroups);
11744 		len = strlen(parent_group->name);
11745 
11746 		while (++index < config->hostgroups_name.values_num)
11747 		{
11748 			group = (zbx_dc_hostgroup_t *)config->hostgroups_name.values[index];
11749 
11750 			if (0 != strncmp(group->name, parent_group->name, len))
11751 				break;
11752 
11753 			if ('\0' == group->name[len] || '/' == group->name[len])
11754 				zbx_vector_uint64_append(&parent_group->nested_groupids, group->groupid);
11755 		}
11756 
11757 		parent_group->flags |= ZBX_DC_HOSTGROUP_FLAGS_NESTED_GROUPIDS;
11758 	}
11759 }
11760 
11761 /******************************************************************************
11762  *                                                                            *
11763  * Function: dc_maintenance_precache_nested_groups                            *
11764  *                                                                            *
11765  * Purpose: pre-caches nested groups for groups used in running maintenances  *
11766  *                                                                            *
11767  ******************************************************************************/
dc_maintenance_precache_nested_groups(void)11768 static void	dc_maintenance_precache_nested_groups(void)
11769 {
11770 	zbx_hashset_iter_t	iter;
11771 	zbx_dc_maintenance_t	*maintenance;
11772 	zbx_vector_uint64_t	groupids;
11773 	int			i;
11774 	zbx_dc_hostgroup_t	*group;
11775 
11776 	if (0 == config->maintenances.num_data)
11777 		return;
11778 
11779 	zbx_vector_uint64_create(&groupids);
11780 	zbx_hashset_iter_reset(&config->maintenances, &iter);
11781 	while (NULL != (maintenance = (zbx_dc_maintenance_t *)zbx_hashset_iter_next(&iter)))
11782 	{
11783 		if (ZBX_MAINTENANCE_RUNNING != maintenance->state)
11784 			continue;
11785 
11786 		zbx_vector_uint64_append_array(&groupids, maintenance->groupids.values,
11787 				maintenance->groupids.values_num);
11788 	}
11789 
11790 	zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
11791 	zbx_vector_uint64_uniq(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
11792 
11793 	for (i = 0; i < groupids.values_num; i++)
11794 	{
11795 		if (NULL != (group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups,
11796 				&groupids.values[i])))
11797 		{
11798 			dc_hostgroup_cache_nested_groupids(group);
11799 		}
11800 	}
11801 
11802 	zbx_vector_uint64_destroy(&groupids);
11803 }
11804 
11805 /******************************************************************************
11806  *                                                                            *
11807  * Function: dc_get_nested_hostgroupids                                       *
11808  *                                                                            *
11809  * Purpose: gets nested group ids for the specified host group                *
11810  *          (including the target group id)                                   *
11811  *                                                                            *
11812  * Parameter: groupid         - [IN] the parent group identifier              *
11813  *            nested_groupids - [OUT] the nested + parent group ids           *
11814  *                                                                            *
11815  ******************************************************************************/
dc_get_nested_hostgroupids(zbx_uint64_t groupid,zbx_vector_uint64_t * nested_groupids)11816 void	dc_get_nested_hostgroupids(zbx_uint64_t groupid, zbx_vector_uint64_t *nested_groupids)
11817 {
11818 	zbx_dc_hostgroup_t	*parent_group;
11819 
11820 	zbx_vector_uint64_append(nested_groupids, groupid);
11821 
11822 	/* The target group id will not be found in the configuration cache if target group was removed */
11823 	/* between call to this function and the configuration cache look-up below. The target group id */
11824 	/* is nevertheless returned so that the SELECT statements of the callers work even if no group  */
11825 	/* was found.                                                                                   */
11826 
11827 	if (NULL != (parent_group = (zbx_dc_hostgroup_t *)zbx_hashset_search(&config->hostgroups, &groupid)))
11828 	{
11829 		dc_hostgroup_cache_nested_groupids(parent_group);
11830 
11831 		if (0 != parent_group->nested_groupids.values_num)
11832 		{
11833 			zbx_vector_uint64_append_array(nested_groupids, parent_group->nested_groupids.values,
11834 					parent_group->nested_groupids.values_num);
11835 		}
11836 	}
11837 }
11838 
11839 /******************************************************************************
11840  *                                                                            *
11841  * Function: zbx_dc_get_nested_hostgroupids                                   *
11842  *                                                                            *
11843  * Purpose: gets nested group ids for the specified host groups               *
11844  *                                                                            *
11845  * Parameter: groupids        - [IN] the parent group identifiers             *
11846  *            groupids_num    - [IN] the number of parent groups              *
11847  *            nested_groupids - [OUT] the nested + parent group ids           *
11848  *                                                                            *
11849  ******************************************************************************/
zbx_dc_get_nested_hostgroupids(zbx_uint64_t * groupids,int groupids_num,zbx_vector_uint64_t * nested_groupids)11850 void	zbx_dc_get_nested_hostgroupids(zbx_uint64_t *groupids, int groupids_num, zbx_vector_uint64_t *nested_groupids)
11851 {
11852 	int	i;
11853 
11854 	WRLOCK_CACHE;
11855 
11856 	for (i = 0; i < groupids_num; i++)
11857 		dc_get_nested_hostgroupids(groupids[i], nested_groupids);
11858 
11859 	UNLOCK_CACHE;
11860 
11861 	zbx_vector_uint64_sort(nested_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
11862 	zbx_vector_uint64_uniq(nested_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
11863 }
11864 
11865 /******************************************************************************
11866  *                                                                            *
11867  * Function: zbx_dc_get_nested_hostgroupids_by_names                          *
11868  *                                                                            *
11869  * Purpose: gets nested group ids for the specified host groups               *
11870  *                                                                            *
11871  * Parameter: groups          - [IN] the parent group names                   *
11872  *            nested_groupids - [OUT] the nested + parent group ids           *
11873  *                                                                            *
11874  ******************************************************************************/
zbx_dc_get_nested_hostgroupids_by_names(zbx_vector_str_t * groups,zbx_vector_uint64_t * nested_groupids)11875 void	zbx_dc_get_nested_hostgroupids_by_names(zbx_vector_str_t *groups, zbx_vector_uint64_t *nested_groupids)
11876 {
11877 	int	i, index;
11878 
11879 	WRLOCK_CACHE;
11880 
11881 	for (i = 0; i < groups->values_num; i++)
11882 	{
11883 		zbx_dc_hostgroup_t	group_local, *group;
11884 
11885 		group_local.name = groups->values[i];
11886 
11887 		if (FAIL != (index = zbx_vector_ptr_bsearch(&config->hostgroups_name, &group_local,
11888 				dc_compare_hgroups)))
11889 		{
11890 			group = (zbx_dc_hostgroup_t *)config->hostgroups_name.values[index];
11891 			dc_get_nested_hostgroupids(group->groupid, nested_groupids);
11892 		}
11893 	}
11894 
11895 	UNLOCK_CACHE;
11896 
11897 	zbx_vector_uint64_sort(nested_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
11898 	zbx_vector_uint64_uniq(nested_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
11899 }
11900 
11901 /******************************************************************************
11902  *                                                                            *
11903  * Function: zbx_dc_get_active_proxy_by_name                                  *
11904  *                                                                            *
11905  * Purpose: gets active proxy data by its name from configuration cache       *
11906  *                                                                            *
11907  * Parameters:                                                                *
11908  *     name  - [IN] the proxy name                                            *
11909  *     proxy - [OUT] the proxy data                                           *
11910  *     error - [OUT] error message                                            *
11911  *                                                                            *
11912  * Return value:                                                              *
11913  *     SUCCEED - proxy data were retrieved successfully                       *
11914  *     FAIL    - failed to retrieve proxy data, error message is set          *
11915  *                                                                            *
11916  ******************************************************************************/
zbx_dc_get_active_proxy_by_name(const char * name,DC_PROXY * proxy,char ** error)11917 int	zbx_dc_get_active_proxy_by_name(const char *name, DC_PROXY *proxy, char **error)
11918 {
11919 	int			ret = FAIL;
11920 	const ZBX_DC_HOST	*dc_host;
11921 	const ZBX_DC_PROXY	*dc_proxy;
11922 
11923 	RDLOCK_CACHE;
11924 
11925 	if (NULL == (dc_host = DCfind_proxy(name)))
11926 	{
11927 		*error = zbx_dsprintf(*error, "proxy \"%s\" not found", name);
11928 		goto out;
11929 	}
11930 
11931 	if (HOST_STATUS_PROXY_ACTIVE != dc_host->status)
11932 	{
11933 		*error = zbx_dsprintf(*error, "proxy \"%s\" is configured for passive mode", name);
11934 		goto out;
11935 	}
11936 
11937 	if (NULL == (dc_proxy = (const ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &dc_host->hostid)))
11938 	{
11939 		*error = zbx_dsprintf(*error, "proxy \"%s\" not found in configuration cache", name);
11940 		goto out;
11941 	}
11942 
11943 	DCget_proxy(proxy, dc_proxy);
11944 	ret = SUCCEED;
11945 out:
11946 	UNLOCK_CACHE;
11947 
11948 	return ret;
11949 }
11950 
11951 /******************************************************************************
11952  *                                                                            *
11953  * Function: zbx_dc_items_update_nextcheck                                    *
11954  *                                                                            *
11955  * Purpose: updates item nextcheck values in configuration cache              *
11956  *                                                                            *
11957  * Parameters: items      - [IN] the items to update                          *
11958  *             values     - [IN] the items values containing new properties   *
11959  *             errcodes   - [IN] item error codes. Update only items with     *
11960  *                               SUCCEED code                                 *
11961  *             values_num - [IN] the number of elements in items,values and   *
11962  *                               errcodes arrays                              *
11963  *                                                                            *
11964  ******************************************************************************/
zbx_dc_items_update_nextcheck(DC_ITEM * items,zbx_agent_value_t * values,int * errcodes,size_t values_num)11965 void	zbx_dc_items_update_nextcheck(DC_ITEM *items, zbx_agent_value_t *values, int *errcodes, size_t values_num)
11966 {
11967 	size_t		i;
11968 	ZBX_DC_ITEM	*dc_item;
11969 	ZBX_DC_HOST	*dc_host;
11970 
11971 	RDLOCK_CACHE;
11972 
11973 	for (i = 0; i < values_num; i++)
11974 	{
11975 		if (FAIL == errcodes[i])
11976 			continue;
11977 
11978 		/* update nextcheck for items that are counted in queue for monitoring purposes */
11979 		if (FAIL == zbx_is_counted_in_item_queue(items[i].type, items[i].key_orig))
11980 			continue;
11981 
11982 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &items[i].itemid)))
11983 			continue;
11984 
11985 		if (ITEM_STATUS_ACTIVE != dc_item->status)
11986 			continue;
11987 
11988 		if (NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
11989 			continue;
11990 
11991 		if (HOST_STATUS_MONITORED != dc_host->status)
11992 			continue;
11993 
11994 		if (ZBX_LOC_NOWHERE != dc_item->location)
11995 			continue;
11996 
11997 		DCitem_nextcheck_update(dc_item, dc_host, items[i].state, ZBX_ITEM_COLLECTED, values[i].ts.sec, NULL);
11998 	}
11999 
12000 	UNLOCK_CACHE;
12001 }
12002 
12003 /******************************************************************************
12004  *                                                                            *
12005  * Function: zbx_dc_get_host_interfaces                                       *
12006  *                                                                            *
12007  * Purpose: get data of all network interfaces for a host in configuration    *
12008  *          cache                                                             *
12009  *                                                                            *
12010  * Parameter: hostid     - [IN] the host identifier                           *
12011  *            interfaces - [OUT] array with interface data                    *
12012  *            n          - [OUT] number of allocated 'interfaces' elements    *
12013  *                                                                            *
12014  * Return value: SUCCEED - interface data retrieved successfully              *
12015  *               FAIL    - host not found                                     *
12016  *                                                                            *
12017  * Comments: if host is found but has no interfaces (should not happen) this  *
12018  *           function sets 'n' to 0 and no memory is allocated for            *
12019  *           'interfaces'. It is a caller responsibility to deallocate        *
12020  *           memory of 'interfaces' and its components.                       *
12021  *                                                                            *
12022  ******************************************************************************/
zbx_dc_get_host_interfaces(zbx_uint64_t hostid,DC_INTERFACE2 ** interfaces,int * n)12023 int	zbx_dc_get_host_interfaces(zbx_uint64_t hostid, DC_INTERFACE2 **interfaces, int *n)
12024 {
12025 	const ZBX_DC_HOST	*host;
12026 	int			i, ret = FAIL;
12027 
12028 	if (0 == hostid)
12029 		return FAIL;
12030 
12031 	RDLOCK_CACHE;
12032 
12033 	/* find host entry in 'config->hosts' hashset */
12034 
12035 	if (NULL == (host = (const ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &hostid)))
12036 		goto unlock;
12037 
12038 	/* allocate memory for results */
12039 
12040 	if (0 < (*n = host->interfaces_v.values_num))
12041 		*interfaces = (DC_INTERFACE2 *)zbx_malloc(NULL, sizeof(DC_INTERFACE2) * (size_t)*n);
12042 
12043 	/* copy data about all host interfaces */
12044 
12045 	for (i = 0; i < *n; i++)
12046 	{
12047 		const ZBX_DC_INTERFACE	*src = (const ZBX_DC_INTERFACE *)host->interfaces_v.values[i];
12048 		DC_INTERFACE2		*dst = *interfaces + i;
12049 
12050 		dst->interfaceid = src->interfaceid;
12051 		dst->type = src->type;
12052 		dst->main = src->main;
12053 		dst->useip = src->useip;
12054 		strscpy(dst->ip_orig, src->ip);
12055 		strscpy(dst->dns_orig, src->dns);
12056 		strscpy(dst->port_orig, src->port);
12057 		dst->addr = (1 == src->useip ? dst->ip_orig : dst->dns_orig);
12058 
12059 		if (INTERFACE_TYPE_SNMP == dst->type)
12060 		{
12061 			ZBX_DC_SNMPINTERFACE *snmp;
12062 
12063 			if (NULL == (snmp = (ZBX_DC_SNMPINTERFACE *)zbx_hashset_search(&config->interfaces_snmp,
12064 					&dst->interfaceid)))
12065 			{
12066 				zbx_free(*interfaces);
12067 				goto unlock;
12068 			}
12069 
12070 			dst->bulk = snmp->bulk;
12071 			dst->snmp_version= snmp->version;
12072 		}
12073 	}
12074 
12075 	ret = SUCCEED;
12076 unlock:
12077 	UNLOCK_CACHE;
12078 
12079 	return ret;
12080 }
12081 
12082 /******************************************************************************
12083  *                                                                            *
12084  * Function: DCconfig_items_apply_changes                                     *
12085  *                                                                            *
12086  * Purpose: apply item state, error, mtime, lastlogsize changes to            *
12087  *          configuration cache                                               *
12088  *                                                                            *
12089  ******************************************************************************/
DCconfig_items_apply_changes(const zbx_vector_ptr_t * item_diff)12090 void	DCconfig_items_apply_changes(const zbx_vector_ptr_t *item_diff)
12091 {
12092 	int			i;
12093 	const zbx_item_diff_t	*diff;
12094 	ZBX_DC_ITEM		*dc_item;
12095 
12096 	if (0 == item_diff->values_num)
12097 		return;
12098 
12099 	WRLOCK_CACHE;
12100 
12101 	for (i = 0; i < item_diff->values_num; i++)
12102 	{
12103 		diff = (const zbx_item_diff_t *)item_diff->values[i];
12104 
12105 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &diff->itemid)))
12106 			continue;
12107 
12108 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_LASTLOGSIZE & diff->flags))
12109 			dc_item->lastlogsize = diff->lastlogsize;
12110 
12111 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_MTIME & diff->flags))
12112 			dc_item->mtime = diff->mtime;
12113 
12114 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_ERROR & diff->flags))
12115 			DCstrpool_replace(1, &dc_item->error, diff->error);
12116 
12117 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_STATE & diff->flags))
12118 			dc_item->state = diff->state;
12119 
12120 		if (0 != (ZBX_FLAGS_ITEM_DIFF_UPDATE_LASTCLOCK & diff->flags))
12121 			dc_item->lastclock = diff->lastclock;
12122 	}
12123 
12124 	UNLOCK_CACHE;
12125 }
12126 
12127 /******************************************************************************
12128  *                                                                            *
12129  * Function: DCconfig_update_inventory_values                                 *
12130  *                                                                            *
12131  * Purpose: update automatic inventory in configuration cache                 *
12132  *                                                                            *
12133  ******************************************************************************/
DCconfig_update_inventory_values(const zbx_vector_ptr_t * inventory_values)12134 void	DCconfig_update_inventory_values(const zbx_vector_ptr_t *inventory_values)
12135 {
12136 	ZBX_DC_HOST_INVENTORY	*host_inventory = NULL;
12137 	int			i;
12138 
12139 	WRLOCK_CACHE;
12140 
12141 	for (i = 0; i < inventory_values->values_num; i++)
12142 	{
12143 		const zbx_inventory_value_t	*inventory_value = (zbx_inventory_value_t *)inventory_values->values[i];
12144 		const char			**value;
12145 
12146 		if (NULL == host_inventory || inventory_value->hostid != host_inventory->hostid)
12147 		{
12148 			host_inventory = (ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories_auto, &inventory_value->hostid);
12149 
12150 			if (NULL == host_inventory)
12151 				continue;
12152 		}
12153 
12154 		value = &host_inventory->values[inventory_value->idx];
12155 
12156 		DCstrpool_replace((NULL != *value ? 1 : 0), value, inventory_value->value);
12157 	}
12158 
12159 	UNLOCK_CACHE;
12160 }
12161 
12162 /******************************************************************************
12163  *                                                                            *
12164  * Function: dc_get_host_inventory_value_by_hostid                            *
12165  *                                                                            *
12166  * Purpose: find inventory value in automatically populated cache, if not     *
12167  *          found then look in main inventory cache                           *
12168  *                                                                            *
12169  * Comments: This function must be called inside configuration cache read     *
12170  *           (or write) lock.                                                 *
12171  *                                                                            *
12172  ******************************************************************************/
dc_get_host_inventory_value_by_hostid(zbx_uint64_t hostid,char ** replace_to,int value_idx)12173 static int	dc_get_host_inventory_value_by_hostid(zbx_uint64_t hostid, char **replace_to, int value_idx)
12174 {
12175 	const ZBX_DC_HOST_INVENTORY	*dc_inventory;
12176 
12177 	if (NULL != (dc_inventory = (const ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories_auto,
12178 			&hostid)) && NULL != dc_inventory->values[value_idx])
12179 	{
12180 		*replace_to = zbx_strdup(*replace_to, dc_inventory->values[value_idx]);
12181 		return SUCCEED;
12182 	}
12183 
12184 	if (NULL != (dc_inventory = (const ZBX_DC_HOST_INVENTORY *)zbx_hashset_search(&config->host_inventories,
12185 			&hostid)))
12186 	{
12187 		*replace_to = zbx_strdup(*replace_to, dc_inventory->values[value_idx]);
12188 		return SUCCEED;
12189 	}
12190 
12191 	return FAIL;
12192 }
12193 
12194 /******************************************************************************
12195  *                                                                            *
12196  * Function: DCget_host_inventory_value_by_itemid                             *
12197  *                                                                            *
12198  * Purpose: find inventory value in automatically populated cache, if not     *
12199  *          found then look in main inventory cache                           *
12200  *                                                                            *
12201  ******************************************************************************/
DCget_host_inventory_value_by_itemid(zbx_uint64_t itemid,char ** replace_to,int value_idx)12202 int	DCget_host_inventory_value_by_itemid(zbx_uint64_t itemid, char **replace_to, int value_idx)
12203 {
12204 	const ZBX_DC_ITEM	*dc_item;
12205 	int			ret = FAIL;
12206 
12207 	RDLOCK_CACHE;
12208 
12209 	if (NULL != (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
12210 		ret = dc_get_host_inventory_value_by_hostid(dc_item->hostid, replace_to, value_idx);
12211 
12212 	UNLOCK_CACHE;
12213 
12214 	return ret;
12215 }
12216 
12217 /******************************************************************************
12218  *                                                                            *
12219  * Function: DCget_host_inventory_value_by_hostid                             *
12220  *                                                                            *
12221  * Purpose: find inventory value in automatically populated cache, if not     *
12222  *          found then look in main inventory cache                           *
12223  *                                                                            *
12224  ******************************************************************************/
DCget_host_inventory_value_by_hostid(zbx_uint64_t hostid,char ** replace_to,int value_idx)12225 int	DCget_host_inventory_value_by_hostid(zbx_uint64_t hostid, char **replace_to, int value_idx)
12226 {
12227 	int	ret;
12228 
12229 	RDLOCK_CACHE;
12230 
12231 	ret = dc_get_host_inventory_value_by_hostid(hostid, replace_to, value_idx);
12232 
12233 	UNLOCK_CACHE;
12234 
12235 	return ret;
12236 }
12237 
12238 /******************************************************************************
12239  *                                                                            *
12240  * Function: zbx_dc_get_trigger_dependencies                                  *
12241  *                                                                            *
12242  * Purpose: checks/returns trigger dependencies for a set of triggers         *
12243  *                                                                            *
12244  * Parameter: triggerids  - [IN] the currently processing trigger ids         *
12245  *            deps        - [OUT] list of dependency check results for failed *
12246  *                                or unresolved dependencies                  *
12247  *                                                                            *
12248  * Comments: This function returns list of zbx_trigger_dep_t structures       *
12249  *           for failed or unresolved dependency checks.                      *
12250  *           Dependency check is failed if any of the master triggers that    *
12251  *           are not being processed in this batch (present in triggerids     *
12252  *           vector) has a problem value.                                     *
12253  *           Dependency check is unresolved if a master trigger is being      *
12254  *           processed in this batch (present in triggerids vector) and no    *
12255  *           other master triggers have problem value.                        *
12256  *           Dependency check is successful if all master triggers (if any)   *
12257  *           have OK value and are not being processed in this batch.         *
12258  *                                                                            *
12259  ******************************************************************************/
zbx_dc_get_trigger_dependencies(const zbx_vector_uint64_t * triggerids,zbx_vector_ptr_t * deps)12260 void	zbx_dc_get_trigger_dependencies(const zbx_vector_uint64_t *triggerids, zbx_vector_ptr_t *deps)
12261 {
12262 	int				i, ret;
12263 	const ZBX_DC_TRIGGER_DEPLIST	*trigdep;
12264 	zbx_vector_uint64_t		masterids;
12265 	zbx_trigger_dep_t		*dep;
12266 
12267 	zbx_vector_uint64_create(&masterids);
12268 	zbx_vector_uint64_reserve(&masterids, 64);
12269 
12270 	RDLOCK_CACHE;
12271 
12272 	for (i = 0; i < triggerids->values_num; i++)
12273 	{
12274 		if (NULL == (trigdep = (ZBX_DC_TRIGGER_DEPLIST *)zbx_hashset_search(&config->trigdeps, &triggerids->values[i])))
12275 			continue;
12276 
12277 		if (FAIL == (ret = DCconfig_check_trigger_dependencies_rec(trigdep, 0, triggerids, &masterids)) ||
12278 				0 != masterids.values_num)
12279 		{
12280 			dep = (zbx_trigger_dep_t *)zbx_malloc(NULL, sizeof(zbx_trigger_dep_t));
12281 			dep->triggerid = triggerids->values[i];
12282 			zbx_vector_uint64_create(&dep->masterids);
12283 
12284 			if (SUCCEED == ret)
12285 			{
12286 				dep->status = ZBX_TRIGGER_DEPENDENCY_UNRESOLVED;
12287 				zbx_vector_uint64_append_array(&dep->masterids, masterids.values, masterids.values_num);
12288 			}
12289 			else
12290 				dep->status = ZBX_TRIGGER_DEPENDENCY_FAIL;
12291 
12292 			zbx_vector_ptr_append(deps, dep);
12293 		}
12294 
12295 		zbx_vector_uint64_clear(&masterids);
12296 	}
12297 
12298 	UNLOCK_CACHE;
12299 
12300 	zbx_vector_uint64_destroy(&masterids);
12301 }
12302 
12303 /******************************************************************************
12304  *                                                                            *
12305  * Function: zbx_dc_reschedule_items                                          *
12306  *                                                                            *
12307  * Purpose: reschedules items that are processed by the target daemon         *
12308  *                                                                            *
12309  * Parameter: itemids       - [IN] the item identifiers                       *
12310  *            nextcheck     - [IN] the schedueld time                         *
12311  *            proxy_hostids - [OUT] the proxy_hostids of the given itemids    *
12312  *                                  (optional, can be NULL)                   *
12313  *                                                                            *
12314  * Comments: On server this function reschedules items monitored by server.   *
12315  *           On proxy only items monitored by the proxy is accessible, so     *
12316  *           all items can be safely rescheduled.                             *
12317  *                                                                            *
12318  ******************************************************************************/
zbx_dc_reschedule_items(const zbx_vector_uint64_t * itemids,int nextcheck,zbx_uint64_t * proxy_hostids)12319 void	zbx_dc_reschedule_items(const zbx_vector_uint64_t *itemids, int nextcheck, zbx_uint64_t *proxy_hostids)
12320 {
12321 	int		i;
12322 	ZBX_DC_ITEM	*dc_item;
12323 	ZBX_DC_HOST	*dc_host;
12324 	zbx_uint64_t	proxy_hostid;
12325 
12326 	WRLOCK_CACHE;
12327 
12328 	for (i = 0; i < itemids->values_num; i++)
12329 	{
12330 		if (NULL == (dc_item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemids->values[i])) ||
12331 				NULL == (dc_host = (ZBX_DC_HOST *)zbx_hashset_search(&config->hosts, &dc_item->hostid)))
12332 		{
12333 			zabbix_log(LOG_LEVEL_WARNING, "cannot perform check now for itemid [" ZBX_FS_UI64 "]"
12334 					": item is not in cache", itemids->values[i]);
12335 
12336 			proxy_hostid = 0;
12337 		}
12338 		else if (0 == dc_item->schedulable)
12339 		{
12340 			zabbix_log(LOG_LEVEL_WARNING, "cannot perform check now for item \"%s\" on host \"%s\""
12341 					": item configuration error", dc_item->key, dc_host->host);
12342 
12343 			proxy_hostid = 0;
12344 		}
12345 		else if (0 == (proxy_hostid = dc_host->proxy_hostid) ||
12346 				SUCCEED == is_item_processed_by_server(dc_item->type, dc_item->key))
12347 		{
12348 			dc_requeue_item_at(dc_item, dc_host, nextcheck);
12349 			proxy_hostid = 0;
12350 		}
12351 
12352 		if (NULL != proxy_hostids)
12353 			proxy_hostids[i] = proxy_hostid;
12354 	}
12355 
12356 	UNLOCK_CACHE;
12357 }
12358 
12359 /******************************************************************************
12360  *                                                                            *
12361  * Function: zbx_dc_proxy_update_nodata                                       *
12362  *                                                                            *
12363  * Purpose: stop suppress mode of the nodata() trigger                        *
12364  *                                                                            *
12365  * Parameter: subscriptions - [IN] the array of trigger id and time of values *
12366  *                                                                            *
12367  ******************************************************************************/
zbx_dc_proxy_update_nodata(zbx_vector_uint64_pair_t * subscriptions)12368 void	zbx_dc_proxy_update_nodata(zbx_vector_uint64_pair_t *subscriptions)
12369 {
12370 	ZBX_DC_PROXY		*proxy = NULL;
12371 	int			i;
12372 	zbx_uint64_pair_t	p;
12373 
12374 	WRLOCK_CACHE;
12375 
12376 	for (i = 0; i < subscriptions->values_num; i++)
12377 	{
12378 		p = subscriptions->values[i];
12379 
12380 		if ((NULL == proxy || p.first != proxy->hostid) &&
12381 				NULL == (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &p.first)))
12382 		{
12383 			continue;
12384 		}
12385 
12386 		if (0 == (proxy->nodata_win.flags & ZBX_PROXY_SUPPRESS_ACTIVE))
12387 			continue;
12388 
12389 		if (0 != (proxy->nodata_win.flags & ZBX_PROXY_SUPPRESS_MORE) &&
12390 				(int)p.second > proxy->nodata_win.period_end)
12391 		{
12392 			continue;
12393 		}
12394 
12395 		proxy->nodata_win.values_num --;
12396 
12397 		if (0 < proxy->nodata_win.values_num || 0 != (proxy->nodata_win.flags & ZBX_PROXY_SUPPRESS_MORE))
12398 			continue;
12399 
12400 		proxy->nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
12401 		proxy->nodata_win.period_end = 0;
12402 		proxy->nodata_win.values_num = 0;
12403 	}
12404 
12405 	UNLOCK_CACHE;
12406 }
12407 
12408 /******************************************************************************
12409  *                                                                            *
12410  * Function: zbx_dc_update_proxy                                              *
12411  *                                                                            *
12412  * Purpose: updates changed proxy data in configuration cache and updates     *
12413  *          diff flags to reflect the updated data                            *
12414  *                                                                            *
12415  * Parameter: diff - [IN/OUT] the properties to update                        *
12416  *                                                                            *
12417  ******************************************************************************/
zbx_dc_update_proxy(zbx_proxy_diff_t * diff)12418 void	zbx_dc_update_proxy(zbx_proxy_diff_t *diff)
12419 {
12420 	ZBX_DC_PROXY	*proxy;
12421 
12422 	WRLOCK_CACHE;
12423 
12424 	if (diff->lastaccess < config->proxy_lastaccess_ts)
12425 		diff->lastaccess = config->proxy_lastaccess_ts;
12426 
12427 	if (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &diff->hostid)))
12428 	{
12429 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTACCESS))
12430 		{
12431 			int	lost = 0;	/* communication lost */
12432 
12433 			if (0 != (diff->flags &
12434 					(ZBX_FLAGS_PROXY_DIFF_UPDATE_HEARTBEAT | ZBX_FLAGS_PROXY_DIFF_UPDATE_CONFIG)))
12435 			{
12436 				int	delay = diff->lastaccess - proxy->lastaccess;
12437 
12438 				if (NET_DELAY_MAX < delay)
12439 					lost = 1;
12440 			}
12441 
12442 			if (0 == lost && proxy->lastaccess != diff->lastaccess)
12443 				proxy->lastaccess = diff->lastaccess;
12444 
12445 			/* proxy last access in database is updated separately in  */
12446 			/* every ZBX_PROXY_LASTACCESS_UPDATE_FREQUENCY seconds     */
12447 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTACCESS);
12448 		}
12449 
12450 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_VERSION))
12451 		{
12452 			if (proxy->version != diff->version)
12453 				proxy->version = diff->version;
12454 			else
12455 				diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_VERSION);
12456 		}
12457 
12458 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_COMPRESS))
12459 		{
12460 			if (proxy->auto_compress == diff->compress)
12461 				diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_COMPRESS);
12462 			proxy->auto_compress = diff->compress;
12463 		}
12464 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTERROR))
12465 		{
12466 			proxy->last_version_error_time = diff->last_version_error_time;
12467 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_LASTERROR);
12468 		}
12469 
12470 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_PROXYDELAY))
12471 		{
12472 			proxy->proxy_delay = diff->proxy_delay;
12473 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_PROXYDELAY);
12474 		}
12475 
12476 		if (0 != (diff->flags & ZBX_FLAGS_PROXY_DIFF_UPDATE_SUPPRESS_WIN))
12477 		{
12478 			zbx_proxy_suppress_t	*ps_win = &proxy->nodata_win, *ds_win = &diff->nodata_win;
12479 
12480 			if ((ps_win->flags & ZBX_PROXY_SUPPRESS_ACTIVE) != (ds_win->flags & ZBX_PROXY_SUPPRESS_ACTIVE))
12481 			{
12482 				ps_win->period_end = ds_win->period_end;
12483 			}
12484 
12485 			if (ps_win->flags != ds_win->flags)
12486 				ps_win->flags = ds_win->flags;
12487 
12488 			if (0 > ps_win->values_num)	/* some new values was processed faster than old */
12489 				ps_win->values_num = 0;	/* we will suppress more                         */
12490 
12491 			ps_win->values_num += ds_win->values_num;
12492 			diff->flags &= (~ZBX_FLAGS_PROXY_DIFF_UPDATE_SUPPRESS_WIN);
12493 		}
12494 	}
12495 
12496 	UNLOCK_CACHE;
12497 }
12498 
12499 /******************************************************************************
12500  *                                                                            *
12501  * Function: zbx_dc_get_proxy_lastaccess                                      *
12502  *                                                                            *
12503  * Purpose: returns proxy lastaccess changes since last lastaccess request    *
12504  *                                                                            *
12505  * Parameter: lastaccess - [OUT] last access updates for proxies that need    *
12506  *                               to be synced with database, sorted by        *
12507  *                               hostid                                       *
12508  *                                                                            *
12509  ******************************************************************************/
zbx_dc_get_proxy_lastaccess(zbx_vector_uint64_pair_t * lastaccess)12510 void	zbx_dc_get_proxy_lastaccess(zbx_vector_uint64_pair_t *lastaccess)
12511 {
12512 	ZBX_DC_PROXY	*proxy;
12513 	int		now;
12514 
12515 	if (ZBX_PROXY_LASTACCESS_UPDATE_FREQUENCY < (now = time(NULL)) - config->proxy_lastaccess_ts)
12516 	{
12517 		zbx_hashset_iter_t	iter;
12518 
12519 		WRLOCK_CACHE;
12520 
12521 		zbx_hashset_iter_reset(&config->proxies, &iter);
12522 
12523 		while (NULL != (proxy = (ZBX_DC_PROXY *)zbx_hashset_iter_next(&iter)))
12524 		{
12525 			if (proxy->lastaccess >= config->proxy_lastaccess_ts)
12526 			{
12527 				zbx_uint64_pair_t	pair = {proxy->hostid, proxy->lastaccess};
12528 
12529 				zbx_vector_uint64_pair_append(lastaccess, pair);
12530 			}
12531 		}
12532 
12533 		config->proxy_lastaccess_ts = now;
12534 
12535 		UNLOCK_CACHE;
12536 
12537 		zbx_vector_uint64_pair_sort(lastaccess, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
12538 	}
12539 }
12540 
12541 /******************************************************************************
12542  *                                                                            *
12543  * Function: zbx_dc_get_session_token                                         *
12544  *                                                                            *
12545  * Purpose: returns session token                                             *
12546  *                                                                            *
12547  * Return value: pointer to session token (NULL for server).                  *
12548  *                                                                            *
12549  * Comments: The session token is generated during configuration cache        *
12550  *           initialization and is not changed later. Therefore no locking    *
12551  *           is required.                                                     *
12552  *                                                                            *
12553  ******************************************************************************/
zbx_dc_get_session_token(void)12554 const char	*zbx_dc_get_session_token(void)
12555 {
12556 	return config->session_token;
12557 }
12558 
12559 /******************************************************************************
12560  *                                                                            *
12561  * Function: zbx_dc_get_or_create_data_session                                *
12562  *                                                                            *
12563  * Purpose: returns data session, creates a new session if none found         *
12564  *                                                                            *
12565  * Parameter: hostid - [IN] the host (proxy) identifier                       *
12566  *            token  - [IN] the session token (not NULL)                      *
12567  *                                                                            *
12568  * Return value: pointer to data session.                                     *
12569  *                                                                            *
12570  * Comments: The last_valueid property of the returned session object can be  *
12571  *           updated directly without locking cache because only one data     *
12572  *           session is updated at the same time and after retrieving the     *
12573  *           session object will not be deleted for 24 hours.                 *
12574  *                                                                            *
12575  ******************************************************************************/
zbx_dc_get_or_create_data_session(zbx_uint64_t hostid,const char * token)12576 zbx_data_session_t	*zbx_dc_get_or_create_data_session(zbx_uint64_t hostid, const char *token)
12577 {
12578 	zbx_data_session_t	*session, session_local;
12579 	time_t			now;
12580 
12581 	now = time(NULL);
12582 	session_local.hostid = hostid;
12583 	session_local.token = token;
12584 
12585 	RDLOCK_CACHE;
12586 	session = (zbx_data_session_t *)zbx_hashset_search(&config->data_sessions, &session_local);
12587 	UNLOCK_CACHE;
12588 
12589 	if (NULL == session)
12590 	{
12591 		WRLOCK_CACHE;
12592 		session = (zbx_data_session_t *)zbx_hashset_insert(&config->data_sessions, &session_local,
12593 				sizeof(session_local));
12594 		session->token = dc_strdup(token);
12595 		UNLOCK_CACHE;
12596 
12597 		session->last_valueid = 0;
12598 	}
12599 
12600 	session->lastaccess = now;
12601 
12602 	return session;
12603 }
12604 
12605 /******************************************************************************
12606  *                                                                            *
12607  * Function: zbx_dc_cleanup_data_sessions                                     *
12608  *                                                                            *
12609  * Purpose: removes data sessions not accessed for 24 hours                   *
12610  *                                                                            *
12611  ******************************************************************************/
zbx_dc_cleanup_data_sessions(void)12612 void	zbx_dc_cleanup_data_sessions(void)
12613 {
12614 	zbx_data_session_t	*session;
12615 	zbx_hashset_iter_t	iter;
12616 	time_t			now;
12617 
12618 	now = time(NULL);
12619 
12620 	WRLOCK_CACHE;
12621 
12622 	zbx_hashset_iter_reset(&config->data_sessions, &iter);
12623 	while (NULL != (session = (zbx_data_session_t *)zbx_hashset_iter_next(&iter)))
12624 	{
12625 		if (session->lastaccess + SEC_PER_DAY <= now)
12626 		{
12627 			__config_mem_free_func((char *)session->token);
12628 			zbx_hashset_iter_remove(&iter);
12629 		}
12630 	}
12631 
12632 	UNLOCK_CACHE;
12633 }
12634 
zbx_gather_tags_from_host(zbx_uint64_t hostid,zbx_vector_ptr_t * item_tags)12635 static void	zbx_gather_tags_from_host(zbx_uint64_t hostid, zbx_vector_ptr_t *item_tags)
12636 {
12637 	zbx_dc_host_tag_index_t 	*dc_tag_index;
12638 	zbx_dc_host_tag_t		*dc_tag;
12639 	zbx_item_tag_t			*tag;
12640 	int				i;
12641 
12642 	if (NULL != (dc_tag_index = zbx_hashset_search(&config->host_tags_index, &hostid)))
12643 	{
12644 		for (i = 0; i < dc_tag_index->tags.values_num; i++)
12645 		{
12646 			dc_tag = (zbx_dc_host_tag_t *)dc_tag_index->tags.values[i];
12647 			tag = (zbx_item_tag_t *) zbx_malloc(NULL, sizeof(zbx_item_tag_t));
12648 			tag->tag.tag = zbx_strdup(NULL, dc_tag->tag);
12649 			tag->tag.value = zbx_strdup(NULL, dc_tag->value);
12650 			zbx_vector_ptr_append(item_tags, tag);
12651 		}
12652 	}
12653 }
12654 
zbx_gather_tags_from_template_chain(zbx_uint64_t itemid,zbx_vector_ptr_t * item_tags)12655 static void	zbx_gather_tags_from_template_chain(zbx_uint64_t itemid, zbx_vector_ptr_t *item_tags)
12656 {
12657 	ZBX_DC_TEMPLATE_ITEM	*item;
12658 
12659 	if (NULL != (item = (ZBX_DC_TEMPLATE_ITEM *)zbx_hashset_search(&config->template_items, &itemid)))
12660 	{
12661 		zbx_gather_tags_from_host(item->hostid, item_tags);
12662 
12663 		if (0 != item->templateid)
12664 			zbx_gather_tags_from_template_chain(item->templateid, item_tags);
12665 	}
12666 }
12667 
zbx_get_item_tags(zbx_uint64_t itemid,zbx_vector_ptr_t * item_tags)12668 static void	zbx_get_item_tags(zbx_uint64_t itemid, zbx_vector_ptr_t *item_tags)
12669 {
12670 	ZBX_DC_ITEM		*item;
12671 	ZBX_DC_PROTOTYPE_ITEM	*lld_item;
12672 	zbx_item_tag_t		*tag;
12673 	int			n, i;
12674 
12675 	if (NULL == (item = (ZBX_DC_ITEM *)zbx_hashset_search(&config->items, &itemid)))
12676 		return;
12677 
12678 	n = item_tags->values_num;
12679 
12680 	zbx_gather_tags_from_host(item->hostid, item_tags);
12681 
12682 	if (0 != item->templateid)
12683 		zbx_gather_tags_from_template_chain(item->templateid, item_tags);
12684 
12685 	/* check for discovered item */
12686 	if (0 != item->parent_itemid && 4 == item->flags)
12687 	{
12688 		if (NULL != (lld_item = (ZBX_DC_PROTOTYPE_ITEM *)zbx_hashset_search(&config->prototype_items,
12689 				&item->parent_itemid)))
12690 		{
12691 			if (0 != lld_item->templateid)
12692 				zbx_gather_tags_from_template_chain(lld_item->templateid, item_tags);
12693 		}
12694 	}
12695 
12696 	/* assign hostid and itemid values to newly gathered tags */
12697 	for (i = n; i < item_tags->values_num; i++)
12698 	{
12699 		tag = (zbx_item_tag_t *)item_tags->values[i];
12700 		tag->hostid = item->hostid;
12701 		tag->itemid = item->itemid;
12702 	}
12703 }
12704 
zbx_dc_get_item_tags_by_functionids(const zbx_uint64_t * functionids,size_t functionids_num,zbx_vector_ptr_t * item_tags)12705 void	zbx_dc_get_item_tags_by_functionids(const zbx_uint64_t *functionids, size_t functionids_num,
12706 		zbx_vector_ptr_t *item_tags)
12707 {
12708 	const ZBX_DC_FUNCTION	*dc_function;
12709 	size_t			i;
12710 
12711 	RDLOCK_CACHE;
12712 
12713 	for (i = 0; i < functionids_num; i++)
12714 	{
12715 		if (NULL == (dc_function = (const ZBX_DC_FUNCTION *)zbx_hashset_search(&config->functions,
12716 				&functionids[i])))
12717 		{
12718 			continue;
12719 		}
12720 
12721 		zbx_get_item_tags(dc_function->itemid, item_tags);
12722 	}
12723 
12724 	UNLOCK_CACHE;
12725 }
12726 
12727 /******************************************************************************
12728  *                                                                            *
12729  * Function: DCget_proxy_nodata_win                                           *
12730  *                                                                            *
12731  * Purpose: retrieves proxy suppress window data from the cache               *
12732  *                                                                            *
12733  * Parameters: hostid     - [IN] proxy host id                                *
12734  *             nodata_win - [OUT] suppress window data                        *
12735  *             lastaccess - [OUT] proxy last access time                      *
12736  *                                                                            *
12737  * Return value: SUCCEED - the data is retrieved                              *
12738  *               FAIL    - the data cannot be retrieved, proxy not found in   *
12739  *                         configuration cache                                *
12740  *                                                                            *
12741  ******************************************************************************/
DCget_proxy_nodata_win(zbx_uint64_t hostid,zbx_proxy_suppress_t * nodata_win,int * lastaccess)12742 int	DCget_proxy_nodata_win(zbx_uint64_t hostid, zbx_proxy_suppress_t *nodata_win, int *lastaccess)
12743 {
12744 	const ZBX_DC_PROXY	*dc_proxy;
12745 	int			ret;
12746 
12747 	RDLOCK_CACHE;
12748 
12749 	if (NULL != (dc_proxy = (const ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
12750 	{
12751 		const zbx_proxy_suppress_t	*proxy_nodata_win = &dc_proxy->nodata_win;
12752 
12753 		nodata_win->period_end = proxy_nodata_win->period_end;
12754 		nodata_win->values_num = proxy_nodata_win->values_num;
12755 		nodata_win->flags = proxy_nodata_win->flags;
12756 		*lastaccess = dc_proxy->lastaccess;
12757 		ret = SUCCEED;
12758 	}
12759 	else
12760 		ret = FAIL;
12761 
12762 	UNLOCK_CACHE;
12763 
12764 	return ret;
12765 }
12766 
12767 /******************************************************************************
12768  *                                                                            *
12769  * Function: DCget_proxy_delay                                                *
12770  *                                                                            *
12771  * Purpose: retrieves proxy delay from the cache                              *
12772  *                                                                            *
12773  * Parameters: hostid - [IN] proxy host id                                    *
12774  *             delay  - [OUT] proxy delay                                     *
12775  *                                                                            *
12776  * Return value: SUCCEED - the delay is retrieved                             *
12777  *               FAIL    - the delay cannot be retrieved, proxy not found in  *
12778  *                         configuration cache                                *
12779  *                                                                            *
12780  ******************************************************************************/
DCget_proxy_delay(zbx_uint64_t hostid,int * delay)12781 int	DCget_proxy_delay(zbx_uint64_t hostid, int *delay)
12782 {
12783 	const ZBX_DC_PROXY	*dc_proxy;
12784 	int			ret;
12785 
12786 	RDLOCK_CACHE;
12787 
12788 	if (NULL != (dc_proxy = (const ZBX_DC_PROXY *)zbx_hashset_search(&config->proxies, &hostid)))
12789 	{
12790 		*delay = dc_proxy->proxy_delay;
12791 		ret = SUCCEED;
12792 	}
12793 	else
12794 		ret = FAIL;
12795 
12796 	UNLOCK_CACHE;
12797 
12798 	return ret;
12799 }
12800 
12801 /******************************************************************************
12802  *                                                                            *
12803  * Function: DCget_proxy_delay_by_name                                        *
12804  *                                                                            *
12805  * Purpose: retrieves proxy delay from the cache                              *
12806  *                                                                            *
12807  * Parameters: name  - [IN] proxy host name                                   *
12808  *             delay - [OUT] proxy delay                                      *
12809  *             error - [OUT] error                                            *
12810  *                                                                            *
12811  * Return value: SUCCEED - proxy delay is retrieved                           *
12812  *               FAIL    - proxy delay cannot be retrieved                    *
12813  *                                                                            *
12814  ******************************************************************************/
DCget_proxy_delay_by_name(const char * name,int * delay,char ** error)12815 int	DCget_proxy_delay_by_name(const char *name, int *delay, char **error)
12816 {
12817 	const ZBX_DC_HOST	*dc_host;
12818 
12819 	RDLOCK_CACHE;
12820 	dc_host = DCfind_proxy(name);
12821 	UNLOCK_CACHE;
12822 
12823 	if (NULL == dc_host)
12824 	{
12825 		*error = zbx_dsprintf(*error, "Proxy \"%s\" not found.", name);
12826 		return FAIL;
12827 	}
12828 
12829 	if (SUCCEED != DCget_proxy_delay(dc_host->hostid, delay))
12830 	{
12831 		*error = zbx_dsprintf(*error, "Proxy \"%s\" not found in configuration cache.", name);
12832 		return FAIL;
12833 	}
12834 
12835 	return SUCCEED;
12836 }
12837 
12838 /******************************************************************************
12839  *                                                                            *
12840  * Function: zbx_dc_set_macro_env                                             *
12841  *                                                                            *
12842  * Purpose: sets user macro environment security level                        *
12843  *                                                                            *
12844  * Parameter: env - [IN] the security level (see ZBX_MACRO_ENV_* defines)     *
12845  *                                                                            *
12846  * Comments: The security level affects how the secret macros are resolved -  *
12847  *           as they values or '******'.                                      *
12848  *                                                                            *
12849  ******************************************************************************/
zbx_dc_set_macro_env(unsigned char env)12850 unsigned char	zbx_dc_set_macro_env(unsigned char env)
12851 {
12852 	unsigned char	old_env = macro_env;
12853 	macro_env = env;
12854 	return old_env;
12855 }
12856 
12857 /******************************************************************************
12858  *                                                                            *
12859  * Function: zbx_dc_get_instanceid                                            *
12860  *                                                                            *
12861  * Purpose: returns server/proxy instance id                                  *
12862  *                                                                            *
12863  * Return value: the instance id                                              *
12864  *                                                                            *
12865  ******************************************************************************/
zbx_dc_get_instanceid(void)12866 const char	*zbx_dc_get_instanceid(void)
12867 {
12868 	/* instanceid is initialized during the first configuration cache synchronization */
12869 	/* and is never updated - so it can be accessed without locking cache             */
12870 	return config->config->instanceid;
12871 }
12872 
12873 /******************************************************************************
12874  *                                                                            *
12875  * Function: dc_expand_user_macros_in_func_params                             *
12876  *                                                                            *
12877  * Purpose: expand user macros in trigger function parameters                 *
12878  *                                                                            *
12879  * Parameters: params - [IN] the function parameters                          *
12880  *             hostid - [IN] host of the item used in function                *
12881  *                                                                            *
12882  * Return value: The function parameters with expanded user macros.           *
12883  *                                                                            *
12884  ******************************************************************************/
dc_expand_user_macros_in_func_params(const char * params,zbx_uint64_t hostid)12885 char	*dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid)
12886 {
12887 	const char	*ptr;
12888 	size_t		params_len;
12889 	char		*buf;
12890 	size_t		buf_alloc, buf_offset = 0, sep_pos;
12891 
12892 	if ('\0' == *params)
12893 		return zbx_strdup(NULL, params);
12894 
12895 	buf_alloc = params_len = strlen(params);
12896 	buf = zbx_malloc(NULL, buf_alloc);
12897 
12898 	for (ptr = params; ptr < params + params_len; ptr += sep_pos + 1)
12899 	{
12900 		size_t	param_pos, param_len;
12901 		int	quoted;
12902 		char	*param, *resolved_param;
12903 
12904 		zbx_function_param_parse(ptr, &param_pos, &param_len, &sep_pos);
12905 
12906 		param = zbx_function_param_unquote_dyn(ptr + param_pos, param_len, &quoted);
12907 		resolved_param = dc_expand_user_macros(param, &hostid, 1);
12908 
12909 		if (SUCCEED == zbx_function_param_quote(&resolved_param, quoted))
12910 			zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, resolved_param);
12911 		else
12912 			zbx_strncpy_alloc(&buf, &buf_alloc, &buf_offset, ptr + param_pos, param_len);
12913 
12914 		if (',' == ptr[sep_pos])
12915 			zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, ',');
12916 
12917 		zbx_free(resolved_param);
12918 		zbx_free(param);
12919 	}
12920 
12921 	return buf;
12922 }
12923 
zbx_dc_expand_user_macros_in_func_params(const char * params,zbx_uint64_t hostid)12924 char	*zbx_dc_expand_user_macros_in_func_params(const char *params, zbx_uint64_t hostid)
12925 {
12926 	char	*resolved_params;
12927 
12928 	RDLOCK_CACHE;
12929 	resolved_params = dc_expand_user_macros_in_func_params(params, hostid);
12930 	UNLOCK_CACHE;
12931 
12932 	return resolved_params;
12933 }
12934 
dc_expand_user_macros_in_calcitem(const char * formula,zbx_uint64_t hostid)12935 char	*dc_expand_user_macros_in_calcitem(const char *formula, zbx_uint64_t hostid)
12936 {
12937 	char		*exp, *tmp,*expanded, error[128];
12938 	const char	*e;
12939 	size_t		exp_alloc = 128, exp_offset = 0, tmp_alloc = 128, tmp_offset = 0, f_pos, par_l, par_r;
12940 	ZBX_DC_HOST	*dc_host;
12941 
12942 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() formula:%s", __func__, formula);
12943 
12944 	exp = (char *)zbx_malloc(NULL, exp_alloc);
12945 	tmp = (char *)zbx_malloc(NULL, tmp_alloc);
12946 
12947 	for (e = formula; SUCCEED == zbx_function_find(e, &f_pos, &par_l, &par_r, error, sizeof(error)); e += par_r + 1)
12948 	{
12949 		size_t		param_pos, param_len, sep_pos;
12950 		int		quoted;
12951 		char		*hostkey, *host = NULL, *key = NULL;
12952 		zbx_uint64_t	func_hostid = 0;
12953 
12954 		/* substitute user macros in the part of the string preceding function parameters */
12955 
12956 		zbx_strncpy_alloc(&tmp, &tmp_alloc, &tmp_offset, e, par_l + 1);
12957 		expanded = dc_expand_user_macros_in_expression(tmp, &hostid, 1);
12958 		zbx_strcpy_alloc(&exp, &exp_alloc, &exp_offset, expanded);
12959 		zbx_free(expanded);
12960 		tmp_offset = 0;
12961 
12962 		/* substitute user macros in function parameters */
12963 
12964 		zbx_function_param_parse(e + par_l + 1, &param_pos, &param_len, &sep_pos);
12965 
12966 		/* convert relative offset to absolute */
12967 		param_pos += par_l + 1;
12968 		sep_pos += par_l + 1;
12969 
12970 		zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, e + par_l + 1, sep_pos - par_l);
12971 
12972 		/* calculated function has only fist parameter - host:key */
12973 		if (sep_pos == par_r)
12974 			continue;
12975 
12976 		/* extract host:key parameter to find the function hostid */
12977 		hostkey = zbx_function_param_unquote_dyn(e + param_pos, param_len, &quoted);
12978 		if (SUCCEED == parse_host_key(hostkey, &host, &key))
12979 		{
12980 			if (NULL != host)
12981 			{
12982 				if (NULL != (dc_host = DCfind_host(host)))
12983 					func_hostid = dc_host->hostid;
12984 			}
12985 			else
12986 				func_hostid = hostid;
12987 		}
12988 		zbx_free(host);
12989 		zbx_free(key);
12990 		zbx_free(hostkey);
12991 
12992 		if (0 == func_hostid)
12993 		{
12994 			/* couldn't obtain target host, copy the rest of the function as it is */
12995 			zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, e + sep_pos + 1, par_r - sep_pos);
12996 			continue;
12997 		}
12998 
12999 		/* extract remaining parameters and expand user macros */
13000 		zbx_strncpy_alloc(&tmp, &tmp_alloc, &tmp_offset, e + sep_pos + 1, par_r - sep_pos - 1);
13001 		expanded = dc_expand_user_macros_in_func_params(tmp, func_hostid);
13002 		zbx_strcpy_alloc(&exp, &exp_alloc, &exp_offset, expanded);
13003 		zbx_free(expanded);
13004 		tmp_offset = 0;
13005 
13006 		zbx_strcpy_alloc(&exp, &exp_alloc, &exp_offset, ")");
13007 	}
13008 
13009 	if (par_l <= par_r)
13010 	{
13011 		/* substitute user macros in the remaining part */
13012 		zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, e);
13013 		expanded = dc_expand_user_macros_in_expression(tmp, &hostid, 1);
13014 		zbx_strcpy_alloc(&exp, &exp_alloc, &exp_offset, expanded);
13015 		zbx_free(expanded);
13016 	}
13017 
13018 	zbx_free(tmp);
13019 
13020 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() formula:%s", __func__, exp);
13021 
13022 	return exp;
13023 }
13024 
zbx_dc_maintenance_has_tags(void)13025 int	zbx_dc_maintenance_has_tags(void)
13026 {
13027 	int	ret;
13028 
13029 	RDLOCK_CACHE;
13030 	ret = config->maintenance_tags.num_data != 0 ? SUCCEED : FAIL;
13031 	UNLOCK_CACHE;
13032 
13033 	return ret;
13034 }
13035 
13036 #ifdef HAVE_TESTS
13037 #	include "../../../tests/libs/zbxdbcache/dc_item_poller_type_update_test.c"
13038 #endif
13039