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