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