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/logfiles.h"
28 #include "comms.h"
29 #include "threads.h"
30 #include "zbxjson.h"
31 #include "alias.h"
32 #include "metrics.h"
33 
34 extern unsigned char			program_type;
35 extern ZBX_THREAD_LOCAL unsigned char	process_type;
36 extern ZBX_THREAD_LOCAL int		server_num, process_num;
37 extern ZBX_THREAD_LOCAL char		*CONFIG_HOSTNAME;
38 
39 #if defined(ZABBIX_SERVICE)
40 #	include "service.h"
41 #elif defined(ZABBIX_DAEMON)
42 #	include "daemon.h"
43 #endif
44 
45 #include "zbxcrypto.h"
46 
47 static ZBX_THREAD_LOCAL ZBX_ACTIVE_BUFFER	buffer;
48 static ZBX_THREAD_LOCAL zbx_vector_ptr_t	active_metrics;
49 static ZBX_THREAD_LOCAL zbx_vector_ptr_t	regexps;
50 static ZBX_THREAD_LOCAL char			*session_token;
51 static ZBX_THREAD_LOCAL zbx_uint64_t		last_valueid = 0;
52 static ZBX_THREAD_LOCAL zbx_vector_pre_persistent_t	pre_persistent_vec;	/* used for staging of data going */
53 										/* into persistent files */
54 /* used for deleting inactive persistent files */
55 static ZBX_THREAD_LOCAL zbx_vector_persistent_inactive_t	persistent_inactive_vec;
56 
init_active_metrics(void)57 static void	init_active_metrics(void)
58 {
59 	size_t	sz;
60 
61 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
62 
63 	if (NULL == buffer.data)
64 	{
65 		zabbix_log(LOG_LEVEL_DEBUG, "buffer: first allocation for %d elements", CONFIG_BUFFER_SIZE);
66 		sz = (size_t)CONFIG_BUFFER_SIZE * sizeof(ZBX_ACTIVE_BUFFER_ELEMENT);
67 		buffer.data = (ZBX_ACTIVE_BUFFER_ELEMENT *)zbx_malloc(buffer.data, sz);
68 		memset(buffer.data, 0, sz);
69 		buffer.count = 0;
70 		buffer.pcount = 0;
71 		buffer.lastsent = (int)time(NULL);
72 		buffer.first_error = 0;
73 	}
74 
75 	zbx_vector_ptr_create(&active_metrics);
76 	zbx_vector_ptr_create(&regexps);
77 	zbx_vector_pre_persistent_create(&pre_persistent_vec);
78 	zbx_vector_persistent_inactive_create(&persistent_inactive_vec);
79 
80 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
81 }
82 
free_active_metric(ZBX_ACTIVE_METRIC * metric)83 static void	free_active_metric(ZBX_ACTIVE_METRIC *metric)
84 {
85 	int	i;
86 
87 	zbx_free(metric->key);
88 	zbx_free(metric->key_orig);
89 
90 	for (i = 0; i < metric->logfiles_num; i++)
91 		zbx_free(metric->logfiles[i].filename);
92 
93 	zbx_free(metric->logfiles);
94 #if !defined(_WINDOWS) && !defined(__MINGW32__)
95 	zbx_free(metric->persistent_file_name);
96 #endif
97 	zbx_free(metric);
98 }
99 
100 #ifdef _WINDOWS
free_active_metrics(void)101 static void	free_active_metrics(void)
102 {
103 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
104 
105 	zbx_regexp_clean_expressions(&regexps);
106 	zbx_vector_ptr_destroy(&regexps);
107 
108 	zbx_vector_ptr_clear_ext(&active_metrics, (zbx_clean_func_t)free_active_metric);
109 	zbx_vector_ptr_destroy(&active_metrics);
110 
111 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
112 }
113 #endif
114 
get_min_nextcheck(void)115 static int	get_min_nextcheck(void)
116 {
117 	int	i, min = -1;
118 
119 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
120 
121 	for (i = 0; i < active_metrics.values_num; i++)
122 	{
123 		const ZBX_ACTIVE_METRIC	*metric = (const ZBX_ACTIVE_METRIC *)active_metrics.values[i];
124 
125 		if (metric->nextcheck < min || -1 == min)
126 			min = metric->nextcheck;
127 	}
128 
129 	if (-1 == min)
130 		min = FAIL;
131 
132 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __func__, min);
133 
134 	return min;
135 }
136 
add_check(const char * key,const char * key_orig,int refresh,zbx_uint64_t lastlogsize,int mtime)137 static void	add_check(const char *key, const char *key_orig, int refresh, zbx_uint64_t lastlogsize, int mtime)
138 {
139 	ZBX_ACTIVE_METRIC	*metric;
140 	int			i;
141 
142 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s' refresh:%d lastlogsize:" ZBX_FS_UI64 " mtime:%d",
143 			__func__, key, refresh, lastlogsize, mtime);
144 
145 	for (i = 0; i < active_metrics.values_num; i++)
146 	{
147 		metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
148 
149 		if (0 != strcmp(metric->key_orig, key_orig))
150 			continue;
151 
152 		if (0 != strcmp(metric->key, key))
153 		{
154 			int	j;
155 
156 			zbx_free(metric->key);
157 			metric->key = zbx_strdup(NULL, key);
158 			metric->lastlogsize = lastlogsize;
159 			metric->mtime = mtime;
160 			metric->big_rec = 0;
161 			metric->use_ino = 0;
162 			metric->error_count = 0;
163 
164 			for (j = 0; j < metric->logfiles_num; j++)
165 				zbx_free(metric->logfiles[j].filename);
166 
167 			zbx_free(metric->logfiles);
168 			metric->logfiles_num = 0;
169 			metric->start_time = 0.0;
170 			metric->processed_bytes = 0;
171 #if !defined(_WINDOWS) && !defined(__MINGW32__)
172 			if (NULL != metric->persistent_file_name)
173 			{
174 				char	*error = NULL;
175 
176 				zabbix_log(LOG_LEVEL_DEBUG, "%s() removing persistent file '%s'",
177 						__func__, metric->persistent_file_name);
178 
179 				zbx_remove_from_persistent_inactive_list(&persistent_inactive_vec, metric->key_orig);
180 
181 				if (SUCCEED != zbx_remove_persistent_file(metric->persistent_file_name, &error))
182 				{
183 					/* log error and continue operation */
184 					zabbix_log(LOG_LEVEL_WARNING, "cannot remove persistent file \"%s\": %s",
185 							metric->persistent_file_name, error);
186 					zbx_free(error);
187 				}
188 
189 				zbx_free(metric->persistent_file_name);
190 			}
191 #endif
192 		}
193 #if !defined(_WINDOWS) && !defined(__MINGW32__)
194 		else if (NULL != metric->persistent_file_name)
195 		{
196 			/* the metric is active, but it could have been placed on inactive list earlier */
197 			zbx_remove_from_persistent_inactive_list(&persistent_inactive_vec, metric->key_orig);
198 		}
199 #endif
200 		/* replace metric */
201 		if (metric->refresh != refresh)
202 		{
203 			metric->nextcheck = 0;
204 			metric->refresh = refresh;
205 		}
206 
207 		goto out;
208 	}
209 
210 	metric = (ZBX_ACTIVE_METRIC *)zbx_malloc(NULL, sizeof(ZBX_ACTIVE_METRIC));
211 
212 	/* add new metric */
213 	metric->key = zbx_strdup(NULL, key);
214 	metric->key_orig = zbx_strdup(NULL, key_orig);
215 	metric->refresh = refresh;
216 	metric->nextcheck = 0;
217 	metric->state = ITEM_STATE_NORMAL;
218 	metric->lastlogsize = lastlogsize;
219 	metric->mtime = mtime;
220 	/* existing log[], log.count[] and eventlog[] data can be skipped */
221 	metric->skip_old_data = (0 != metric->lastlogsize ? 0 : 1);
222 	metric->big_rec = 0;
223 	metric->use_ino = 0;
224 	metric->error_count = 0;
225 	metric->logfiles_num = 0;
226 	metric->logfiles = NULL;
227 	metric->flags = ZBX_METRIC_FLAG_NEW;
228 
229 	if ('l' == metric->key[0] && 'o' == metric->key[1] && 'g' == metric->key[2])
230 	{
231 		if ('[' == metric->key[3])					/* log[ */
232 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOG;
233 		else if (0 == strncmp(metric->key + 3, "rt[", 3))		/* logrt[ */
234 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOGRT;
235 		else if (0 == strncmp(metric->key + 3, ".count[", 7))		/* log.count[ */
236 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOG | ZBX_METRIC_FLAG_LOG_COUNT;
237 		else if (0 == strncmp(metric->key + 3, "rt.count[", 9))		/* logrt.count[ */
238 			metric->flags |= ZBX_METRIC_FLAG_LOG_LOGRT | ZBX_METRIC_FLAG_LOG_COUNT;
239 	}
240 	else if (0 == strncmp(metric->key, "eventlog[", 9))
241 		metric->flags |= ZBX_METRIC_FLAG_LOG_EVENTLOG;
242 
243 	metric->start_time = 0.0;
244 	metric->processed_bytes = 0;
245 	metric->persistent_file_name = NULL;	/* initialized but not used on Microsoft Windows */
246 
247 	zbx_vector_ptr_append(&active_metrics, metric);
248 out:
249 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
250 }
251 
252 /******************************************************************************
253  *                                                                            *
254  * Function: mode_parameter_is_skip                                           *
255  *                                                                            *
256  * Purpose: test log[] or log.count[] item key if <mode> parameter is set to  *
257  *          'skip'                                                            *
258  *                                                                            *
259  * Return value: SUCCEED - <mode> parameter is set to 'skip'                  *
260  *               FAIL - <mode> is not 'skip' or error                         *
261  *                                                                            *
262  ******************************************************************************/
mode_parameter_is_skip(unsigned char flags,const char * itemkey)263 static int	mode_parameter_is_skip(unsigned char flags, const char *itemkey)
264 {
265 	AGENT_REQUEST	request;
266 	const char	*skip;
267 	int		ret = FAIL, max_num_parameters;
268 
269 	if (0 == (ZBX_METRIC_FLAG_LOG_COUNT & flags))	/* log[] */
270 		max_num_parameters = 7;
271 	else						/* log.count[] */
272 		max_num_parameters = 6;
273 
274 	init_request(&request);
275 
276 	if (SUCCEED == parse_item_key(itemkey, &request) && 0 < get_rparams_num(&request) &&
277 			max_num_parameters >= get_rparams_num(&request) && NULL != (skip = get_rparam(&request, 4)) &&
278 			0 == strcmp(skip, "skip"))
279 	{
280 		ret = SUCCEED;
281 	}
282 
283 	free_request(&request);
284 
285 	return ret;
286 }
287 
288 /******************************************************************************
289  *                                                                            *
290  * Function: parse_list_of_checks                                             *
291  *                                                                            *
292  * Purpose: Parse list of active checks received from server                  *
293  *                                                                            *
294  * Parameters: str  - NULL terminated string received from server             *
295  *             host - address of host                                         *
296  *             port - port number on host                                     *
297  *                                                                            *
298  * Return value: returns SUCCEED on successful parsing,                       *
299  *               FAIL on an incorrect format of string                        *
300  *                                                                            *
301  * Author: Eugene Grigorjev, Alexei Vladishev (new json protocol)             *
302  *                                                                            *
303  * Comments:                                                                  *
304  *    String represented as "ZBX_EOF" termination list                        *
305  *    With '\n' delimiter between elements.                                   *
306  *    Each element represented as:                                            *
307  *           <key>:<refresh time>:<last log size>:<modification time>         *
308  *                                                                            *
309  ******************************************************************************/
parse_list_of_checks(char * str,const char * host,unsigned short port)310 static int	parse_list_of_checks(char *str, const char *host, unsigned short port)
311 {
312 	const char		*p;
313 	size_t			name_alloc = 0, key_orig_alloc = 0;
314 	char			*name = NULL, *key_orig = NULL, expression[MAX_STRING_LEN],
315 				tmp[MAX_STRING_LEN], exp_delimiter;
316 	zbx_uint64_t		lastlogsize;
317 	struct zbx_json_parse	jp;
318 	struct zbx_json_parse	jp_data, jp_row;
319 	ZBX_ACTIVE_METRIC	*metric;
320 	zbx_vector_str_t	received_metrics;
321 	int			delay, mtime, expression_type, case_sensitive, i, j, ret = FAIL;
322 
323 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
324 
325 	zbx_vector_str_create(&received_metrics);
326 
327 	if (SUCCEED != zbx_json_open(str, &jp))
328 	{
329 		zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
330 		goto out;
331 	}
332 
333 	if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, tmp, sizeof(tmp), NULL))
334 	{
335 		zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
336 		goto out;
337 	}
338 
339 	if (0 != strcmp(tmp, ZBX_PROTO_VALUE_SUCCESS))
340 	{
341 		if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_INFO, tmp, sizeof(tmp), NULL))
342 			zabbix_log(LOG_LEVEL_WARNING, "no active checks on server [%s:%hu]: %s", host, port, tmp);
343 		else
344 			zabbix_log(LOG_LEVEL_WARNING, "no active checks on server");
345 
346 		goto out;
347 	}
348 
349 	if (SUCCEED != zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
350 	{
351 		zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
352 		goto out;
353 	}
354 
355  	p = NULL;
356 	while (NULL != (p = zbx_json_next(&jp_data, p)))
357 	{
358 /* {"data":[{"key":"system.cpu.num",...,...},{...},...]}
359  *          ^------------------------------^
360  */ 		if (SUCCEED != zbx_json_brackets_open(p, &jp_row))
361 		{
362 			zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
363 			goto out;
364 		}
365 
366 		if (SUCCEED != zbx_json_value_by_name_dyn(&jp_row, ZBX_PROTO_TAG_KEY, &name, &name_alloc, NULL) ||
367 				'\0' == *name)
368 		{
369 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_KEY);
370 			continue;
371 		}
372 
373 		if (SUCCEED != zbx_json_value_by_name_dyn(&jp_row, ZBX_PROTO_TAG_KEY_ORIG, &key_orig, &key_orig_alloc,
374 				NULL) || '\0' == *key_orig)
375 		{
376 			size_t offset = 0;
377 			zbx_strcpy_alloc(&key_orig, &key_orig_alloc, &offset, name);
378 		}
379 
380 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_DELAY, tmp, sizeof(tmp), NULL) ||
381 				'\0' == *tmp)
382 		{
383 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_DELAY);
384 			continue;
385 		}
386 
387 		delay = atoi(tmp);
388 
389 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_LASTLOGSIZE, tmp, sizeof(tmp), NULL) ||
390 				SUCCEED != is_uint64(tmp, &lastlogsize))
391 		{
392 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_LASTLOGSIZE);
393 			continue;
394 		}
395 
396 		if (SUCCEED != zbx_json_value_by_name(&jp_row, ZBX_PROTO_TAG_MTIME, tmp, sizeof(tmp), NULL) ||
397 				'\0' == *tmp)
398 		{
399 			zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", ZBX_PROTO_TAG_MTIME);
400 			mtime = 0;
401 		}
402 		else
403 			mtime = atoi(tmp);
404 
405 		add_check(zbx_alias_get(name), key_orig, delay, lastlogsize, mtime);
406 
407 		/* remember what was received */
408 		zbx_vector_str_append(&received_metrics, zbx_strdup(NULL, key_orig));
409 	}
410 
411 	/* remove what wasn't received */
412 	for (i = 0; i < active_metrics.values_num; i++)
413 	{
414 		int	found = 0;
415 
416 		metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
417 
418 		/* 'Do-not-delete' exception for log[] and log.count[] items with <mode> parameter set to 'skip'. */
419 		/* We need to keep their state, namely 'skip_old_data', in case the items become NOTSUPPORTED as */
420 		/* server might not send them in a new active check list. */
421 
422 		if (0 != (ZBX_METRIC_FLAG_LOG_LOG & metric->flags) && ITEM_STATE_NOTSUPPORTED == metric->state &&
423 				0 == metric->skip_old_data && SUCCEED == mode_parameter_is_skip(metric->flags,
424 				metric->key))
425 		{
426 			continue;
427 		}
428 
429 		for (j = 0; j < received_metrics.values_num; j++)
430 		{
431 			if (0 == strcmp(metric->key_orig, received_metrics.values[j]))
432 			{
433 				found = 1;
434 				break;
435 			}
436 		}
437 
438 		if (0 == found)
439 		{
440 #if !defined(_WINDOWS) && !defined(__MINGW32__)
441 			if (NULL != metric->persistent_file_name)
442 			{
443 				zbx_add_to_persistent_inactive_list(&persistent_inactive_vec, metric->key_orig,
444 						metric->persistent_file_name);
445 			}
446 #endif
447 			zbx_vector_ptr_remove_noorder(&active_metrics, i);
448 			free_active_metric(metric);
449 			i--;	/* consider the same index on the next run */
450 		}
451 	}
452 
453 	zbx_regexp_clean_expressions(&regexps);
454 
455 	if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_REGEXP, &jp_data))
456 	{
457 	 	p = NULL;
458 		while (NULL != (p = zbx_json_next(&jp_data, p)))
459 		{
460 /* {"regexp":[{"name":"regexp1",...,...},{...},...]}
461  *            ^------------------------^
462  */			if (SUCCEED != zbx_json_brackets_open(p, &jp_row))
463 			{
464 				zabbix_log(LOG_LEVEL_ERR, "cannot parse list of active checks: %s", zbx_json_strerror());
465 				goto out;
466 			}
467 
468 			if (SUCCEED != zbx_json_value_by_name_dyn(&jp_row, "name", &name, &name_alloc, NULL))
469 			{
470 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "name");
471 				continue;
472 			}
473 
474 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "expression", expression, sizeof(expression),
475 					NULL) || '\0' == *expression)
476 			{
477 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "expression");
478 				continue;
479 			}
480 
481 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "expression_type", tmp, sizeof(tmp), NULL) ||
482 					'\0' == *tmp)
483 			{
484 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "expression_type");
485 				continue;
486 			}
487 
488 			expression_type = atoi(tmp);
489 
490 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "exp_delimiter", tmp, sizeof(tmp), NULL))
491 			{
492 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "exp_delimiter");
493 				continue;
494 			}
495 
496 			exp_delimiter = tmp[0];
497 
498 			if (SUCCEED != zbx_json_value_by_name(&jp_row, "case_sensitive", tmp,
499 					sizeof(tmp), NULL) || '\0' == *tmp)
500 			{
501 				zabbix_log(LOG_LEVEL_WARNING, "cannot retrieve value of tag \"%s\"", "case_sensitive");
502 				continue;
503 			}
504 
505 			case_sensitive = atoi(tmp);
506 
507 			add_regexp_ex(&regexps, name, expression, expression_type, exp_delimiter, case_sensitive);
508 		}
509 	}
510 
511 	ret = SUCCEED;
512 out:
513 	zbx_vector_str_clear_ext(&received_metrics, zbx_str_free);
514 	zbx_vector_str_destroy(&received_metrics);
515 	zbx_free(key_orig);
516 	zbx_free(name);
517 
518 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
519 
520 	return ret;
521 }
522 
523 /*********************************************************************************
524  *                                                                               *
525  * Function: process_config_item                                                 *
526  *                                                                               *
527  * Purpose: process configuration item and set it value to respective parameter  *
528  *                                                                               *
529  * Parameters: json   - pointer to JSON structure where to put resulting value   *
530  *             config - pointer to configuration parameter                       *
531  *             length - length of configuration parameter                        *
532  *             proto  - configuration parameter prototype                        *
533  *                                                                               *
534  ********************************************************************************/
process_config_item(struct zbx_json * json,char * config,size_t length,const char * proto)535 static void process_config_item(struct zbx_json *json, char *config, size_t length, const char *proto)
536 {
537 	char		**value;
538 	AGENT_RESULT	result;
539 	const char	*config_name;
540 	const char	*config_type;
541 
542 	if (CONFIG_HOST_METADATA_ITEM == config)
543 	{
544 		config_name = "HostMetadataItem";
545 		config_type = "metadata";
546 	}
547 	else /* CONFIG_HOST_INTERFACE_ITEM */
548 	{
549 		config_name = "HostInterfaceItem";
550 		config_type = "interface";
551 	}
552 
553 	init_result(&result);
554 
555 	if (SUCCEED == process(config, PROCESS_LOCAL_COMMAND | PROCESS_WITH_ALIAS, &result) &&
556 			NULL != (value = GET_STR_RESULT(&result)) && NULL != *value)
557 	{
558 		if (SUCCEED != zbx_is_utf8(*value))
559 		{
560 			zabbix_log(LOG_LEVEL_WARNING, "cannot get host %s using \"%s\" item specified by"
561 					" \"%s\" configuration parameter: returned value is not"
562 					" an UTF-8 string",config_type, config, config_name);
563 		}
564 		else
565 		{
566 			if (length < zbx_strlen_utf8(*value))
567 			{
568 				size_t	bytes;
569 
570 				zabbix_log(LOG_LEVEL_WARNING, "the returned value of \"%s\" item specified by"
571 						" \"%s\" configuration parameter is too long,"
572 						" using first %d characters", config, config_name, (int)length);
573 
574 				bytes = zbx_strlen_utf8_nchars(*value, length);
575 				(*value)[bytes] = '\0';
576 			}
577 			zbx_json_addstring(json, proto, *value, ZBX_JSON_TYPE_STRING);
578 		}
579 	}
580 	else
581 		zabbix_log(LOG_LEVEL_WARNING, "cannot get host %s using \"%s\" item specified by"
582 				" \"%s\" configuration parameter",config_type, config,config_name);
583 
584 	free_result(&result);
585 }
586 
587 /******************************************************************************
588  *                                                                            *
589  * Function: refresh_active_checks                                            *
590  *                                                                            *
591  * Purpose: Retrieve from Zabbix server list of active checks                 *
592  *                                                                            *
593  * Parameters: host - IP or Hostname of Zabbix server                         *
594  *             port - port of Zabbix server                                   *
595  *                                                                            *
596  * Return value: returns SUCCEED on successful parsing,                       *
597  *               FAIL on other cases                                          *
598  *                                                                            *
599  * Author: Eugene Grigorjev, Alexei Vladishev (new json protocol)             *
600  *                                                                            *
601  * Comments:                                                                  *
602  *                                                                            *
603  ******************************************************************************/
refresh_active_checks(const char * host,unsigned short port)604 static int	refresh_active_checks(const char *host, unsigned short port)
605 {
606 	static ZBX_THREAD_LOCAL int	last_ret = SUCCEED;
607 	int				ret;
608 	char				*tls_arg1, *tls_arg2;
609 	zbx_socket_t			s;
610 	struct zbx_json			json;
611 
612 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s' port:%hu", __func__, host, port);
613 
614 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
615 
616 	zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_GET_ACTIVE_CHECKS, ZBX_JSON_TYPE_STRING);
617 	zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST, CONFIG_HOSTNAME, ZBX_JSON_TYPE_STRING);
618 
619 	if (NULL != CONFIG_HOST_METADATA)
620 	{
621 		zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST_METADATA, CONFIG_HOST_METADATA, ZBX_JSON_TYPE_STRING);
622 	}
623 	else if (NULL != CONFIG_HOST_METADATA_ITEM)
624 	{
625 		process_config_item(&json, CONFIG_HOST_METADATA_ITEM, HOST_METADATA_LEN, ZBX_PROTO_TAG_HOST_METADATA);
626 	}
627 
628 	if (NULL != CONFIG_HOST_INTERFACE)
629 	{
630 		zbx_json_addstring(&json, ZBX_PROTO_TAG_INTERFACE, CONFIG_HOST_INTERFACE, ZBX_JSON_TYPE_STRING);
631 	}
632 	else if (NULL != CONFIG_HOST_INTERFACE_ITEM)
633 	{
634 		process_config_item(&json, CONFIG_HOST_INTERFACE_ITEM, HOST_INTERFACE_LEN, ZBX_PROTO_TAG_INTERFACE);
635 	}
636 
637 	if (NULL != CONFIG_LISTEN_IP)
638 	{
639 		char	*p;
640 
641 		if (NULL != (p = strchr(CONFIG_LISTEN_IP, ',')))
642 			*p = '\0';
643 
644 		zbx_json_addstring(&json, ZBX_PROTO_TAG_IP, CONFIG_LISTEN_IP, ZBX_JSON_TYPE_STRING);
645 
646 		if (NULL != p)
647 			*p = ',';
648 	}
649 
650 	if (ZBX_DEFAULT_AGENT_PORT != CONFIG_LISTEN_PORT)
651 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_PORT, (zbx_uint64_t)CONFIG_LISTEN_PORT);
652 
653 	switch (configured_tls_connect_mode)
654 	{
655 		case ZBX_TCP_SEC_UNENCRYPTED:
656 			tls_arg1 = NULL;
657 			tls_arg2 = NULL;
658 			break;
659 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
660 		case ZBX_TCP_SEC_TLS_CERT:
661 			tls_arg1 = CONFIG_TLS_SERVER_CERT_ISSUER;
662 			tls_arg2 = CONFIG_TLS_SERVER_CERT_SUBJECT;
663 			break;
664 		case ZBX_TCP_SEC_TLS_PSK:
665 			tls_arg1 = CONFIG_TLS_PSK_IDENTITY;
666 			tls_arg2 = NULL;	/* zbx_tls_connect() will find PSK */
667 			break;
668 #endif
669 		default:
670 			THIS_SHOULD_NEVER_HAPPEN;
671 			ret = FAIL;
672 			goto out;
673 	}
674 
675 	if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, CONFIG_TIMEOUT,
676 			configured_tls_connect_mode, tls_arg1, tls_arg2)))
677 	{
678 		zabbix_log(LOG_LEVEL_DEBUG, "sending [%s]", json.buffer);
679 
680 		if (SUCCEED == (ret = zbx_tcp_send(&s, json.buffer)))
681 		{
682 			zabbix_log(LOG_LEVEL_DEBUG, "before read");
683 
684 			if (SUCCEED == (ret = zbx_tcp_recv(&s)))
685 			{
686 				zabbix_log(LOG_LEVEL_DEBUG, "got [%s]", s.buffer);
687 
688 				if (SUCCEED != last_ret)
689 				{
690 					zabbix_log(LOG_LEVEL_WARNING, "active check configuration update from [%s:%hu]"
691 							" is working again", host, port);
692 				}
693 				parse_list_of_checks(s.buffer, host, port);
694 			}
695 		}
696 
697 		zbx_tcp_close(&s);
698 	}
699 out:
700 	if (SUCCEED != ret && SUCCEED == last_ret)
701 	{
702 		zabbix_log(LOG_LEVEL_WARNING,
703 				"active check configuration update from [%s:%hu] started to fail (%s)",
704 				host, port, zbx_socket_strerror());
705 	}
706 
707 	last_ret = ret;
708 
709 	zbx_json_free(&json);
710 
711 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
712 
713 	return ret;
714 }
715 
716 /******************************************************************************
717  *                                                                            *
718  * Function: check_response                                                   *
719  *                                                                            *
720  * Purpose: Check whether JSON response is SUCCEED                            *
721  *                                                                            *
722  * Parameters: JSON response from Zabbix trapper                              *
723  *                                                                            *
724  * Return value:  SUCCEED - processed successfully                            *
725  *                FAIL - an error occurred                                    *
726  *                                                                            *
727  * Author: Alexei Vladishev                                                   *
728  *                                                                            *
729  * Comments: zabbix_sender has almost the same function!                      *
730  *                                                                            *
731  ******************************************************************************/
check_response(char * response)732 static int	check_response(char *response)
733 {
734 	struct zbx_json_parse	jp;
735 	char			value[MAX_STRING_LEN];
736 	char			info[MAX_STRING_LEN];
737 	int			ret;
738 
739 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() response:'%s'", __func__, response);
740 
741 	ret = zbx_json_open(response, &jp);
742 
743 	if (SUCCEED == ret)
744 		ret = zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, value, sizeof(value), NULL);
745 
746 	if (SUCCEED == ret && 0 != strcmp(value, ZBX_PROTO_VALUE_SUCCESS))
747 		ret = FAIL;
748 
749 	if (SUCCEED == ret && SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_INFO, info, sizeof(info), NULL))
750 		zabbix_log(LOG_LEVEL_DEBUG, "info from server: '%s'", info);
751 
752 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
753 
754 	return ret;
755 }
756 
757 /******************************************************************************
758  *                                                                            *
759  * Function: send_buffer                                                      *
760  *                                                                            *
761  * Purpose: Send value stored in the buffer to Zabbix server                  *
762  *                                                                            *
763  * Parameters: host     - [IN] IP or Hostname of Zabbix server                *
764  *             port     - [IN] port number                                    *
765  *             prep_vec - [IN/OUT] vector with data for writing into          *
766  *                                 persistent files                           *
767  *                                                                            *
768  * Return value: SUCCEED if:                                                  *
769  *                    - no need to send data now (buffer empty or has enough  *
770  *                      free elements, or recently sent)                      *
771  *                    - data successfully sent to server (proxy)              *
772  *               FAIL - error when sending data                               *
773  *                                                                            *
774  * Author: Alexei Vladishev                                                   *
775  *                                                                            *
776  ******************************************************************************/
send_buffer(const char * host,unsigned short port,zbx_vector_pre_persistent_t * prep_vec)777 static int	send_buffer(const char *host, unsigned short port, zbx_vector_pre_persistent_t *prep_vec)
778 {
779 	ZBX_ACTIVE_BUFFER_ELEMENT	*el;
780 	int				ret = SUCCEED, i, now;
781 	char				*tls_arg1, *tls_arg2;
782 	zbx_timespec_t			ts;
783 	const char			*err_send_step = "";
784 	zbx_socket_t			s;
785 	struct zbx_json 		json;
786 
787 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s' port:%d entries:%d/%d",
788 			__func__, host, port, buffer.count, CONFIG_BUFFER_SIZE);
789 
790 	if (0 == buffer.count)
791 		goto ret;
792 
793 	now = (int)time(NULL);
794 
795 	if (CONFIG_BUFFER_SIZE / 2 > buffer.pcount && CONFIG_BUFFER_SIZE > buffer.count &&
796 			CONFIG_BUFFER_SEND > now - buffer.lastsent)
797 	{
798 		zabbix_log(LOG_LEVEL_DEBUG, "%s() now:%d lastsent:%d now-lastsent:%d BufferSend:%d; will not send now",
799 				__func__, now, buffer.lastsent, now - buffer.lastsent, CONFIG_BUFFER_SEND);
800 		goto ret;
801 	}
802 
803 	zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN);
804 	zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_AGENT_DATA, ZBX_JSON_TYPE_STRING);
805 	zbx_json_addstring(&json, ZBX_PROTO_TAG_SESSION, session_token, ZBX_JSON_TYPE_STRING);
806 	zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA);
807 
808 	for (i = 0; i < buffer.count; i++)
809 	{
810 		el = &buffer.data[i];
811 
812 		zbx_json_addobject(&json, NULL);
813 		zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST, el->host, ZBX_JSON_TYPE_STRING);
814 		zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, el->key, ZBX_JSON_TYPE_STRING);
815 
816 		if (NULL != el->value)
817 			zbx_json_addstring(&json, ZBX_PROTO_TAG_VALUE, el->value, ZBX_JSON_TYPE_STRING);
818 
819 		if (ITEM_STATE_NOTSUPPORTED == el->state)
820 		{
821 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_STATE, ITEM_STATE_NOTSUPPORTED);
822 		}
823 		else
824 		{
825 			/* add item meta information only for items in normal state */
826 			if (0 != (ZBX_METRIC_FLAG_LOG & el->flags))
827 				zbx_json_adduint64(&json, ZBX_PROTO_TAG_LASTLOGSIZE, el->lastlogsize);
828 			if (0 != (ZBX_METRIC_FLAG_LOG_LOGRT & el->flags))
829 				zbx_json_adduint64(&json, ZBX_PROTO_TAG_MTIME, el->mtime);
830 		}
831 
832 		if (0 != el->timestamp)
833 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGTIMESTAMP, el->timestamp);
834 
835 		if (NULL != el->source)
836 			zbx_json_addstring(&json, ZBX_PROTO_TAG_LOGSOURCE, el->source, ZBX_JSON_TYPE_STRING);
837 
838 		if (0 != el->severity)
839 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGSEVERITY, el->severity);
840 
841 		if (0 != el->logeventid)
842 			zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGEVENTID, el->logeventid);
843 
844 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_ID, el->id);
845 
846 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_CLOCK, el->ts.sec);
847 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_NS, el->ts.ns);
848 		zbx_json_close(&json);
849 	}
850 
851 	zbx_json_close(&json);
852 
853 	switch (configured_tls_connect_mode)
854 	{
855 		case ZBX_TCP_SEC_UNENCRYPTED:
856 			tls_arg1 = NULL;
857 			tls_arg2 = NULL;
858 			break;
859 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
860 		case ZBX_TCP_SEC_TLS_CERT:
861 			tls_arg1 = CONFIG_TLS_SERVER_CERT_ISSUER;
862 			tls_arg2 = CONFIG_TLS_SERVER_CERT_SUBJECT;
863 			break;
864 		case ZBX_TCP_SEC_TLS_PSK:
865 			tls_arg1 = CONFIG_TLS_PSK_IDENTITY;
866 			tls_arg2 = NULL;	/* zbx_tls_connect() will find PSK */
867 			break;
868 #endif
869 		default:
870 			THIS_SHOULD_NEVER_HAPPEN;
871 			ret = FAIL;
872 			goto out;
873 	}
874 
875 	if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, MIN(buffer.count * CONFIG_TIMEOUT, 60),
876 			configured_tls_connect_mode, tls_arg1, tls_arg2)))
877 	{
878 		zbx_timespec(&ts);
879 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_CLOCK, ts.sec);
880 		zbx_json_adduint64(&json, ZBX_PROTO_TAG_NS, ts.ns);
881 
882 		zabbix_log(LOG_LEVEL_DEBUG, "JSON before sending [%s]", json.buffer);
883 
884 		if (SUCCEED == (ret = zbx_tcp_send(&s, json.buffer)))
885 		{
886 			if (SUCCEED == (ret = zbx_tcp_recv(&s)))
887 			{
888 				zabbix_log(LOG_LEVEL_DEBUG, "JSON back [%s]", s.buffer);
889 
890 				if (NULL == s.buffer || SUCCEED != check_response(s.buffer))
891 				{
892 					ret = FAIL;
893 					zabbix_log(LOG_LEVEL_DEBUG, "NOT OK");
894 				}
895 				else
896 					zabbix_log(LOG_LEVEL_DEBUG, "OK");
897 			}
898 			else
899 				err_send_step = "[recv] ";
900 		}
901 		else
902 			err_send_step = "[send] ";
903 
904 		zbx_tcp_close(&s);
905 	}
906 	else
907 		err_send_step = "[connect] ";
908 out:
909 	zbx_json_free(&json);
910 
911 	if (SUCCEED == ret)
912 	{
913 #if !defined(_WINDOWS) && !defined(__MINGW32__)
914 		zbx_write_persistent_files(prep_vec);
915 		zbx_clean_pre_persistent_elements(prep_vec);
916 #else
917 		ZBX_UNUSED(prep_vec);
918 #endif
919 		/* free buffer */
920 		for (i = 0; i < buffer.count; i++)
921 		{
922 			el = &buffer.data[i];
923 
924 			zbx_free(el->host);
925 			zbx_free(el->key);
926 			zbx_free(el->value);
927 			zbx_free(el->source);
928 		}
929 		buffer.count = 0;
930 		buffer.pcount = 0;
931 		buffer.lastsent = now;
932 		if (0 != buffer.first_error)
933 		{
934 			zabbix_log(LOG_LEVEL_WARNING, "active check data upload to [%s:%hu] is working again",
935 					host, port);
936 			buffer.first_error = 0;
937 		}
938 	}
939 	else
940 	{
941 		if (0 == buffer.first_error)
942 		{
943 			zabbix_log(LOG_LEVEL_WARNING, "active check data upload to [%s:%hu] started to fail (%s%s)",
944 					host, port, err_send_step, zbx_socket_strerror());
945 			buffer.first_error = now;
946 		}
947 		zabbix_log(LOG_LEVEL_DEBUG, "send value error: %s%s", err_send_step, zbx_socket_strerror());
948 	}
949 ret:
950 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
951 
952 	return ret;
953 }
954 
955 /******************************************************************************
956  *                                                                            *
957  * Function: process_value                                                    *
958  *                                                                            *
959  * Purpose: Buffer new value or send the whole buffer to the server           *
960  *                                                                            *
961  * Parameters: server      - IP or Hostname of Zabbix server                  *
962  *             port        - port of Zabbix server                            *
963  *             host        - name of host in Zabbix database                  *
964  *             key         - name of metric                                   *
965  *             value       - key value or error message why an item became    *
966  *                           NOTSUPPORTED                                     *
967  *             state       - ITEM_STATE_NORMAL or ITEM_STATE_NOTSUPPORTED     *
968  *             lastlogsize - size of read logfile                             *
969  *             mtime       - time of last file modification                   *
970  *             timestamp   - timestamp of read value                          *
971  *             source      - name of logged data source                       *
972  *             severity    - severity of logged data sources                  *
973  *             logeventid  - the application-specific identifier for          *
974  *                           the event; used for monitoring of Windows        *
975  *                           event logs                                       *
976  *             flags       - metric flags                                     *
977  *                                                                            *
978  * Return value: returns SUCCEED on successful parsing,                       *
979  *               FAIL on other cases                                          *
980  *                                                                            *
981  * Author: Alexei Vladishev                                                   *
982  *                                                                            *
983  * Comments: ATTENTION! This function's address and pointers to arguments     *
984  *           are described in Zabbix defined type "zbx_process_value_func_t"  *
985  *           and used when calling process_log(), process_logrt() and         *
986  *           zbx_read2(). If you ever change this process_value() arguments   *
987  *           or return value do not forget to synchronize changes with the    *
988  *           defined type "zbx_process_value_func_t" and implementations of   *
989  *           process_log(), process_logrt(), zbx_read2() and their callers.   *
990  *                                                                            *
991  ******************************************************************************/
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,const unsigned long * timestamp,const char * source,const unsigned short * severity,const unsigned long * logeventid,unsigned char flags)992 static int	process_value(const char *server, unsigned short port, const char *host, const char *key,
993 		const char *value, unsigned char state, zbx_uint64_t *lastlogsize, const int *mtime,
994 		const unsigned long *timestamp, const char *source, const unsigned short *severity,
995 		const unsigned long *logeventid, unsigned char flags)
996 {
997 	ZBX_ACTIVE_BUFFER_ELEMENT	*el = NULL;
998 	int				i, ret = FAIL;
999 	size_t				sz;
1000 
1001 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
1002 	{
1003 		if (NULL != lastlogsize)
1004 		{
1005 			zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s:%s' lastlogsize:" ZBX_FS_UI64 " value:'%s'",
1006 					__func__, host, key, *lastlogsize, ZBX_NULL2STR(value));
1007 		}
1008 		else
1009 		{
1010 			/* log a dummy lastlogsize to keep the same record format for simpler parsing */
1011 			zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s:%s' lastlogsize:null value:'%s'",
1012 					__func__, host, key, ZBX_NULL2STR(value));
1013 		}
1014 	}
1015 
1016 	/* do not send data from buffer if host/key are the same as previous unless buffer is full already */
1017 	if (0 < buffer.count)
1018 	{
1019 		el = &buffer.data[buffer.count - 1];
1020 
1021 		if ((0 != (flags & ZBX_METRIC_FLAG_PERSISTENT) && CONFIG_BUFFER_SIZE / 2 <= buffer.pcount) ||
1022 				CONFIG_BUFFER_SIZE <= buffer.count ||
1023 				0 != strcmp(el->key, key) || 0 != strcmp(el->host, host))
1024 		{
1025 			send_buffer(server, port, &pre_persistent_vec);
1026 		}
1027 	}
1028 
1029 	if (0 != (ZBX_METRIC_FLAG_PERSISTENT & flags) && CONFIG_BUFFER_SIZE / 2 <= buffer.pcount)
1030 	{
1031 		zabbix_log(LOG_LEVEL_WARNING, "buffer is full, cannot store persistent value");
1032 		goto out;
1033 	}
1034 
1035 	if (CONFIG_BUFFER_SIZE > buffer.count)
1036 	{
1037 		zabbix_log(LOG_LEVEL_DEBUG, "buffer: new element %d", buffer.count);
1038 		el = &buffer.data[buffer.count];
1039 		buffer.count++;
1040 	}
1041 	else
1042 	{
1043 		if (0 == (ZBX_METRIC_FLAG_PERSISTENT & flags))
1044 		{
1045 			for (i = 0; i < buffer.count; i++)
1046 			{
1047 				el = &buffer.data[i];
1048 				if (0 == strcmp(el->host, host) && 0 == strcmp(el->key, key))
1049 					break;
1050 			}
1051 		}
1052 
1053 		if (0 != (ZBX_METRIC_FLAG_PERSISTENT & flags) || i == buffer.count)
1054 		{
1055 			for (i = 0; i < buffer.count; i++)
1056 			{
1057 				el = &buffer.data[i];
1058 				if (0 == (ZBX_METRIC_FLAG_PERSISTENT & el->flags))
1059 					break;
1060 			}
1061 		}
1062 
1063 		if (NULL != el)
1064 		{
1065 			zabbix_log(LOG_LEVEL_DEBUG, "remove element [%d] Key:'%s:%s'", i, el->host, el->key);
1066 
1067 			zbx_free(el->host);
1068 			zbx_free(el->key);
1069 			zbx_free(el->value);
1070 			zbx_free(el->source);
1071 		}
1072 
1073 		sz = (size_t)(CONFIG_BUFFER_SIZE - i - 1) * sizeof(ZBX_ACTIVE_BUFFER_ELEMENT);
1074 		memmove(&buffer.data[i], &buffer.data[i + 1], sz);
1075 
1076 		zabbix_log(LOG_LEVEL_DEBUG, "buffer full: new element %d", buffer.count - 1);
1077 
1078 		el = &buffer.data[CONFIG_BUFFER_SIZE - 1];
1079 	}
1080 
1081 	memset(el, 0, sizeof(ZBX_ACTIVE_BUFFER_ELEMENT));
1082 	el->host = zbx_strdup(NULL, host);
1083 	el->key = zbx_strdup(NULL, key);
1084 	if (NULL != value)
1085 		el->value = zbx_strdup(NULL, value);
1086 	el->state = state;
1087 
1088 	if (NULL != source)
1089 		el->source = strdup(source);
1090 	if (NULL != severity)
1091 		el->severity = *severity;
1092 	if (NULL != lastlogsize)
1093 		el->lastlogsize = *lastlogsize;
1094 	if (NULL != mtime)
1095 		el->mtime = *mtime;
1096 	if (NULL != timestamp)
1097 		el->timestamp = *timestamp;
1098 	if (NULL != logeventid)
1099 		el->logeventid = (int)*logeventid;
1100 
1101 	zbx_timespec(&el->ts);
1102 	el->flags = flags;
1103 	el->id = ++last_valueid;
1104 
1105 	if (0 != (ZBX_METRIC_FLAG_PERSISTENT & flags))
1106 		buffer.pcount++;
1107 
1108 	/* If conditions are met then send buffer now. It is necessary for synchronization */
1109 	/* between sending data to server and writing of persistent files. */
1110 	if ((0 != (flags & ZBX_METRIC_FLAG_PERSISTENT) && CONFIG_BUFFER_SIZE / 2 <= buffer.pcount) ||
1111 			CONFIG_BUFFER_SIZE <= buffer.count)
1112 	{
1113 		send_buffer(server, port, &pre_persistent_vec);
1114 	}
1115 
1116 	ret = SUCCEED;
1117 out:
1118 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1119 
1120 	return ret;
1121 }
1122 
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)1123 static int	need_meta_update(ZBX_ACTIVE_METRIC *metric, zbx_uint64_t lastlogsize_sent, int mtime_sent,
1124 		unsigned char old_state, zbx_uint64_t lastlogsize_last, int mtime_last)
1125 {
1126 	int	ret = FAIL;
1127 
1128 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:%s", __func__, metric->key);
1129 
1130 	if (0 != (ZBX_METRIC_FLAG_LOG & metric->flags))
1131 	{
1132 		/* meta information update is needed if:                                              */
1133 		/* - lastlogsize or mtime changed since we last sent within this check                */
1134 		/* - nothing was sent during this check and state changed from notsupported to normal */
1135 		/* - nothing was sent during this check and it's a new metric                         */
1136 		if (lastlogsize_sent != metric->lastlogsize || mtime_sent != metric->mtime ||
1137 				(lastlogsize_last == lastlogsize_sent && mtime_last == mtime_sent &&
1138 						(old_state != metric->state ||
1139 						0 != (ZBX_METRIC_FLAG_NEW & metric->flags))))
1140 		{
1141 			/* needs meta information update */
1142 			ret = SUCCEED;
1143 		}
1144 	}
1145 
1146 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1147 
1148 	return ret;
1149 }
1150 
1151 #if !defined(_WINDOWS) && !defined(__MINGW32__)
process_eventlog_check(char * server,unsigned short port,zbx_vector_ptr_t * regular_expressions,ZBX_ACTIVE_METRIC * metric,zbx_process_value_func_t process_value_cb,zbx_uint64_t * lastlogsize_sent,char ** error)1152 static int	process_eventlog_check(char *server, unsigned short port, zbx_vector_ptr_t *regular_expressions,
1153 		ZBX_ACTIVE_METRIC *metric, zbx_process_value_func_t process_value_cb, zbx_uint64_t *lastlogsize_sent,
1154 		char **error)
1155 {
1156 	ZBX_UNUSED(server);
1157 	ZBX_UNUSED(port);
1158 	ZBX_UNUSED(regular_expressions);
1159 	ZBX_UNUSED(metric);
1160 	ZBX_UNUSED(process_value_cb);
1161 	ZBX_UNUSED(lastlogsize_sent);
1162 	ZBX_UNUSED(error);
1163 
1164 	return FAIL;
1165 }
1166 #else
1167 int	process_eventlog_check(char *server, unsigned short port, zbx_vector_ptr_t *regexps, ZBX_ACTIVE_METRIC *metric,
1168 		zbx_process_value_func_t process_value_cb, zbx_uint64_t *lastlogsize_sent, char **error);
1169 #endif
1170 
process_common_check(char * server,unsigned short port,ZBX_ACTIVE_METRIC * metric,char ** error)1171 static int	process_common_check(char *server, unsigned short port, ZBX_ACTIVE_METRIC *metric, char **error)
1172 {
1173 	int		ret;
1174 	AGENT_RESULT	result;
1175 	char		**pvalue;
1176 
1177 	init_result(&result);
1178 
1179 	if (SUCCEED != (ret = process(metric->key, 0, &result)))
1180 	{
1181 		if (NULL != (pvalue = GET_MSG_RESULT(&result)))
1182 			*error = zbx_strdup(*error, *pvalue);
1183 		goto out;
1184 	}
1185 
1186 	if (NULL != (pvalue = GET_TEXT_RESULT(&result)))
1187 	{
1188 		zabbix_log(LOG_LEVEL_DEBUG, "for key [%s] received value [%s]", metric->key, *pvalue);
1189 
1190 		process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, *pvalue, ITEM_STATE_NORMAL, NULL, NULL,
1191 				NULL, NULL, NULL, NULL, metric->flags);
1192 	}
1193 out:
1194 	free_result(&result);
1195 
1196 	return ret;
1197 }
1198 
1199 #if !defined(_WINDOWS) && !defined(__MINGW32__)
1200 /******************************************************************************
1201  *                                                                            *
1202  * Function: zbx_minimal_init_prep_vec_data                                   *
1203  *                                                                            *
1204  * Purpose: initialize an element of preparation vector with available data   *
1205  *                                                                            *
1206  * Parameters: lastlogsize   - [IN] lastlogize value to write into persistent *
1207  *                                  data file                                 *
1208  *             mtime         - [IN] mtime value to write into persistent data *
1209  *                                  file                                      *
1210  *             prep_vec_elem - [IN/OUT] element of vector to initialize       *
1211  *                                                                            *
1212  * Comments: this is a minimal initialization for using before sending status *
1213  *           updates or meta-data. It initializes only 2 attributes to be     *
1214  *           usable without any data about log files.                         *
1215  *                                                                            *
1216  ******************************************************************************/
zbx_minimal_init_prep_vec_data(zbx_uint64_t lastlogsize,int mtime,zbx_pre_persistent_t * prep_vec_elem)1217 static void	zbx_minimal_init_prep_vec_data(zbx_uint64_t lastlogsize, int mtime, zbx_pre_persistent_t *prep_vec_elem)
1218 {
1219 	if (NULL != prep_vec_elem->filename)
1220 		zbx_free(prep_vec_elem->filename);	/* filename == NULL should be checked when preparing JSON */
1221 							/* for writing as most attributes are not initialized */
1222 	prep_vec_elem->processed_size = lastlogsize;
1223 	prep_vec_elem->mtime = mtime;
1224 }
1225 
zbx_fill_prep_vec_element(zbx_vector_pre_persistent_t * prep_vec,const char * key,const char * persistent_file_name,const struct st_logfile * logfile,const zbx_uint64_t lastlogsize,const int mtime)1226 static void	zbx_fill_prep_vec_element(zbx_vector_pre_persistent_t *prep_vec, const char *key,
1227 		const char *persistent_file_name, const struct st_logfile *logfile, const zbx_uint64_t lastlogsize,
1228 		const int mtime)
1229 {
1230 	/* index in preparation vector */
1231 	int	idx = zbx_find_or_create_prep_vec_element(prep_vec, key, persistent_file_name);
1232 
1233 	if (NULL != logfile)
1234 	{
1235 		zbx_init_prep_vec_data(logfile, prep_vec->values + idx);
1236 		zbx_update_prep_vec_data(logfile, logfile->processed_size, prep_vec->values + idx);
1237 	}
1238 	else
1239 		zbx_minimal_init_prep_vec_data(lastlogsize, mtime, prep_vec->values + idx);
1240 }
1241 #endif	/* not WINDOWS, not __MINGW32__ */
1242 
process_active_checks(char * server,unsigned short port)1243 static void	process_active_checks(char *server, unsigned short port)
1244 {
1245 	char	*error = NULL;
1246 	int	i, now;
1247 
1248 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() server:'%s' port:%hu", __func__, server, port);
1249 
1250 	now = (int)time(NULL);
1251 
1252 	for (i = 0; i < active_metrics.values_num; i++)
1253 	{
1254 		zbx_uint64_t		lastlogsize_last, lastlogsize_sent;
1255 		int			mtime_last, mtime_sent, ret;
1256 		ZBX_ACTIVE_METRIC	*metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
1257 
1258 		if (metric->nextcheck > now)
1259 			continue;
1260 
1261 		/* for meta information update we need to know if something was sent at all during the check */
1262 		lastlogsize_last = metric->lastlogsize;
1263 		mtime_last = metric->mtime;
1264 
1265 		lastlogsize_sent = metric->lastlogsize;
1266 		mtime_sent = metric->mtime;
1267 
1268 		/* before processing make sure refresh is not 0 to avoid overload */
1269 		if (0 == metric->refresh)
1270 		{
1271 			ret = FAIL;
1272 			error = zbx_strdup(error, "Incorrect update interval.");
1273 		}
1274 		else if (0 != ((ZBX_METRIC_FLAG_LOG_LOG | ZBX_METRIC_FLAG_LOG_LOGRT) & metric->flags))
1275 		{
1276 			ret = process_log_check(server, port, &regexps, metric, process_value, &lastlogsize_sent,
1277 					&mtime_sent, &error, &pre_persistent_vec);
1278 		}
1279 		else if (0 != (ZBX_METRIC_FLAG_LOG_EVENTLOG & metric->flags))
1280 		{
1281 			ret = process_eventlog_check(server, port, &regexps, metric, process_value, &lastlogsize_sent,
1282 					&error);
1283 		}
1284 		else
1285 			ret = process_common_check(server, port, metric, &error);
1286 
1287 		if (SUCCEED != ret)
1288 		{
1289 			const char	*perror = (NULL != error ? error : ZBX_NOTSUPPORTED_MSG);
1290 
1291 			metric->state = ITEM_STATE_NOTSUPPORTED;
1292 			metric->error_count = 0;
1293 			metric->processed_bytes = 0;
1294 
1295 			zabbix_log(LOG_LEVEL_WARNING, "active check \"%s\" is not supported: %s", metric->key, perror);
1296 #if !defined(_WINDOWS) && !defined(__MINGW32__)
1297 			/* only for log*[] items */
1298 			if (0 != ((ZBX_METRIC_FLAG_LOG_LOG | ZBX_METRIC_FLAG_LOG_LOGRT) & metric->flags) &&
1299 					NULL != metric->persistent_file_name)
1300 			{
1301 				const struct st_logfile	*logfile = NULL;
1302 
1303 				if (0 < metric->logfiles_num)
1304 				{
1305 					logfile = find_last_processed_file_in_logfiles_list(metric->logfiles,
1306 							metric->logfiles_num);
1307 				}
1308 
1309 				zbx_fill_prep_vec_element(&pre_persistent_vec, metric->key_orig,
1310 						metric->persistent_file_name, logfile, metric->lastlogsize,
1311 						metric->mtime);
1312 			}
1313 #endif
1314 			process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, perror, ITEM_STATE_NOTSUPPORTED,
1315 					&metric->lastlogsize, &metric->mtime, NULL, NULL, NULL, NULL, metric->flags);
1316 
1317 			zbx_free(error);
1318 		}
1319 		else
1320 		{
1321 			if (0 == metric->error_count)
1322 			{
1323 				unsigned char	old_state = metric->state;
1324 
1325 				if (ITEM_STATE_NOTSUPPORTED == metric->state)
1326 				{
1327 					/* item became supported */
1328 					metric->state = ITEM_STATE_NORMAL;
1329 				}
1330 
1331 				if (SUCCEED == need_meta_update(metric, lastlogsize_sent, mtime_sent, old_state,
1332 						lastlogsize_last, mtime_last))
1333 				{
1334 #if !defined(_WINDOWS) && !defined(__MINGW32__)
1335 					if (NULL != metric->persistent_file_name)
1336 					{
1337 						const struct st_logfile	*logfile = NULL;
1338 
1339 						if (0 < metric->logfiles_num)
1340 						{
1341 							logfile = find_last_processed_file_in_logfiles_list(
1342 									metric->logfiles, metric->logfiles_num);
1343 						}
1344 
1345 						zbx_fill_prep_vec_element(&pre_persistent_vec, metric->key_orig,
1346 								metric->persistent_file_name, logfile, metric->lastlogsize,
1347 								metric->mtime);
1348 					}
1349 #endif
1350 					/* meta information update */
1351 					process_value(server, port, CONFIG_HOSTNAME, metric->key_orig, NULL,
1352 							metric->state, &metric->lastlogsize, &metric->mtime, NULL, NULL,
1353 							NULL, NULL, metric->flags);
1354 				}
1355 
1356 				/* remove "new metric" flag */
1357 				metric->flags &= ~ZBX_METRIC_FLAG_NEW;
1358 			}
1359 		}
1360 
1361 		send_buffer(server, port, &pre_persistent_vec);
1362 		metric->nextcheck = (int)time(NULL) + metric->refresh;
1363 	}
1364 
1365 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1366 }
1367 
1368 /******************************************************************************
1369  *                                                                            *
1370  * Function: update_schedule                                                  *
1371  *                                                                            *
1372  * Purpose: update active check and send buffer schedule by the specified     *
1373  *          time delta                                                        *
1374  *                                                                            *
1375  * Parameters: delta - [IN] the time delta in seconds                         *
1376  *                                                                            *
1377  * Comments: This function is used to update checking and sending schedules   *
1378  *           if the system time was rolled back.                              *
1379  *                                                                            *
1380  ******************************************************************************/
update_schedule(int delta)1381 static void	update_schedule(int delta)
1382 {
1383 	int	i;
1384 
1385 	for (i = 0; i < active_metrics.values_num; i++)
1386 	{
1387 		ZBX_ACTIVE_METRIC	*metric = (ZBX_ACTIVE_METRIC *)active_metrics.values[i];
1388 		metric->nextcheck += delta;
1389 	}
1390 
1391 	buffer.lastsent += delta;
1392 }
1393 
ZBX_THREAD_ENTRY(active_checks_thread,args)1394 ZBX_THREAD_ENTRY(active_checks_thread, args)
1395 {
1396 	ZBX_THREAD_ACTIVECHK_ARGS activechk_args;
1397 
1398 	time_t	nextcheck = 0, nextrefresh = 0, nextsend = 0, now, delta, lastcheck = 0;
1399 
1400 	assert(args);
1401 	assert(((zbx_thread_args_t *)args)->args);
1402 
1403 	process_type = ((zbx_thread_args_t *)args)->process_type;
1404 	server_num = ((zbx_thread_args_t *)args)->server_num;
1405 	process_num = ((zbx_thread_args_t *)args)->process_num;
1406 
1407 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
1408 			server_num, get_process_type_string(process_type), process_num);
1409 
1410 	activechk_args.host = zbx_strdup(NULL, ((ZBX_THREAD_ACTIVECHK_ARGS *)((zbx_thread_args_t *)args)->args)->host);
1411 	activechk_args.port = ((ZBX_THREAD_ACTIVECHK_ARGS *)((zbx_thread_args_t *)args)->args)->port;
1412 	CONFIG_HOSTNAME = zbx_strdup(NULL, ((ZBX_THREAD_ACTIVECHK_ARGS *)((zbx_thread_args_t *)args)->args)->hostname);
1413 
1414 	zbx_free(args);
1415 
1416 	session_token = zbx_create_token(0);
1417 
1418 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1419 	zbx_tls_init_child();
1420 #endif
1421 	init_active_metrics();
1422 
1423 	while (ZBX_IS_RUNNING())
1424 	{
1425 		zbx_update_env(zbx_time());
1426 
1427 		if ((now = time(NULL)) >= nextsend)
1428 		{
1429 			send_buffer(activechk_args.host, activechk_args.port, &pre_persistent_vec);
1430 			nextsend = time(NULL) + 1;
1431 		}
1432 
1433 		if (now >= nextrefresh)
1434 		{
1435 			zbx_setproctitle("active checks #%d [getting list of active checks]", process_num);
1436 
1437 			if (FAIL == refresh_active_checks(activechk_args.host, activechk_args.port))
1438 			{
1439 				nextrefresh = time(NULL) + 60;
1440 			}
1441 			else
1442 			{
1443 				nextrefresh = time(NULL) + CONFIG_REFRESH_ACTIVE_CHECKS;
1444 			}
1445 #if !defined(_WINDOWS) && !defined(__MINGW32__)
1446 			zbx_remove_inactive_persistent_files(&persistent_inactive_vec);
1447 #endif
1448 		}
1449 
1450 		if (now >= nextcheck && CONFIG_BUFFER_SIZE / 2 > buffer.pcount)
1451 		{
1452 			zbx_setproctitle("active checks #%d [processing active checks]", process_num);
1453 
1454 			process_active_checks(activechk_args.host, activechk_args.port);
1455 
1456 			if (CONFIG_BUFFER_SIZE / 2 <= buffer.pcount)	/* failed to complete processing active checks */
1457 				continue;
1458 
1459 			nextcheck = get_min_nextcheck();
1460 			if (FAIL == nextcheck)
1461 				nextcheck = time(NULL) + 60;
1462 		}
1463 		else
1464 		{
1465 			if (0 > (delta = now - lastcheck))
1466 			{
1467 				zabbix_log(LOG_LEVEL_WARNING, "the system time has been pushed back,"
1468 						" adjusting active check schedule");
1469 				update_schedule((int)delta);
1470 				nextcheck += delta;
1471 				nextsend += delta;
1472 				nextrefresh += delta;
1473 			}
1474 
1475 			zbx_setproctitle("active checks #%d [idle 1 sec]", process_num);
1476 			zbx_sleep(1);
1477 		}
1478 
1479 		lastcheck = now;
1480 	}
1481 
1482 	zbx_free(session_token);
1483 
1484 #ifdef _WINDOWS
1485 	zbx_free(activechk_args.host);
1486 	free_active_metrics();
1487 
1488 	ZBX_DO_EXIT();
1489 
1490 	zbx_thread_exit(EXIT_SUCCESS);
1491 #else
1492 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
1493 
1494 	while (1)
1495 		zbx_sleep(SEC_PER_MIN);
1496 #endif
1497 }
1498