1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "active.h"
22 #include "zbxconf.h"
23 
24 #include "cfg.h"
25 #include "log.h"
26 #include "sysinfo.h"
27 #include "logfiles.h"
28 #ifdef _WINDOWS
29 #	include "eventlog.h"
30 #	include <delayimp.h>
31 #endif
32 #include "comms.h"
33 #include "threads.h"
34 #include "zbxjson.h"
35 #include "alias.h"
36 
37 extern unsigned char			program_type;
38 extern ZBX_THREAD_LOCAL unsigned char	process_type;
39 extern ZBX_THREAD_LOCAL int		server_num, process_num;
40 
41 #if defined(ZABBIX_SERVICE)
42 #	include "service.h"
43 #elif defined(ZABBIX_DAEMON)
44 #	include "daemon.h"
45 #endif
46 
47 #include "../libs/zbxcrypto/tls.h"
48 
49 ZBX_THREAD_LOCAL static ZBX_ACTIVE_BUFFER	buffer;
50 ZBX_THREAD_LOCAL static zbx_vector_ptr_t	active_metrics;
51 ZBX_THREAD_LOCAL static zbx_vector_ptr_t	regexps;
52 ZBX_THREAD_LOCAL static char			*session_token;
53 ZBX_THREAD_LOCAL static zbx_uint64_t		last_valueid = 0;
54 
55 #ifdef _WINDOWS
DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS excpointers)56 LONG WINAPI	DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS excpointers)
57 {
58 	LONG		disposition = EXCEPTION_EXECUTE_HANDLER;
59 	PDelayLoadInfo	delayloadinfo = (PDelayLoadInfo)(excpointers->ExceptionRecord->ExceptionInformation[0]);
60 
61 	switch (excpointers->ExceptionRecord->ExceptionCode)
62 	{
63 		case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND):
64 			zabbix_log(LOG_LEVEL_DEBUG, "function %s was not found in %s",
65 					delayloadinfo->dlp.szProcName, delayloadinfo->szDll);
66 			break;
67 		case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND):
68 			if (delayloadinfo->dlp.fImportByName)
69 			{
70 				zabbix_log(LOG_LEVEL_DEBUG, "function %s was not found in %s",
71 						delayloadinfo->dlp.szProcName, delayloadinfo->szDll);
72 			}
73 			else
74 			{
75 				zabbix_log(LOG_LEVEL_DEBUG, "function ordinal %d was not found in %s",
76 						delayloadinfo->dlp.dwOrdinal, delayloadinfo->szDll);
77 			}
78 			break;
79 		default:
80 			disposition = EXCEPTION_CONTINUE_SEARCH;
81 			break;
82 	}
83 
84 	return disposition;
85 }
86 #endif
87 
init_active_metrics(void)88 static void	init_active_metrics(void)
89 {
90 	const char	*__function_name = "init_active_metrics";
91 	size_t		sz;
92 
93 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
94 
95 	if (NULL == buffer.data)
96 	{
97 		zabbix_log(LOG_LEVEL_DEBUG, "buffer: first allocation for %d elements", CONFIG_BUFFER_SIZE);
98 		sz = CONFIG_BUFFER_SIZE * sizeof(ZBX_ACTIVE_BUFFER_ELEMENT);
99 		buffer.data = (ZBX_ACTIVE_BUFFER_ELEMENT *)zbx_malloc(buffer.data, sz);
100 		memset(buffer.data, 0, sz);
101 		buffer.count = 0;
102 		buffer.pcount = 0;
103 		buffer.lastsent = (int)time(NULL);
104 		buffer.first_error = 0;
105 	}
106 
107 	zbx_vector_ptr_create(&active_metrics);
108 	zbx_vector_ptr_create(&regexps);
109 
110 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
111 }
112 
free_active_metric(ZBX_ACTIVE_METRIC * metric)113 static void	free_active_metric(ZBX_ACTIVE_METRIC *metric)
114 {
115 	int	i;
116 
117 	zbx_free(metric->key);
118 	zbx_free(metric->key_orig);
119 
120 	for (i = 0; i < metric->logfiles_num; i++)
121 		zbx_free(metric->logfiles[i].filename);
122 
123 	zbx_free(metric->logfiles);
124 	zbx_free(metric);
125 }
126 
127 #ifdef _WINDOWS
free_active_metrics(void)128 static void	free_active_metrics(void)
129 {
130 	const char	*__function_name = "free_active_metrics";
131 
132 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
133 
134 	zbx_regexp_clean_expressions(&regexps);
135 	zbx_vector_ptr_destroy(&regexps);
136 
137 	zbx_vector_ptr_clear_ext(&active_metrics, (zbx_clean_func_t)free_active_metric);
138 	zbx_vector_ptr_destroy(&active_metrics);
139 
140 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
141 }
142 #endif
143 
metric_ready_to_process(const ZBX_ACTIVE_METRIC * metric)144 static int	metric_ready_to_process(const ZBX_ACTIVE_METRIC *metric)
145 {
146 	if (ITEM_STATE_NOTSUPPORTED == metric->state && 0 == metric->refresh_unsupported)
147 		return FAIL;
148 
149 	return SUCCEED;
150 }
151 
get_min_nextcheck(void)152 static int	get_min_nextcheck(void)
153 {
154 	const char	*__function_name = "get_min_nextcheck";
155 	int		i, min = -1;
156 
157 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
158 
159 	for (i = 0; i < active_metrics.values_num; i++)
160 	{
161 		const ZBX_ACTIVE_METRIC	*metric = (const ZBX_ACTIVE_METRIC *)active_metrics.values[i];
162 
163 		if (SUCCEED != metric_ready_to_process(metric))
164 			continue;
165 
166 		if (metric->nextcheck < min || -1 == min)
167 			min = metric->nextcheck;
168 	}
169 
170 	if (-1 == min)
171 		min = FAIL;
172 
173 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, min);
174 
175 	return min;
176 }
177 
add_check(const char * key,const char * key_orig,int refresh,zbx_uint64_t lastlogsize,int mtime)178 static void	add_check(const char *key, const char *key_orig, int refresh, zbx_uint64_t lastlogsize, int mtime)
179 {
180 	const char		*__function_name = "add_check";
181 	ZBX_ACTIVE_METRIC	*metric;
182 	int			i;
183 
184 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s' refresh:%d lastlogsize:" ZBX_FS_UI64 " mtime:%d",
185 			__function_name, key, refresh, lastlogsize, mtime);
186 
187 	for (i = 0; i < active_metrics.values_num; i++)
188 	{
189 		metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
190 
191 		if (0 != strcmp(metric->key_orig, key_orig))
192 			continue;
193 
194 		if (0 != strcmp(metric->key, key))
195 		{
196 			int	j;
197 
198 			zbx_free(metric->key);
199 			metric->key = zbx_strdup(NULL, key);
200 			metric->lastlogsize = lastlogsize;
201 			metric->mtime = mtime;
202 			metric->big_rec = 0;
203 			metric->use_ino = 0;
204 			metric->error_count = 0;
205 
206 			for (j = 0; j < metric->logfiles_num; j++)
207 				zbx_free(metric->logfiles[j].filename);
208 
209 			zbx_free(metric->logfiles);
210 			metric->logfiles_num = 0;
211 			metric->start_time = 0.0;
212 			metric->processed_bytes = 0;
213 		}
214 
215 		/* replace metric */
216 		if (metric->refresh != refresh)
217 		{
218 			metric->nextcheck = 0;
219 			metric->refresh = refresh;
220 		}
221 
222 		if (ITEM_STATE_NOTSUPPORTED == metric->state)
223 		{
224 			/* Currently receiving list of active checks works as a signal to refresh unsupported */
225 			/* items. Hopefully in the future this will be controlled by server (ZBXNEXT-2633). */
226 			metric->refresh_unsupported = 1;
227 			metric->start_time = 0.0;
228 			metric->processed_bytes = 0;
229 		}
230 
231 		goto out;
232 	}
233 
234 	metric = (ZBX_ACTIVE_METRIC *)zbx_malloc(NULL, sizeof(ZBX_ACTIVE_METRIC));
235 
236 	/* add new metric */
237 	metric->key = zbx_strdup(NULL, key);
238 	metric->key_orig = zbx_strdup(NULL, key_orig);
239 	metric->refresh = refresh;
240 	metric->nextcheck = 0;
241 	metric->state = ITEM_STATE_NORMAL;
242 	metric->refresh_unsupported = 0;
243 	metric->lastlogsize = lastlogsize;
244 	metric->mtime = mtime;
245 	/* existing log[], log.count[] and eventlog[] data can be skipped */
246 	metric->skip_old_data = (0 != metric->lastlogsize ? 0 : 1);
247 	metric->big_rec = 0;
248 	metric->use_ino = 0;
249 	metric->error_count = 0;
250 	metric->logfiles_num = 0;
251 	metric->logfiles = NULL;
252 	metric->flags = ZBX_METRIC_FLAG_NEW;
253 
254 	if ('l' == metric->key[0] && 'o' == metric->key[1] && 'g' == metric->key[2])
255 	{
256 		if ('[' == metric->key[3])					/* log[ */
257 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOG;
258 		else if (0 == strncmp(metric->key + 3, "rt[", 3))		/* logrt[ */
259 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOGRT;
260 		else if (0 == strncmp(metric->key + 3, ".count[", 7))		/* log.count[ */
261 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOG | ZBX_METRIC_FLAG_LOG_COUNT;
262 		else if (0 == strncmp(metric->key + 3, "rt.count[", 9))		/* logrt.count[ */
263 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOGRT | ZBX_METRIC_FLAG_LOG_COUNT;
264 	}
265 	else if (0 == strncmp(metric->key, "eventlog[", 9))
266 		metric->flags |= ZBX_METRIC_FLAG_LOG_EVENTLOG;
267 
268 	metric->start_time = 0.0;
269 	metric->processed_bytes = 0;
270 
271 	zbx_vector_ptr_append(&active_metrics, metric);
272 out:
273 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
274 }
275 
276 /******************************************************************************
277  *                                                                            *
278  * Function: mode_parameter_is_skip                                           *
279  *                                                                            *
280  * Purpose: test log[] or log.count[] item key if <mode> parameter is set to  *
281  *          'skip'                                                            *
282  *                                                                            *
283  * Return value: SUCCEED - <mode> parameter is set to 'skip'                  *
284  *               FAIL - <mode> is not 'skip' or error                         *
285  *                                                                            *
286  ******************************************************************************/
mode_parameter_is_skip(unsigned char flags,const char * itemkey)287 static int	mode_parameter_is_skip(unsigned char flags, const char *itemkey)
288 {
289 	AGENT_REQUEST	request;
290 	const char	*skip;
291 	int		ret = FAIL, max_num_parameters;
292 
293 	if (0 == (ZBX_METRIC_FLAG_LOG_COUNT & flags))	/* log[] */
294 		max_num_parameters = 7;
295 	else						/* log.count[] */
296 		max_num_parameters = 6;
297 
298 	init_request(&request);
299 
300 	if (SUCCEED == parse_item_key(itemkey, &request) && 0 < get_rparams_num(&request) &&
301 			max_num_parameters >= get_rparams_num(&request) && NULL != (skip = get_rparam(&request, 4)) &&
302 			0 == strcmp(skip, "skip"))
303 	{
304 		ret = SUCCEED;
305 	}
306 
307 	free_request(&request);
308 
309 	return ret;
310 }
311 
312 /******************************************************************************
313  *                                                                            *
314  * Function: parse_list_of_checks                                             *
315  *                                                                            *
316  * Purpose: Parse list of active checks received from server                  *
317  *                                                                            *
318  * Parameters: str  - NULL terminated string received from server             *
319  *             host - address of host                                         *
320  *             port - port number on host                                     *
321  *                                                                            *
322  * Return value: returns SUCCEED on successful parsing,                       *
323  *               FAIL on an incorrect format of string                        *
324  *                                                                            *
325  * Author: Eugene Grigorjev, Alexei Vladishev (new json protocol)             *
326  *                                                                            *
327  * Comments:                                                                  *
328  *    String represented as "ZBX_EOF" termination list                        *
329  *    With '\n' delimiter between elements.                                   *
330  *    Each element represented as:                                            *
331  *           <key>:<refresh time>:<last log size>:<modification time>         *
332  *                                                                            *
333  ******************************************************************************/
parse_list_of_checks(char * str,const char * host,unsigned short port)334 static int	parse_list_of_checks(char *str, const char *host, unsigned short port)
335 {
336 	const char		*__function_name = "parse_list_of_checks";
337 	const char		*p;
338 	char			name[MAX_STRING_LEN], key_orig[MAX_STRING_LEN], expression[MAX_STRING_LEN],
339 				tmp[MAX_STRING_LEN], exp_delimiter;
340 	zbx_uint64_t		lastlogsize;
341 	struct zbx_json_parse	jp;
342 	struct zbx_json_parse	jp_data, jp_row;
343 	ZBX_ACTIVE_METRIC	*metric;
344 	zbx_vector_str_t	received_metrics;
345 	int			delay, mtime, expression_type, case_sensitive, i, j, ret = FAIL;
346 
347 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
348 
349 	zbx_vector_str_create(&received_metrics);
350 
351 	if (SUCCEED != zbx_json_open(str, &jp))
352 	{
353 		zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
354 		goto out;
355 	}
356 
357 	if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, tmp, sizeof(tmp), NULL))
358 	{
359 		zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
360 		goto out;
361 	}
362 
363 	if (0 != strcmp(tmp, ZBX_PROTO_VALUE_SUCCESS))
364 	{
365 		if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_INFO, tmp, sizeof(tmp), NULL))
366 			zabbix_log(LOG_LEVEL_WARNING, "no active checks on server [%s:%hu]: %s", host, port, tmp);
367 		else
368 			zabbix_log(LOG_LEVEL_WARNING, "no active checks on server");
369 
370 		goto out;
371 	}
372 
373 	if (SUCCEED != zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
374 	{
375 		zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
376 		goto out;
377 	}
378 
379  	p = NULL;
380 	while (NULL != (p = zbx_json_next(&jp_data, p)))
381 	{
382 /* {"data":[{"key":"system.cpu.num",...,...},{...},...]}
383  *          ^------------------------------^
384  */ 		if (SUCCEED != zbx_json_brackets_open(p, &jp_row))
385 		{
386 			zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
387 			goto out;
388 		}
389 
390 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_KEY, name, sizeof(name), NULL) ||
391 				'\0' == *name)
392 		{
393 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_KEY);
394 			continue;
395 		}
396 
397 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_KEY_ORIG, key_orig, sizeof(key_orig), NULL)
398 				|| '\0' == *key_orig) {
399 			zbx_strlcpy(key_orig, name, sizeof(key_orig));
400 		}
401 
402 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_DELAY, tmp, sizeof(tmp), NULL) ||
403 				'\0' == *tmp)
404 		{
405 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_DELAY);
406 			continue;
407 		}
408 
409 		delay = atoi(tmp);
410 
411 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_LASTLOGSIZE, tmp, sizeof(tmp), NULL) ||
412 				SUCCEED != is_uint64(tmp, &lastlogsize))
413 		{
414 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_LASTLOGSIZE);
415 			continue;
416 		}
417 
418 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_MTIME, tmp, sizeof(tmp), NULL) ||
419 				'\0' == *tmp)
420 		{
421 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_MTIME);
422 			mtime = 0;
423 		}
424 		else
425 			mtime = atoi(tmp);
426 
427 		add_check(zbx_alias_get(name), key_orig, delay, lastlogsize, mtime);
428 
429 		/* remember what was received */
430 		zbx_vector_str_append(&received_metrics, zbx_strdup(NULL, key_orig));
431 	}
432 
433 	/* remove what wasn't received */
434 	for (i = 0; i < active_metrics.values_num; i++)
435 	{
436 		int	found = 0;
437 
438 		metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
439 
440 		/* 'Do-not-delete' exception for log[] and log.count[] items with <mode> parameter set to 'skip'. */
441 		/* We need to keep their state, namely 'skip_old_data', in case the items become NOTSUPPORTED as */
442 		/* server might not send them in a new active check list. */
443 
444 		if (0 != (ZBX_METRIC_FLAG_LOG_LOG & metric->flags) && ITEM_STATE_NOTSUPPORTED == metric->state &&
445 				0 == metric->skip_old_data && SUCCEED == mode_parameter_is_skip(metric->flags,
446 				metric->key))
447 		{
448 			continue;
449 		}
450 
451 		for (j = 0; j < received_metrics.values_num; j++)
452 		{
453 			if (0 == strcmp(metric->key_orig, received_metrics.values[j]))
454 			{
455 				found = 1;
456 				break;
457 			}
458 		}
459 
460 		if (0 == found)
461 		{
462 			zbx_vector_ptr_remove_noorder(&active_metrics, i);
463 			free_active_metric(metric);
464 			i--;	/* consider the same index on the next run */
465 		}
466 	}
467 
468 	zbx_regexp_clean_expressions(&regexps);
469 
470 	if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_REGEXP, &jp_data))
471 	{
472 	 	p = NULL;
473 		while (NULL != (p = zbx_json_next(&jp_data, p)))
474 		{
475 /* {"regexp":[{"name":"regexp1",...,...},{...},...]}
476  *            ^------------------------^
477  */			if (SUCCEED != zbx_json_brackets_open(p, &jp_row))
478 			{
479 				zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
480 				goto out;
481 			}
482 
483 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "name", name, sizeof(name), NULL))
484 			{
485 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "name");
486 				continue;
487 			}
488 
489 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "expression", expression, sizeof(expression),
490 					NULL) || '\0' == *expression)
491 			{
492 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "expression");
493 				continue;
494 			}
495 
496 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "expression_type", tmp, sizeof(tmp), NULL) ||
497 					'\0' == *tmp)
498 			{
499 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "expression_type");
500 				continue;
501 			}
502 
503 			expression_type = atoi(tmp);
504 
505 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "exp_delimiter", tmp, sizeof(tmp), NULL))
506 			{
507 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "exp_delimiter");
508 				continue;
509 			}
510 
511 			exp_delimiter = tmp[0];
512 
513 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "case_sensitive", tmp,
514 					sizeof(tmp), NULL) || '\0' == *tmp)
515 			{
516 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "case_sensitive");
517 				continue;
518 			}
519 
520 			case_sensitive = atoi(tmp);
521 
522 			add_regexp_ex(&regexps, name, expression, expression_type, exp_delimiter, case_sensitive);
523 		}
524 	}
525 
526 	ret = SUCCEED;
527 out:
528 	zbx_vector_str_clear_ext(&received_metrics, zbx_str_free);
529 	zbx_vector_str_destroy(&received_metrics);
530 
531 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
532 
533 	return ret;
534 }
535 
536 /******************************************************************************
537  *                                                                            *
538  * Function: refresh_active_checks                                            *
539  *                                                                            *
540  * Purpose: Retrieve from Zabbix server list of active checks                 *
541  *                                                                            *
542  * Parameters: host - IP or Hostname of Zabbix server                         *
543  *             port - port of Zabbix server                                   *
544  *                                                                            *
545  * Return value: returns SUCCEED on successful parsing,                       *
546  *               FAIL on other cases                                          *
547  *                                                                            *
548  * Author: Eugene Grigorjev, Alexei Vladishev (new json protocol)             *
549  *                                                                            *
550  * Comments:                                                                  *
551  *                                                                            *
552  ******************************************************************************/
refresh_active_checks(const char * host,unsigned short port)553 static int	refresh_active_checks(const char *host, unsigned short port)
554 {
555 	const char	*__function_name = "refresh_active_checks";
556 
557 	ZBX_THREAD_LOCAL static int	last_ret = SUCCEED;
558 	int				ret;
559 	char				*tls_arg1, *tls_arg2;
560 	zbx_socket_t			s;
561 	struct zbx_json			json;
562 
563 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s' port:%hu", __function_name, host, port);
564 
565 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
566 
567 	zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_GET_ACTIVE_CHECKS, ZBX_JSON_TYPE_STRING);
568 	zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST, CONFIG_HOSTNAME, ZBX_JSON_TYPE_STRING);
569 
570 	if (NULL != CONFIG_HOST_METADATA)
571 	{
572 		zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST_METADATA, CONFIG_HOST_METADATA, ZBX_JSON_TYPE_STRING);
573 	}
574 	else if (NULL != CONFIG_HOST_METADATA_ITEM)
575 	{
576 		char		**value;
577 		AGENT_RESULT	result;
578 
579 		init_result(&result);
580 
581 		if (SUCCEED == process(CONFIG_HOST_METADATA_ITEM, PROCESS_LOCAL_COMMAND | PROCESS_WITH_ALIAS, &result) &&
582 				NULL != (value = GET_STR_RESULT(&result)) && NULL != *value)
583 		{
584 			if (SUCCEED != zbx_is_utf8(*value))
585 			{
586 				zabbix_log(LOG_LEVEL_WARNING, "cannot get host metadata using \"%s\" item specified by"
587 						" \"HostMetadataItem\" configuration parameter: returned value is not"
588 						" an UTF-8 string", CONFIG_HOST_METADATA_ITEM);
589 			}
590 			else
591 			{
592 				if (HOST_METADATA_LEN < zbx_strlen_utf8(*value))
593 				{
594 					size_t	bytes;
595 
596 					zabbix_log(LOG_LEVEL_WARNING, "the returned value of \"%s\" item specified by"
597 							" \"HostMetadataItem\" configuration parameter is too long,"
598 							" using first %d characters", CONFIG_HOST_METADATA_ITEM,
599 							HOST_METADATA_LEN);
600 
601 					bytes = zbx_strlen_utf8_nchars(*value, HOST_METADATA_LEN);
602 					(*value)[bytes] = '\0';
603 				}
604 				zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST_METADATA, *value, ZBX_JSON_TYPE_STRING);
605 			}
606 		}
607 		else
608 			zabbix_log(LOG_LEVEL_WARNING, "cannot get host metadata using \"%s\" item specified by"
609 					" \"HostMetadataItem\" configuration parameter", CONFIG_HOST_METADATA_ITEM);
610 
611 		free_result(&result);
612 	}
613 
614 	if (NULL != CONFIG_LISTEN_IP)
615 	{
616 		char	*p;
617 
618 		if (NULL != (p = strchr(CONFIG_LISTEN_IP, ',')))
619 			*p = '\0';
620 
621 		zbx_json_addstring(&json, ZBX_PROTO_TAG_IP, CONFIG_LISTEN_IP, ZBX_JSON_TYPE_STRING);
622 
623 		if (NULL != p)
624 			*p = ',';
625 	}
626 
627 	if (ZBX_DEFAULT_AGENT_PORT != CONFIG_LISTEN_PORT)
628 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_PORT, CONFIG_LISTEN_PORT);
629 
630 	switch (configured_tls_connect_mode)
631 	{
632 		case ZBX_TCP_SEC_UNENCRYPTED:
633 			tls_arg1 = NULL;
634 			tls_arg2 = NULL;
635 			break;
636 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
637 		case ZBX_TCP_SEC_TLS_CERT:
638 			tls_arg1 = CONFIG_TLS_SERVER_CERT_ISSUER;
639 			tls_arg2 = CONFIG_TLS_SERVER_CERT_SUBJECT;
640 			break;
641 		case ZBX_TCP_SEC_TLS_PSK:
642 			tls_arg1 = CONFIG_TLS_PSK_IDENTITY;
643 			tls_arg2 = NULL;	/* zbx_tls_connect() will find PSK */
644 			break;
645 #endif
646 		default:
647 			THIS_SHOULD_NEVER_HAPPEN;
648 			ret = FAIL;
649 			goto out;
650 	}
651 
652 	if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, CONFIG_TIMEOUT,
653 			configured_tls_connect_mode, tls_arg1, tls_arg2)))
654 	{
655 		zabbix_log(LOG_LEVEL_DEBUG, "sending [%s]", json.buffer);
656 
657 		if (SUCCEED == (ret = zbx_tcp_send(&s, json.buffer)))
658 		{
659 			zabbix_log(LOG_LEVEL_DEBUG, "before read");
660 
661 			if (SUCCEED == (ret = zbx_tcp_recv(&s)))
662 			{
663 				zabbix_log(LOG_LEVEL_DEBUG, "got [%s]", s.buffer);
664 
665 				if (SUCCEED != last_ret)
666 				{
667 					zabbix_log(LOG_LEVEL_WARNING, "active check configuration update from [%s:%hu]"
668 							" is working again", host, port);
669 				}
670 				parse_list_of_checks(s.buffer, host, port);
671 			}
672 		}
673 
674 		zbx_tcp_close(&s);
675 	}
676 out:
677 	if (SUCCEED != ret && SUCCEED == last_ret)
678 	{
679 		zabbix_log(LOG_LEVEL_WARNING,
680 				"active check configuration update from [%s:%hu] started to fail (%s)",
681 				host, port, zbx_socket_strerror());
682 	}
683 
684 	last_ret = ret;
685 
686 	zbx_json_free(&json);
687 
688 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
689 
690 	return ret;
691 }
692 
693 /******************************************************************************
694  *                                                                            *
695  * Function: check_response                                                   *
696  *                                                                            *
697  * Purpose: Check whether JSON response is SUCCEED                            *
698  *                                                                            *
699  * Parameters: JSON response from Zabbix trapper                              *
700  *                                                                            *
701  * Return value:  SUCCEED - processed successfully                            *
702  *                FAIL - an error occurred                                    *
703  *                                                                            *
704  * Author: Alexei Vladishev                                                   *
705  *                                                                            *
706  * Comments: zabbix_sender has almost the same function!                      *
707  *                                                                            *
708  ******************************************************************************/
check_response(char * response)709 static int	check_response(char *response)
710 {
711 	const char		*__function_name = "check_response";
712 
713 	struct zbx_json_parse	jp;
714 	char			value[MAX_STRING_LEN];
715 	char			info[MAX_STRING_LEN];
716 	int			ret;
717 
718 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() response:'%s'", __function_name, response);
719 
720 	ret = zbx_json_open(response, &jp);
721 
722 	if (SUCCEED == ret)
723 		ret = zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, value, sizeof(value), NULL);
724 
725 	if (SUCCEED == ret && 0 != strcmp(value, ZBX_PROTO_VALUE_SUCCESS))
726 		ret = FAIL;
727 
728 	if (SUCCEED == ret && SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_INFO, info, sizeof(info), NULL))
729 		zabbix_log(LOG_LEVEL_DEBUG, "info from server: '%s'", info);
730 
731 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
732 
733 	return ret;
734 }
735 
736 /******************************************************************************
737  *                                                                            *
738  * Function: send_buffer                                                      *
739  *                                                                            *
740  * Purpose: Send value stored in the buffer to Zabbix server                  *
741  *                                                                            *
742  * Parameters: host - IP or Hostname of Zabbix server                         *
743  *             port - port number                                             *
744  *                                                                            *
745  * Return value: returns SUCCEED on successful sending,                       *
746  *               FAIL on other cases                                          *
747  *                                                                            *
748  * Author: Alexei Vladishev                                                   *
749  *                                                                            *
750  ******************************************************************************/
send_buffer(const char * host,unsigned short port)751 static int	send_buffer(const char *host, unsigned short port)
752 {
753 	const char			*__function_name = "send_buffer";
754 	ZBX_ACTIVE_BUFFER_ELEMENT	*el;
755 	int				ret = SUCCEED, i, now;
756 	char				*tls_arg1, *tls_arg2;
757 	zbx_timespec_t			ts;
758 	const char			*err_send_step = "";
759 	zbx_socket_t			s;
760 	struct zbx_json 		json;
761 
762 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s' port:%d entries:%d/%d",
763 			__function_name, host, port, buffer.count, CONFIG_BUFFER_SIZE);
764 
765 	if (0 == buffer.count)
766 		goto ret;
767 
768 	now = (int)time(NULL);
769 
770 	if (CONFIG_BUFFER_SIZE / 2 > buffer.pcount && CONFIG_BUFFER_SIZE > buffer.count &&
771 			CONFIG_BUFFER_SEND > now - buffer.lastsent)
772 	{
773 		zabbix_log(LOG_LEVEL_DEBUG, "%s() now:%d lastsent:%d now-lastsent:%d BufferSend:%d; will not send now",
774 				__function_name, now, buffer.lastsent, now - buffer.lastsent, CONFIG_BUFFER_SEND);
775 		goto ret;
776 	}
777 
778 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
779 	zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_AGENT_DATA, ZBX_JSON_TYPE_STRING);
780 	zbx_json_addstring(&json, ZBX_PROTO_TAG_SESSION, session_token, ZBX_JSON_TYPE_STRING);
781 	zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
782 
783 	for (i = 0; i < buffer.count; i++)
784 	{
785 		el = &buffer.data[i];
786 
787 		zbx_json_addobject(&json, NULL);
788 		zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST, el->host, ZBX_JSON_TYPE_STRING);
789 		zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, el->key, ZBX_JSON_TYPE_STRING);
790 
791 		if (NULL != el->value)
792 			zbx_json_addstring(&json, ZBX_PROTO_TAG_VALUE, el->value, ZBX_JSON_TYPE_STRING);
793 
794 		if (ITEM_STATE_NOTSUPPORTED == el->state)
795 		{
796 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_STATE, ITEM_STATE_NOTSUPPORTED);
797 		}
798 		else
799 		{
800 			/* add item meta information only for items in normal state */
801 			if (0 != (ZBX_METRIC_FLAG_LOG & el->flags))
802 				zbx_json_adduint64(&json, ZBX_PROTO_TAG_LASTLOGSIZE, el->lastlogsize);
803 			if (0 != (ZBX_METRIC_FLAG_LOG_LOGRT & el->flags))
804 				zbx_json_adduint64(&json, ZBX_PROTO_TAG_MTIME, el->mtime);
805 		}
806 
807 		if (0 != el->timestamp)
808 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGTIMESTAMP, el->timestamp);
809 
810 		if (NULL != el->source)
811 			zbx_json_addstring(&json, ZBX_PROTO_TAG_LOGSOURCE, el->source, ZBX_JSON_TYPE_STRING);
812 
813 		if (0 != el->severity)
814 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGSEVERITY, el->severity);
815 
816 		if (0 != el->logeventid)
817 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGEVENTID, el->logeventid);
818 
819 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_ID, el->id);
820 
821 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_CLOCK, el->ts.sec);
822 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_NS, el->ts.ns);
823 		zbx_json_close(&json);
824 	}
825 
826 	zbx_json_close(&json);
827 
828 	switch (configured_tls_connect_mode)
829 	{
830 		case ZBX_TCP_SEC_UNENCRYPTED:
831 			tls_arg1 = NULL;
832 			tls_arg2 = NULL;
833 			break;
834 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
835 		case ZBX_TCP_SEC_TLS_CERT:
836 			tls_arg1 = CONFIG_TLS_SERVER_CERT_ISSUER;
837 			tls_arg2 = CONFIG_TLS_SERVER_CERT_SUBJECT;
838 			break;
839 		case ZBX_TCP_SEC_TLS_PSK:
840 			tls_arg1 = CONFIG_TLS_PSK_IDENTITY;
841 			tls_arg2 = NULL;	/* zbx_tls_connect() will find PSK */
842 			break;
843 #endif
844 		default:
845 			THIS_SHOULD_NEVER_HAPPEN;
846 			ret = FAIL;
847 			goto out;
848 	}
849 
850 	if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, MIN(buffer.count * CONFIG_TIMEOUT, 60),
851 			configured_tls_connect_mode, tls_arg1, tls_arg2)))
852 	{
853 		zbx_timespec(&ts);
854 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_CLOCK, ts.sec);
855 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_NS, ts.ns);
856 
857 		zabbix_log(LOG_LEVEL_DEBUG, "JSON before sending [%s]", json.buffer);
858 
859 		if (SUCCEED == (ret = zbx_tcp_send(&s, json.buffer)))
860 		{
861 			if (SUCCEED == (ret = zbx_tcp_recv(&s)))
862 			{
863 				zabbix_log(LOG_LEVEL_DEBUG, "JSON back [%s]", s.buffer);
864 
865 				if (NULL == s.buffer || SUCCEED != check_response(s.buffer))
866 				{
867 					ret = FAIL;
868 					zabbix_log(LOG_LEVEL_DEBUG, "NOT OK");
869 				}
870 				else
871 					zabbix_log(LOG_LEVEL_DEBUG, "OK");
872 			}
873 			else
874 				err_send_step = "[recv] ";
875 		}
876 		else
877 			err_send_step = "[send] ";
878 
879 		zbx_tcp_close(&s);
880 	}
881 	else
882 		err_send_step = "[connect] ";
883 out:
884 	zbx_json_free(&json);
885 
886 	if (SUCCEED == ret)
887 	{
888 		/* free buffer */
889 		for (i = 0; i < buffer.count; i++)
890 		{
891 			el = &buffer.data[i];
892 
893 			zbx_free(el->host);
894 			zbx_free(el->key);
895 			zbx_free(el->value);
896 			zbx_free(el->source);
897 		}
898 		buffer.count = 0;
899 		buffer.pcount = 0;
900 		buffer.lastsent = now;
901 		if (0 != buffer.first_error)
902 		{
903 			zabbix_log(LOG_LEVEL_WARNING, "active check data upload to [%s:%hu] is working again",
904 					host, port);
905 			buffer.first_error = 0;
906 		}
907 	}
908 	else
909 	{
910 		if (0 == buffer.first_error)
911 		{
912 			zabbix_log(LOG_LEVEL_WARNING, "active check data upload to [%s:%hu] started to fail (%s%s)",
913 					host, port, err_send_step, zbx_socket_strerror());
914 			buffer.first_error = now;
915 		}
916 		zabbix_log(LOG_LEVEL_DEBUG, "send value error: %s%s", err_send_step, zbx_socket_strerror());
917 	}
918 ret:
919 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
920 
921 	return ret;
922 }
923 
924 /******************************************************************************
925  *                                                                            *
926  * Function: process_value                                                    *
927  *                                                                            *
928  * Purpose: Buffer new value or send the whole buffer to the server           *
929  *                                                                            *
930  * Parameters: server      - IP or Hostname of Zabbix server                  *
931  *             port        - port of Zabbix server                            *
932  *             host        - name of host in Zabbix database                  *
933  *             key         - name of metric                                   *
934  *             value       - key value or error message why an item became    *
935  *                           NOTSUPPORTED                                     *
936  *             state       - ITEM_STATE_NORMAL or ITEM_STATE_NOTSUPPORTED     *
937  *             lastlogsize - size of read logfile                             *
938  *             mtime       - time of last file modification                   *
939  *             timestamp   - timestamp of read value                          *
940  *             source      - name of logged data source                       *
941  *             severity    - severity of logged data sources                  *
942  *             logeventid  - the application-specific identifier for          *
943  *                           the event; used for monitoring of Windows        *
944  *                           event logs                                       *
945  *             flags       - metric flags                                     *
946  *                                                                            *
947  * Return value: returns SUCCEED on successful parsing,                       *
948  *               FAIL on other cases                                          *
949  *                                                                            *
950  * Author: Alexei Vladishev                                                   *
951  *                                                                            *
952  * Comments: ATTENTION! This function's address and pointers to arguments     *
953  *           are described in Zabbix defined type "zbx_process_value_func_t"  *
954  *           and used when calling process_log(), process_logrt() and         *
955  *           zbx_read2(). If you ever change this process_value() arguments   *
956  *           or return value do not forget to synchronize changes with the    *
957  *           defined type "zbx_process_value_func_t" and implementations of   *
958  *           process_log(), process_logrt(), zbx_read2() and their callers.   *
959  *                                                                            *
960  ******************************************************************************/
process_value(const char * server,unsigned short port,const char * host,const char * key,const char * value,unsigned char state,zbx_uint64_t * lastlogsize,const int * mtime,unsigned long * timestamp,const char * source,unsigned short * severity,unsigned long * logeventid,unsigned char flags)961 static int	process_value(const char *server, unsigned short port, const char *host, const char *key,
962 		const char *value, unsigned char state, zbx_uint64_t *lastlogsize, const int *mtime,
963 		unsigned long *timestamp, const char *source, unsigned short *severity, unsigned long *logeventid,
964 		unsigned char flags)
965 {
966 	const char			*__function_name = "process_value";
967 	ZBX_ACTIVE_BUFFER_ELEMENT	*el = NULL;
968 	int				i, ret = FAIL;
969 	size_t				sz;
970 
971 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
972 	{
973 		if (NULL != lastlogsize)
974 		{
975 			zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s:%s' lastlogsize:" ZBX_FS_UI64 " value:'%s'",
976 					__function_name, host, key, *lastlogsize, ZBX_NULL2STR(value));
977 		}
978 		else
979 		{
980 			/* log a dummy lastlogsize to keep the same record format for simpler parsing */
981 			zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s:%s' lastlogsize:null value:'%s'",
982 					__function_name, host, key, ZBX_NULL2STR(value));
983 		}
984 	}
985 
986 	/* do not sent data from buffer if host/key are the same as previous unless buffer is full already */
987 	if (0 < buffer.count)
988 	{
989 		el = &buffer.data[buffer.count - 1];
990 
991 		if ((0 != (flags & ZBX_METRIC_FLAG_PERSISTENT) && CONFIG_BUFFER_SIZE / 2 <= buffer.pcount) ||
992 				CONFIG_BUFFER_SIZE <= buffer.count ||
993 				0 != strcmp(el->key, key) || 0 != strcmp(el->host, host))
994 		{
995 			send_buffer(server, port);
996 		}
997 	}
998 
999 	if (0 != (ZBX_METRIC_FLAG_PERSISTENT & flags) && CONFIG_BUFFER_SIZE / 2 <= buffer.pcount)
1000 	{
1001 		zabbix_log(LOG_LEVEL_WARNING, "buffer is full, cannot store persistent value");
1002 		goto out;
1003 	}
1004 
1005 	if (CONFIG_BUFFER_SIZE > buffer.count)
1006 	{
1007 		zabbix_log(LOG_LEVEL_DEBUG, "buffer: new element %d", buffer.count);
1008 		el = &buffer.data[buffer.count];
1009 		buffer.count++;
1010 	}
1011 	else
1012 	{
1013 		if (0 == (ZBX_METRIC_FLAG_PERSISTENT & flags))
1014 		{
1015 			for (i = 0; i < buffer.count; i++)
1016 			{
1017 				el = &buffer.data[i];
1018 				if (0 == strcmp(el->host, host) && 0 == strcmp(el->key, key))
1019 					break;
1020 			}
1021 		}
1022 
1023 		if (0 != (ZBX_METRIC_FLAG_PERSISTENT & flags) || i == buffer.count)
1024 		{
1025 			for (i = 0; i < buffer.count; i++)
1026 			{
1027 				el = &buffer.data[i];
1028 				if (0 == (ZBX_METRIC_FLAG_PERSISTENT & el->flags))
1029 					break;
1030 			}
1031 		}
1032 
1033 		if (NULL != el)
1034 		{
1035 			zabbix_log(LOG_LEVEL_DEBUG, "remove element [%d] Key:'%s:%s'", i, el->host, el->key);
1036 
1037 			zbx_free(el->host);
1038 			zbx_free(el->key);
1039 			zbx_free(el->value);
1040 			zbx_free(el->source);
1041 		}
1042 
1043 		sz = (CONFIG_BUFFER_SIZE - i - 1) * sizeof(ZBX_ACTIVE_BUFFER_ELEMENT);
1044 		memmove(&buffer.data[i], &buffer.data[i + 1], sz);
1045 
1046 		zabbix_log(LOG_LEVEL_DEBUG, "buffer full: new element %d", buffer.count - 1);
1047 
1048 		el = &buffer.data[CONFIG_BUFFER_SIZE - 1];
1049 	}
1050 
1051 	memset(el, 0, sizeof(ZBX_ACTIVE_BUFFER_ELEMENT));
1052 	el->host = zbx_strdup(NULL, host);
1053 	el->key = zbx_strdup(NULL, key);
1054 	if (NULL != value)
1055 		el->value = zbx_strdup(NULL, value);
1056 	el->state = state;
1057 
1058 	if (NULL != source)
1059 		el->source = strdup(source);
1060 	if (NULL != severity)
1061 		el->severity = *severity;
1062 	if (NULL != lastlogsize)
1063 		el->lastlogsize = *lastlogsize;
1064 	if (NULL != mtime)
1065 		el->mtime = *mtime;
1066 	if (NULL != timestamp)
1067 		el->timestamp = *timestamp;
1068 	if (NULL != logeventid)
1069 		el->logeventid = (int)*logeventid;
1070 
1071 	zbx_timespec(&el->ts);
1072 	el->flags = flags;
1073 	el->id = ++last_valueid;
1074 
1075 	if (0 != (ZBX_METRIC_FLAG_PERSISTENT & flags))
1076 		buffer.pcount++;
1077 
1078 	ret = SUCCEED;
1079 out:
1080 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1081 
1082 	return ret;
1083 }
1084 
need_meta_update(ZBX_ACTIVE_METRIC * metric,zbx_uint64_t lastlogsize_sent,int mtime_sent,unsigned char old_state,zbx_uint64_t lastlogsize_last,int mtime_last)1085 static int	need_meta_update(ZBX_ACTIVE_METRIC *metric, zbx_uint64_t lastlogsize_sent, int mtime_sent,
1086 		unsigned char old_state, zbx_uint64_t lastlogsize_last, int mtime_last)
1087 {
1088 	const char	*__function_name = "need_meta_update";
1089 
1090 	int		ret = FAIL;
1091 
1092 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:%s", __function_name, metric->key);
1093 
1094 	if (0 != (ZBX_METRIC_FLAG_LOG & metric->flags))
1095 	{
1096 		/* meta information update is needed if:                                              */
1097 		/* - lastlogsize or mtime changed since we last sent within this check                */
1098 		/* - nothing was sent during this check and state changed from notsupported to normal */
1099 		/* - nothing was sent during this check and it's a new metric                         */
1100 		if (lastlogsize_sent != metric->lastlogsize || mtime_sent != metric->mtime ||
1101 				(lastlogsize_last == lastlogsize_sent && mtime_last == mtime_sent &&
1102 						(old_state != metric->state ||
1103 						0 != (ZBX_METRIC_FLAG_NEW & metric->flags))))
1104 		{
1105 			/* needs meta information update */
1106 			ret = SUCCEED;
1107 		}
1108 	}
1109 
1110 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1111 
1112 	return ret;
1113 }
1114 
check_number_of_parameters(unsigned char flags,const AGENT_REQUEST * request,char ** error)1115 static int	check_number_of_parameters(unsigned char flags, const AGENT_REQUEST *request, char **error)
1116 {
1117 	int	parameter_num, max_parameter_num;
1118 
1119 	if (0 == (parameter_num = get_rparams_num(request)))
1120 	{
1121 		*error = zbx_strdup(*error, "Invalid number of parameters.");
1122 		return FAIL;
1123 	}
1124 
1125 	if (0 != (ZBX_METRIC_FLAG_LOG_COUNT & flags))
1126 		max_parameter_num = 7;	/* log.count or logrt.count */
1127 	else
1128 		max_parameter_num = 8;	/* log or logrt */
1129 
1130 	if (max_parameter_num < parameter_num)
1131 	{
1132 		*error = zbx_strdup(*error, "Too many parameters.");
1133 		return FAIL;
1134 	}
1135 
1136 	return SUCCEED;
1137 }
1138 
init_max_lines_per_sec(int is_count_item,const AGENT_REQUEST * request,int * max_lines_per_sec,char ** error)1139 static int	init_max_lines_per_sec(int is_count_item, const AGENT_REQUEST *request, int *max_lines_per_sec,
1140 		char **error)
1141 {
1142 	const char	*p;
1143 	int		rate;
1144 
1145 	if (NULL == (p = get_rparam(request, 3)) || '\0' == *p)
1146 	{
1147 		if (0 == is_count_item)				/* log[], logrt[] */
1148 			*max_lines_per_sec = CONFIG_MAX_LINES_PER_SECOND;
1149 		else						/* log.count[], logrt.count[] */
1150 			*max_lines_per_sec = MAX_VALUE_LINES_MULTIPLIER * CONFIG_MAX_LINES_PER_SECOND;
1151 
1152 		return SUCCEED;
1153 	}
1154 
1155 	if (MIN_VALUE_LINES > (rate = atoi(p)) ||
1156 			(0 == is_count_item && MAX_VALUE_LINES < rate) ||
1157 			(0 != is_count_item && MAX_VALUE_LINES_MULTIPLIER * MAX_VALUE_LINES < rate))
1158 	{
1159 		*error = zbx_strdup(*error, "Invalid fourth parameter.");
1160 		return FAIL;
1161 	}
1162 
1163 	*max_lines_per_sec = rate;
1164 	return SUCCEED;
1165 }
1166 
init_max_delay(int is_count_item,const AGENT_REQUEST * request,float * max_delay,char ** error)1167 static int	init_max_delay(int is_count_item, const AGENT_REQUEST *request, float *max_delay, char **error)
1168 {
1169 	const char	*max_delay_str;
1170 	double		max_delay_tmp;
1171 	int		max_delay_par_nr;
1172 
1173 	/* <maxdelay> is parameter 6 for log[], logrt[], but parameter 5 for log.count[], logrt.count[] */
1174 
1175 	if (0 == is_count_item)
1176 		max_delay_par_nr = 6;
1177 	else
1178 		max_delay_par_nr = 5;
1179 
1180 	if (NULL == (max_delay_str = get_rparam(request, max_delay_par_nr)) || '\0' == *max_delay_str)
1181 	{
1182 		*max_delay = 0.0f;
1183 		return SUCCEED;
1184 	}
1185 
1186 	if (SUCCEED != is_double(max_delay_str, &max_delay_tmp) || 0.0 > max_delay_tmp)
1187 	{
1188 		*error = zbx_dsprintf(*error, "Invalid %s parameter.", (5 == max_delay_par_nr) ? "sixth" : "seventh");
1189 		return FAIL;
1190 	}
1191 
1192 	*max_delay = (float)max_delay_tmp;
1193 	return SUCCEED;
1194 }
1195 
init_rotation_type(unsigned char flags,const AGENT_REQUEST * request,zbx_log_rotation_options_t * rotation_type,char ** error)1196 static int	init_rotation_type(unsigned char flags, const AGENT_REQUEST *request,
1197 		zbx_log_rotation_options_t *rotation_type, char **error)
1198 {
1199 	char	*options;
1200 	int	options_par_nr;
1201 
1202 	if (0 == (ZBX_METRIC_FLAG_LOG_COUNT & flags))	/* log, logrt */
1203 		options_par_nr = 7;
1204 	else						/* log.count, logrt.count */
1205 		options_par_nr = 6;
1206 
1207 	options = get_rparam(request, options_par_nr);
1208 
1209 	if (NULL == options || '\0' == *options)	/* default options */
1210 	{
1211 		if (0 != (ZBX_METRIC_FLAG_LOG_LOGRT & flags))
1212 			*rotation_type = ZBX_LOG_ROTATION_LOGRT;
1213 		else
1214 			*rotation_type = ZBX_LOG_ROTATION_REREAD;
1215 	}
1216 	else
1217 	{
1218 		if (0 != (ZBX_METRIC_FLAG_LOG_LOGRT & flags))	/* logrt, logrt.count */
1219 		{
1220 			if (0 == strcmp(options, "copytruncate"))
1221 				*rotation_type = ZBX_LOG_ROTATION_LOGCPT;
1222 			else if (0 == strcmp(options, "rotate") || 0 == strcmp(options, "mtime-reread"))
1223 				*rotation_type = ZBX_LOG_ROTATION_LOGRT;
1224 			else if (0 == strcmp(options, "mtime-noreread"))
1225 				*rotation_type = ZBX_LOG_ROTATION_NO_REREAD;
1226 			else
1227 				goto err;
1228 		}
1229 		else	/* log, log.count */
1230 		{
1231 			if (0 == strcmp(options, "mtime-reread"))
1232 				*rotation_type = ZBX_LOG_ROTATION_REREAD;
1233 			else if (0 == strcmp(options, "mtime-noreread"))
1234 				*rotation_type = ZBX_LOG_ROTATION_NO_REREAD;
1235 			else
1236 				goto err;
1237 		}
1238 	}
1239 
1240 	return SUCCEED;
1241 err:
1242 	*error = zbx_strdup(*error, "Invalid parameter \"options\".");
1243 
1244 	return FAIL;
1245 }
1246 
process_log_check(char * server,unsigned short port,ZBX_ACTIVE_METRIC * metric,zbx_uint64_t * lastlogsize_sent,int * mtime_sent,char ** error)1247 static int	process_log_check(char *server, unsigned short port, ZBX_ACTIVE_METRIC *metric,
1248 		zbx_uint64_t *lastlogsize_sent, int *mtime_sent, char **error)
1249 {
1250 	AGENT_REQUEST			request;
1251 	const char			*filename, *regexp, *encoding, *skip, *output_template;
1252 	char				*encoding_uc = NULL;
1253 	int				max_lines_per_sec, ret = FAIL, s_count, p_count, s_count_orig, is_count_item,
1254 					mtime_orig, big_rec_orig, logfiles_num_new = 0, jumped = 0;
1255 	zbx_log_rotation_options_t	rotation_type;
1256 	zbx_uint64_t			lastlogsize_orig;
1257 	float				max_delay;
1258 	struct st_logfile		*logfiles_new = NULL;
1259 
1260 	if (0 != (ZBX_METRIC_FLAG_LOG_COUNT & metric->flags))
1261 		is_count_item = 1;
1262 	else
1263 		is_count_item = 0;
1264 
1265 	init_request(&request);
1266 
1267 	/* Expected parameters by item: */
1268 	/* log        [file,       <regexp>,<encoding>,<maxlines>,    <mode>,<output>,<maxdelay>, <options>] 8 params */
1269 	/* log.count  [file,       <regexp>,<encoding>,<maxproclines>,<mode>,         <maxdelay>, <options>] 7 params */
1270 	/* logrt      [file_regexp,<regexp>,<encoding>,<maxlines>,    <mode>,<output>,<maxdelay>, <options>] 8 params */
1271 	/* logrt.count[file_regexp,<regexp>,<encoding>,<maxproclines>,<mode>,         <maxdelay>, <options>] 7 params */
1272 
1273 	if (SUCCEED != parse_item_key(metric->key, &request))
1274 	{
1275 		*error = zbx_strdup(*error, "Invalid item key format.");
1276 		goto out;
1277 	}
1278 
1279 	if (SUCCEED != check_number_of_parameters(metric->flags, &request, error))
1280 		goto out;
1281 
1282 	/* parameter 'file' or 'file_regexp' */
1283 
1284 	if (NULL == (filename = get_rparam(&request, 0)) || '\0' == *filename)
1285 	{
1286 		*error = zbx_strdup(*error, "Invalid first parameter.");
1287 		goto out;
1288 	}
1289 
1290 	/* parameter 'regexp' */
1291 
1292 	if (NULL == (regexp = get_rparam(&request, 1)))
1293 	{
1294 		regexp = "";
1295 	}
1296 	else if ('@' == *regexp && SUCCEED != zbx_global_regexp_exists(regexp + 1, &regexps))
1297 	{
1298 		*error = zbx_dsprintf(*error, "Global regular expression \"%s\" does not exist.", regexp + 1);
1299 		goto out;
1300 	}
1301 
1302 	/* parameter 'encoding' */
1303 
1304 	if (NULL == (encoding = get_rparam(&request, 2)))
1305 	{
1306 		encoding = "";
1307 	}
1308 	else
1309 	{
1310 		encoding_uc = zbx_strdup(encoding_uc, encoding);
1311 		zbx_strupper(encoding_uc);
1312 		encoding = encoding_uc;
1313 	}
1314 
1315 	/* parameter 'maxlines' or 'maxproclines' */
1316 	if (SUCCEED !=  init_max_lines_per_sec(is_count_item, &request, &max_lines_per_sec, error))
1317 		goto out;
1318 
1319 	/* parameter 'mode' */
1320 
1321 	if (NULL == (skip = get_rparam(&request, 4)) || '\0' == *skip || 0 == strcmp(skip, "all"))
1322 	{
1323 		metric->skip_old_data = 0;
1324 	}
1325 	else if (0 != strcmp(skip, "skip"))
1326 	{
1327 		*error = zbx_strdup(*error, "Invalid fifth parameter.");
1328 		goto out;
1329 	}
1330 
1331 	/* parameter 'output' (not used for log.count[], logrt.count[]) */
1332 	if (0 != is_count_item || (NULL == (output_template = get_rparam(&request, 5))))
1333 		output_template = "";
1334 
1335 	/* parameter 'maxdelay' */
1336 	if (SUCCEED != init_max_delay(is_count_item, &request, &max_delay, error))
1337 		goto out;
1338 
1339 	/* parameter 'options' */
1340 	if (SUCCEED != init_rotation_type(metric->flags, &request, &rotation_type, error))
1341 		goto out;
1342 
1343 	/* jumping over fast growing log files is not supported with 'copytruncate' */
1344 	if (ZBX_LOG_ROTATION_LOGCPT == rotation_type && 0.0f != max_delay)
1345 	{
1346 		*error = zbx_strdup(*error, "maxdelay > 0 is not supported with copytruncate option.");
1347 		goto out;
1348 	}
1349 
1350 	/* do not flood Zabbix server if file grows too fast */
1351 	s_count = max_lines_per_sec * metric->refresh;
1352 
1353 	/* do not flood local system if file grows too fast */
1354 	if (0 == is_count_item)
1355 	{
1356 		p_count = MAX_VALUE_LINES_MULTIPLIER * s_count;	/* log[], logrt[] */
1357 	}
1358 	else
1359 	{
1360 		/* In log.count[] and logrt.count[] items the variable 's_count' (max number of lines allowed to be */
1361 		/* sent to server) is used for counting matching lines in logfile(s). 's_count' is counted from max */
1362 		/* value down towards 0. */
1363 
1364 		p_count = s_count_orig = s_count;
1365 
1366 		/* remember current state, we may need to restore it if log.count[] or logrt.count[] result cannot */
1367 		/* be sent to server */
1368 
1369 		lastlogsize_orig = metric->lastlogsize;
1370 		mtime_orig = metric->mtime;
1371 		big_rec_orig = metric->big_rec;
1372 
1373 		/* process_logrt() may modify old log file list 'metric->logfiles' but currently modifications are */
1374 		/* limited to 'retry' flag in existing list elements. We do not preserve original 'retry' flag values */
1375 		/* as there is no need to "rollback" their modifications if log.count[] or logrt.count[] result can */
1376 		/* not be sent to server. */
1377 	}
1378 
1379 	ret = process_logrt(metric->flags, filename, &metric->lastlogsize, &metric->mtime, lastlogsize_sent, mtime_sent,
1380 			&metric->skip_old_data, &metric->big_rec, &metric->use_ino, error, &metric->logfiles,
1381 			&metric->logfiles_num, &logfiles_new, &logfiles_num_new, encoding, &regexps, regexp,
1382 			output_template, &p_count, &s_count, process_value, server, port, CONFIG_HOSTNAME,
1383 			metric->key_orig, &jumped, max_delay, &metric->start_time, &metric->processed_bytes,
1384 			rotation_type);
1385 
1386 	if (0 == is_count_item && NULL != logfiles_new)
1387 	{
1388 		/* for log[] and logrt[] items - switch to the new log file list */
1389 
1390 		destroy_logfile_list(&metric->logfiles, NULL, &metric->logfiles_num);
1391 		metric->logfiles = logfiles_new;
1392 		metric->logfiles_num = logfiles_num_new;
1393 	}
1394 
1395 	if (SUCCEED == ret)
1396 	{
1397 		metric->error_count = 0;
1398 
1399 		if (0 != is_count_item)
1400 		{
1401 			/* send log.count[] or logrt.count[] item value to server */
1402 
1403 			int	match_count;			/* number of matching lines */
1404 			char	buf[ZBX_MAX_UINT64_LEN];
1405 
1406 			match_count = s_count_orig - s_count;
1407 
1408 			zbx_snprintf(buf, sizeof(buf), "%d", match_count);
1409 
1410 			if (SUCCEED == process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, buf,
1411 					ITEM_STATE_NORMAL, &metric->lastlogsize, &metric->mtime, NULL, NULL, NULL, NULL,
1412 					metric->flags | ZBX_METRIC_FLAG_PERSISTENT) || 0 != jumped)
1413 			{
1414 				/* if process_value() fails (i.e. log(rt).count result cannot be sent to server) but */
1415 				/* a jump took place to meet <maxdelay> then we discard the result and keep the state */
1416 				/* after jump */
1417 
1418 				*lastlogsize_sent = metric->lastlogsize;
1419 				*mtime_sent = metric->mtime;
1420 
1421 				/* switch to the new log file list */
1422 				destroy_logfile_list(&metric->logfiles, NULL, &metric->logfiles_num);
1423 				metric->logfiles = logfiles_new;
1424 				metric->logfiles_num = logfiles_num_new;
1425 			}
1426 			else
1427 			{
1428 				/* unable to send data and no jump took place, restore original state to try again */
1429 				/* during the next check */
1430 
1431 				metric->lastlogsize = lastlogsize_orig;
1432 				metric->mtime =  mtime_orig;
1433 				metric->big_rec = big_rec_orig;
1434 
1435 				/* the old log file list 'metric->logfiles' stays in its place, drop the new list */
1436 				destroy_logfile_list(&logfiles_new, NULL, &logfiles_num_new);
1437 			}
1438 		}
1439 	}
1440 	else
1441 	{
1442 		metric->error_count++;
1443 
1444 		if (0 != is_count_item)
1445 		{
1446 			/* restore original state to try again during the next check */
1447 
1448 			metric->lastlogsize = lastlogsize_orig;
1449 			metric->mtime =  mtime_orig;
1450 			metric->big_rec = big_rec_orig;
1451 
1452 			/* the old log file list 'metric->logfiles' stays in its place, drop the new list */
1453 			destroy_logfile_list(&logfiles_new, NULL, &logfiles_num_new);
1454 		}
1455 
1456 		/* suppress first two errors */
1457 		if (3 > metric->error_count)
1458 		{
1459 			zabbix_log(LOG_LEVEL_DEBUG, "suppressing log(rt)(.count) processing error #%d: %s",
1460 					metric->error_count, NULL != *error ? *error : "unknown error");
1461 
1462 			zbx_free(*error);
1463 			ret = SUCCEED;
1464 		}
1465 	}
1466 out:
1467 	zbx_free(encoding_uc);
1468 	free_request(&request);
1469 
1470 	return ret;
1471 }
1472 
process_eventlog_check(char * server,unsigned short port,ZBX_ACTIVE_METRIC * metric,zbx_uint64_t * lastlogsize_sent,char ** error)1473 static int	process_eventlog_check(char *server, unsigned short port, ZBX_ACTIVE_METRIC *metric,
1474 		zbx_uint64_t *lastlogsize_sent, char **error)
1475 {
1476 	int 		ret = FAIL;
1477 
1478 #ifdef _WINDOWS
1479 	AGENT_REQUEST	request;
1480 	const char	*filename, *pattern, *maxlines_persec, *key_severity, *key_source, *key_logeventid, *skip;
1481 	int		rate;
1482 	OSVERSIONINFO	versionInfo;
1483 
1484 	init_request(&request);
1485 
1486 	if (SUCCEED != parse_item_key(metric->key, &request))
1487 	{
1488 		*error = zbx_strdup(*error, "Invalid item key format.");
1489 		goto out;
1490 	}
1491 
1492 	if (0 == get_rparams_num(&request))
1493 	{
1494 		*error = zbx_strdup(*error, "Invalid number of parameters.");
1495 		goto out;
1496 	}
1497 
1498 	if (7 < get_rparams_num(&request))
1499 	{
1500 		*error = zbx_strdup(*error, "Too many parameters.");
1501 		goto out;
1502 	}
1503 
1504 	if (NULL == (filename = get_rparam(&request, 0)) || '\0' == *filename)
1505 	{
1506 		*error = zbx_strdup(*error, "Invalid first parameter.");
1507 		goto out;
1508 	}
1509 
1510 	if (NULL == (pattern = get_rparam(&request, 1)))
1511 	{
1512 		pattern = "";
1513 	}
1514 	else if ('@' == *pattern && SUCCEED != zbx_global_regexp_exists(pattern + 1, &regexps))
1515 	{
1516 		*error = zbx_dsprintf(*error, "Global regular expression \"%s\" does not exist.", pattern + 1);
1517 		goto out;
1518 	}
1519 
1520 	if (NULL == (key_severity = get_rparam(&request, 2)))
1521 	{
1522 		key_severity = "";
1523 	}
1524 	else if ('@' == *key_severity && SUCCEED != zbx_global_regexp_exists(key_severity + 1, &regexps))
1525 	{
1526 		*error = zbx_dsprintf(*error, "Global regular expression \"%s\" does not exist.", key_severity + 1);
1527 		goto out;
1528 	}
1529 
1530 	if (NULL == (key_source = get_rparam(&request, 3)))
1531 	{
1532 		key_source = "";
1533 	}
1534 	else if ('@' == *key_source && SUCCEED != zbx_global_regexp_exists(key_source + 1, &regexps))
1535 	{
1536 		*error = zbx_dsprintf(*error, "Global regular expression \"%s\" does not exist.", key_source + 1);
1537 		goto out;
1538 	}
1539 
1540 	if (NULL == (key_logeventid = get_rparam(&request, 4)))
1541 	{
1542 		key_logeventid = "";
1543 	}
1544 	else if ('@' == *key_logeventid && SUCCEED != zbx_global_regexp_exists(key_logeventid + 1, &regexps))
1545 	{
1546 		*error = zbx_dsprintf(*error, "Global regular expression \"%s\" does not exist.", key_logeventid + 1);
1547 		goto out;
1548 	}
1549 
1550 	if (NULL == (maxlines_persec = get_rparam(&request, 5)) || '\0' == *maxlines_persec)
1551 	{
1552 		rate = CONFIG_MAX_LINES_PER_SECOND;
1553 	}
1554 	else if (MIN_VALUE_LINES > (rate = atoi(maxlines_persec)) || MAX_VALUE_LINES < rate)
1555 	{
1556 		*error = zbx_strdup(*error, "Invalid sixth parameter.");
1557 		goto out;
1558 	}
1559 
1560 	if (NULL == (skip = get_rparam(&request, 6)) || '\0' == *skip || 0 == strcmp(skip, "all"))
1561 	{
1562 		metric->skip_old_data = 0;
1563 	}
1564 	else if (0 != strcmp(skip, "skip"))
1565 	{
1566 		*error = zbx_strdup(*error, "Invalid seventh parameter.");
1567 		goto out;
1568 	}
1569 
1570 	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1571 	GetVersionEx(&versionInfo);
1572 
1573 	if (versionInfo.dwMajorVersion >= 6)	/* Windows Vista, 7 or Server 2008 */
1574 	{
1575 		__try
1576 		{
1577 			zbx_uint64_t	lastlogsize = metric->lastlogsize;
1578 			EVT_HANDLE	eventlog6_render_context = NULL;
1579 			EVT_HANDLE	eventlog6_query = NULL;
1580 			zbx_uint64_t	eventlog6_firstid = 0;
1581 			zbx_uint64_t	eventlog6_lastid = 0;
1582 
1583 			if (SUCCEED != initialize_eventlog6(filename, &lastlogsize, &eventlog6_firstid,
1584 					&eventlog6_lastid, &eventlog6_render_context, &eventlog6_query, error))
1585 			{
1586 				finalize_eventlog6(&eventlog6_render_context, &eventlog6_query);
1587 				goto out;
1588 			}
1589 
1590 			ret = process_eventslog6(server, port, filename, &eventlog6_render_context, &eventlog6_query,
1591 					lastlogsize, eventlog6_firstid, eventlog6_lastid, &regexps, pattern,
1592 					key_severity, key_source, key_logeventid, rate, process_value, metric,
1593 					lastlogsize_sent, error);
1594 
1595 			finalize_eventlog6(&eventlog6_render_context, &eventlog6_query);
1596 		}
1597 		__except (DelayLoadDllExceptionFilter(GetExceptionInformation()))
1598 		{
1599 			zabbix_log(LOG_LEVEL_WARNING, "failed to process eventlog");
1600 		}
1601 	}
1602 	else if (versionInfo.dwMajorVersion < 6)    /* Windows versions before Vista */
1603 	{
1604 		ret = process_eventslog(server, port, filename, &regexps, pattern, key_severity, key_source,
1605 				key_logeventid, rate, process_value, metric, lastlogsize_sent, error);
1606 	}
1607 out:
1608 	free_request(&request);
1609 #else	/* not _WINDOWS */
1610 	ZBX_UNUSED(server);
1611 	ZBX_UNUSED(port);
1612 	ZBX_UNUSED(metric);
1613 	ZBX_UNUSED(lastlogsize_sent);
1614 	ZBX_UNUSED(error);
1615 #endif	/* _WINDOWS */
1616 
1617 	return ret;
1618 }
1619 
process_common_check(char * server,unsigned short port,ZBX_ACTIVE_METRIC * metric,char ** error)1620 static int	process_common_check(char *server, unsigned short port, ZBX_ACTIVE_METRIC *metric, char **error)
1621 {
1622 	int		ret;
1623 	AGENT_RESULT	result;
1624 	char		**pvalue;
1625 
1626 	init_result(&result);
1627 
1628 	if (SUCCEED != (ret = process(metric->key, 0, &result)))
1629 	{
1630 		if (NULL != (pvalue = GET_MSG_RESULT(&result)))
1631 			*error = zbx_strdup(*error, *pvalue);
1632 		goto out;
1633 	}
1634 
1635 	if (NULL != (pvalue = GET_TEXT_RESULT(&result)))
1636 	{
1637 		zabbix_log(LOG_LEVEL_DEBUG, "for key [%s] received value [%s]", metric->key, *pvalue);
1638 
1639 		process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, *pvalue, ITEM_STATE_NORMAL, NULL, NULL,
1640 				NULL, NULL, NULL, NULL, metric->flags);
1641 	}
1642 out:
1643 	free_result(&result);
1644 
1645 	return ret;
1646 }
1647 
process_active_checks(char * server,unsigned short port)1648 static void	process_active_checks(char *server, unsigned short port)
1649 {
1650 	const char	*__function_name = "process_active_checks";
1651 	char		*error = NULL;
1652 	int		i, now, ret;
1653 
1654 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() server:'%s' port:%hu", __function_name, server, port);
1655 
1656 	now = (int)time(NULL);
1657 
1658 	for (i = 0; i < active_metrics.values_num; i++)
1659 	{
1660 		zbx_uint64_t		lastlogsize_last, lastlogsize_sent;
1661 		int			mtime_last, mtime_sent;
1662 		ZBX_ACTIVE_METRIC	*metric;
1663 
1664 		metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
1665 
1666 		if (metric->nextcheck > now)
1667 			continue;
1668 
1669 		if (SUCCEED != metric_ready_to_process(metric))
1670 			continue;
1671 
1672 		/* for meta information update we need to know if something was sent at all during the check */
1673 		lastlogsize_last = metric->lastlogsize;
1674 		mtime_last = metric->mtime;
1675 
1676 		lastlogsize_sent = metric->lastlogsize;
1677 		mtime_sent = metric->mtime;
1678 
1679 		/* before processing make sure refresh is not 0 to avoid overload */
1680 		if (0 == metric->refresh)
1681 		{
1682 			ret = FAIL;
1683 			error = zbx_strdup(error, "Incorrect update interval.");
1684 		}
1685 		else if (0 != ((ZBX_METRIC_FLAG_LOG_LOG | ZBX_METRIC_FLAG_LOG_LOGRT) & metric->flags))
1686 			ret = process_log_check(server, port, metric, &lastlogsize_sent, &mtime_sent, &error);
1687 		else if (0 != (ZBX_METRIC_FLAG_LOG_EVENTLOG & metric->flags))
1688 			ret = process_eventlog_check(server, port, metric, &lastlogsize_sent, &error);
1689 		else
1690 			ret = process_common_check(server, port, metric, &error);
1691 
1692 		if (SUCCEED != ret)
1693 		{
1694 			const char	*perror;
1695 
1696 			perror = (NULL != error ? error : ZBX_NOTSUPPORTED_MSG);
1697 
1698 			metric->state = ITEM_STATE_NOTSUPPORTED;
1699 			metric->refresh_unsupported = 0;
1700 			metric->error_count = 0;
1701 			metric->start_time = 0.0;
1702 			metric->processed_bytes = 0;
1703 
1704 			zabbix_log(LOG_LEVEL_WARNING, "active check \"%s\" is not supported: %s", metric->key, perror);
1705 
1706 			process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, perror, ITEM_STATE_NOTSUPPORTED,
1707 					&metric->lastlogsize, &metric->mtime, NULL, NULL, NULL, NULL, metric->flags);
1708 
1709 			zbx_free(error);
1710 		}
1711 		else
1712 		{
1713 			if (0 == metric->error_count)
1714 			{
1715 				unsigned char	old_state;
1716 
1717 				old_state = metric->state;
1718 
1719 				if (ITEM_STATE_NOTSUPPORTED == metric->state)
1720 				{
1721 					/* item became supported */
1722 					metric->state = ITEM_STATE_NORMAL;
1723 					metric->refresh_unsupported = 0;
1724 				}
1725 
1726 				if (SUCCEED == need_meta_update(metric, lastlogsize_sent, mtime_sent, old_state,
1727 						lastlogsize_last, mtime_last))
1728 				{
1729 					/* meta information update */
1730 					process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, NULL,
1731 							metric->state, &metric->lastlogsize, &metric->mtime, NULL, NULL,
1732 							NULL, NULL, metric->flags);
1733 				}
1734 
1735 				/* remove "new metric" flag */
1736 				metric->flags &= ~ZBX_METRIC_FLAG_NEW;
1737 			}
1738 		}
1739 
1740 		send_buffer(server, port);
1741 		metric->nextcheck = (int)time(NULL) + metric->refresh;
1742 	}
1743 
1744 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1745 }
1746 
1747 /******************************************************************************
1748  *                                                                            *
1749  * Function: update_schedule                                                  *
1750  *                                                                            *
1751  * Purpose: update active check and send buffer schedule by the specified     *
1752  *          time delta                                                        *
1753  *                                                                            *
1754  * Parameters: delta - [IN] the time delta in seconds                         *
1755  *                                                                            *
1756  * Comments: This function is used to update checking and sending schedules   *
1757  *           if the system time was rolled back.                              *
1758  *                                                                            *
1759  ******************************************************************************/
update_schedule(int delta)1760 static void	update_schedule(int delta)
1761 {
1762 	int	i;
1763 
1764 	for (i = 0; i < active_metrics.values_num; i++)
1765 	{
1766 		ZBX_ACTIVE_METRIC	*metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
1767 		metric->nextcheck += delta;
1768 	}
1769 
1770 	buffer.lastsent += delta;
1771 }
1772 
ZBX_THREAD_ENTRY(active_checks_thread,args)1773 ZBX_THREAD_ENTRY(active_checks_thread, args)
1774 {
1775 	ZBX_THREAD_ACTIVECHK_ARGS activechk_args;
1776 
1777 	time_t	nextcheck = 0, nextrefresh = 0, nextsend = 0, now, delta, lastcheck = 0;
1778 
1779 	assert(args);
1780 	assert(((zbx_thread_args_t *)args)->args);
1781 
1782 	process_type = ((zbx_thread_args_t *)args)->process_type;
1783 	server_num = ((zbx_thread_args_t *)args)->server_num;
1784 	process_num = ((zbx_thread_args_t *)args)->process_num;
1785 
1786 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
1787 			server_num, get_process_type_string(process_type), process_num);
1788 
1789 	activechk_args.host = zbx_strdup(NULL, ((ZBX_THREAD_ACTIVECHK_ARGS *)((zbx_thread_args_t *)args)->args)->host);
1790 	activechk_args.port = ((ZBX_THREAD_ACTIVECHK_ARGS *)((zbx_thread_args_t *)args)->args)->port;
1791 
1792 	zbx_free(args);
1793 
1794 	session_token = zbx_create_token(0);
1795 
1796 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1797 	zbx_tls_init_child();
1798 #endif
1799 	init_active_metrics();
1800 
1801 	while (ZBX_IS_RUNNING())
1802 	{
1803 		zbx_update_env(zbx_time());
1804 
1805 		if ((now = time(NULL)) >= nextsend)
1806 		{
1807 			send_buffer(activechk_args.host, activechk_args.port);
1808 			nextsend = time(NULL) + 1;
1809 		}
1810 
1811 		if (now >= nextrefresh)
1812 		{
1813 			zbx_setproctitle("active checks #%d [getting list of active checks]", process_num);
1814 
1815 			if (FAIL == refresh_active_checks(activechk_args.host, activechk_args.port))
1816 			{
1817 				nextrefresh = time(NULL) + 60;
1818 			}
1819 			else
1820 			{
1821 				nextrefresh = time(NULL) + CONFIG_REFRESH_ACTIVE_CHECKS;
1822 			}
1823 		}
1824 
1825 		if (now >= nextcheck && CONFIG_BUFFER_SIZE / 2 > buffer.pcount)
1826 		{
1827 			zbx_setproctitle("active checks #%d [processing active checks]", process_num);
1828 
1829 			process_active_checks(activechk_args.host, activechk_args.port);
1830 
1831 			if (CONFIG_BUFFER_SIZE / 2 <= buffer.pcount)	/* failed to complete processing active checks */
1832 				continue;
1833 
1834 			nextcheck = get_min_nextcheck();
1835 			if (FAIL == nextcheck)
1836 				nextcheck = time(NULL) + 60;
1837 		}
1838 		else
1839 		{
1840 			if (0 > (delta = now - lastcheck))
1841 			{
1842 				zabbix_log(LOG_LEVEL_WARNING, "the system time has been pushed back,"
1843 						" adjusting active check schedule");
1844 				update_schedule((int)delta);
1845 				nextcheck += delta;
1846 				nextsend += delta;
1847 				nextrefresh += delta;
1848 			}
1849 
1850 			zbx_setproctitle("active checks #%d [idle 1 sec]", process_num);
1851 			zbx_sleep(1);
1852 		}
1853 
1854 		lastcheck = now;
1855 	}
1856 
1857 	zbx_free(session_token);
1858 
1859 #ifdef _WINDOWS
1860 	zbx_free(activechk_args.host);
1861 	free_active_metrics();
1862 
1863 	ZBX_DO_EXIT();
1864 
1865 	zbx_thread_exit(EXIT_SUCCESS);
1866 #else
1867 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
1868 
1869 	while (1)
1870 		zbx_sleep(SEC_PER_MIN);
1871 #endif
1872 }
1873