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