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