/****************************************************************************** * * * Function: filter_evaluate_or * * * * Purpose: check if the lld data passes filter evaluation by or rule * * * * Parameters: filter - [IN] the lld filter * * jp_row - [IN] the lld data row * * * * Return value: SUCCEED - the lld data passed filter evaluation * * FAIL - otherwise * * * ******************************************************************************/ static int filter_evaluate_or(lld_filter_t *filter, struct zbx_json_parse *jp_row) { const char *__function_name = "filter_evaluate_or"; int i, ret = SUCCEED; char *value = NULL; size_t value_alloc = 0; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); for (i = 0; i < filter->conditions.values_num; i++) { lld_condition_t *condition = (lld_condition_t *)filter->conditions.values[i]; if (SUCCEED == (ret = zbx_json_value_by_name_dyn(jp_row, condition->macro, &value, &value_alloc))) { ret = (ZBX_REGEXP_MATCH == regexp_match_ex(&condition->regexps, value, condition->regexp, ZBX_CASE_SENSITIVE) ? SUCCEED : FAIL); } /* if any of conditions are true the evaluation returns true */ if (SUCCEED == ret) break; } zbx_free(value); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
/****************************************************************************** * * * Function: zbx_recv_response * * * * Purpose: read a response message (in JSON format) from socket, optionally * * extract "info" value. * * * * Parameters: sock - [IN] socket descriptor * * timeout - [IN] timeout for this operation * * error - [OUT] pointer to error message * * * * Return value: SUCCEED - "response":"success" successfully retrieved * * FAIL - otherwise * * Comments: * * Allocates memory. * * * * If an error occurs, the function allocates dynamic memory for an error * * message and writes its address into location pointed to by "error" * * parameter. * * * * When the "info" value is present in the response message then function * * copies the "info" value into the "error" buffer as additional * * information * * * * IMPORTANT: it is a responsibility of the caller to release the * * "error" memory ! * * * ******************************************************************************/ int zbx_recv_response(zbx_socket_t *sock, int timeout, char **error) { const char *__function_name = "zbx_recv_response"; struct zbx_json_parse jp; char value[16]; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); if (SUCCEED != zbx_tcp_recv_to(sock, timeout)) { /* since we have successfully sent data earlier, we assume the other */ /* side is just too busy processing our data if there is no response */ *error = zbx_strdup(*error, zbx_socket_strerror()); goto out; } zabbix_log(LOG_LEVEL_DEBUG, "%s() '%s'", __function_name, sock->buffer); /* deal with empty string here because zbx_json_open() does not produce an error message in this case */ if ('\0' == *sock->buffer) { *error = zbx_strdup(*error, "empty string received"); goto out; } if (SUCCEED != zbx_json_open(sock->buffer, &jp)) { *error = zbx_strdup(*error, zbx_json_strerror()); goto out; } if (SUCCEED != zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, value, sizeof(value))) { *error = zbx_strdup(*error, "no \"" ZBX_PROTO_TAG_RESPONSE "\" tag"); goto out; } if (0 != strcmp(value, ZBX_PROTO_VALUE_SUCCESS)) { char *info = NULL; size_t info_alloc = 0; if (SUCCEED == zbx_json_value_by_name_dyn(&jp, ZBX_PROTO_TAG_INFO, &info, &info_alloc)) *error = zbx_strdup(*error, info); else *error = zbx_dsprintf(*error, "negative response \"%s\"", value); zbx_free(info); goto out; } ret = SUCCEED; out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
/****************************************************************************** * * * Function: filter_evaluate_expression * * * * Purpose: check if the lld data passes filter evaluation by custom * * expression * * * * Parameters: filter - [IN] the lld filter * * jp_row - [IN] the lld data row * * * * Return value: SUCCEED - the lld data passed filter evaluation * * FAIL - otherwise * * * * Comments: 1) replace {item_condition} references with action condition * * evaluation results (1 or 0) * * 2) call evaluate() to calculate the final result * * * ******************************************************************************/ static int filter_evaluate_expression(lld_filter_t *filter, struct zbx_json_parse *jp_row) { const char *__function_name = "filter_evaluate_expression"; int i, ret = FAIL, id_len; char *expression, id[ZBX_MAX_UINT64_LEN + 2], *p, error[256]; double result; zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:%s", __function_name, filter->expression); expression = zbx_strdup(NULL, filter->expression); for (i = 0; i < filter->conditions.values_num; i++) { char *value = NULL; size_t value_alloc = 0; lld_condition_t *condition = (lld_condition_t *)filter->conditions.values[i]; if (SUCCEED == (ret = zbx_json_value_by_name_dyn(jp_row, condition->macro, &value, &value_alloc))) { ret = (ZBX_REGEXP_MATCH == regexp_match_ex(&condition->regexps, value, condition->regexp, ZBX_CASE_SENSITIVE) ? SUCCEED : FAIL); } zbx_free(value); zbx_snprintf(id, sizeof(id), "{" ZBX_FS_UI64 "}", condition->id); id_len = strlen(id); p = expression; while (NULL != (p = strstr(p, id))) { *p = (SUCCEED == ret ? '1' : '0'); memset(p + 1, ' ', id_len - 1); p += id_len; } } if (SUCCEED == evaluate(&result, expression, error, sizeof(error))) ret = (SUCCEED != zbx_double_compare(result, 0) ? SUCCEED : FAIL); zbx_free(expression); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
/****************************************************************************** * * * Function: filter_evaluate_and_or * * * * Purpose: check if the lld data passes filter evaluation by and/or rule * * * * Parameters: filter - [IN] the lld filter * * jp_row - [IN] the lld data row * * * * Return value: SUCCEED - the lld data passed filter evaluation * * FAIL - otherwise * * * ******************************************************************************/ static int filter_evaluate_and_or(lld_filter_t *filter, struct zbx_json_parse *jp_row) { const char *__function_name = "filter_evaluate_and_or"; int i, ret = SUCCEED, rc = SUCCEED; char *lastmacro = NULL, *value = NULL; size_t value_alloc = 0; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); for (i = 0; i < filter->conditions.values_num; i++) { lld_condition_t *condition = (lld_condition_t *)filter->conditions.values[i]; if (SUCCEED == (rc = zbx_json_value_by_name_dyn(jp_row, condition->macro, &value, &value_alloc))) { rc = (ZBX_REGEXP_MATCH == regexp_match_ex(&condition->regexps, value, condition->regexp, ZBX_CASE_SENSITIVE) ? SUCCEED : FAIL); } /* check if a new condition group has started */ if (NULL == lastmacro || 0 != strcmp(lastmacro, condition->macro)) { /* if any of condition groups are false the evaluation returns false */ if (FAIL == ret) goto out; ret = rc; } else { if (SUCCEED == rc) ret = rc; } lastmacro = condition->macro; } out: zbx_free(value); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
static int lld_check_record(struct zbx_json_parse *jp_row, const char *f_macro, const char *f_regexp, zbx_vector_ptr_t *regexps) { const char *__function_name = "lld_check_record"; char *value = NULL; size_t value_alloc = 0; int res = SUCCEED; zabbix_log(LOG_LEVEL_DEBUG, "In %s() jp_row:'%.*s'", __function_name, jp_row->end - jp_row->start + 1, jp_row->start); if (SUCCEED == zbx_json_value_by_name_dyn(jp_row, f_macro, &value, &value_alloc)) res = regexp_match_ex(regexps, value, f_regexp, ZBX_CASE_SENSITIVE); zbx_free(value); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res)); return res; }
static int parse_response(DC_ITEM *items, AGENT_RESULT *results, int *errcodes, int num, char *response, char *error, int max_error_len) { const char *p; struct zbx_json_parse jp, jp_data, jp_row; char *value = NULL; size_t value_alloc = 0; int i, ret = GATEWAY_ERROR; if (SUCCEED == zbx_json_open(response, &jp)) { if (SUCCEED != zbx_json_value_by_name_dyn(&jp, ZBX_PROTO_TAG_RESPONSE, &value, &value_alloc)) { zbx_snprintf(error, max_error_len, "No '%s' tag in received JSON", ZBX_PROTO_TAG_RESPONSE); goto exit; } if (0 == strcmp(value, ZBX_PROTO_VALUE_SUCCESS)) { if (SUCCEED != zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data)) { zbx_strlcpy(error, "Cannot open data array in received JSON", max_error_len); goto exit; } p = NULL; for (i = 0; i < num; i++) { if (SUCCEED != errcodes[i]) continue; if (NULL == (p = zbx_json_next(&jp_data, p))) { zbx_strlcpy(error, "Not all values included in received JSON", max_error_len); goto exit; } if (SUCCEED != zbx_json_brackets_open(p, &jp_row)) { zbx_strlcpy(error, "Cannot open value object in received JSON", max_error_len); goto exit; } if (SUCCEED == zbx_json_value_by_name_dyn(&jp_row, ZBX_PROTO_TAG_VALUE, &value, &value_alloc)) { if (SUCCEED == set_result_type(&results[i], items[i].value_type, items[i].data_type, value)) errcodes[i] = SUCCEED; else errcodes[i] = NOTSUPPORTED; } else if (SUCCEED == zbx_json_value_by_name_dyn(&jp_row, ZBX_PROTO_TAG_ERROR, &value, &value_alloc)) { SET_MSG_RESULT(&results[i], zbx_strdup(NULL, value)); errcodes[i] = NOTSUPPORTED; } else { SET_MSG_RESULT(&results[i], zbx_strdup(NULL, "Cannot get item value or error message")); errcodes[i] = AGENT_ERROR; } } ret = SUCCEED; } else if (0 == strcmp(value, ZBX_PROTO_VALUE_FAILED)) { if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_ERROR, error, max_error_len)) ret = NETWORK_ERROR; else zbx_strlcpy(error, "Cannot get error message describing reasons for failure", max_error_len); goto exit; } else { zbx_snprintf(error, max_error_len, "Bad '%s' tag value '%s' in received JSON", ZBX_PROTO_TAG_RESPONSE, value); goto exit; } } else { zbx_strlcpy(error, "Cannot open received JSON", max_error_len); goto exit; } exit: zbx_free(value); return ret; }
/****************************************************************************** * * * Function: send_list_of_active_checks_json * * * * Purpose: send list of active checks to the host * * * * Parameters: sock - open socket of server-agent connection * * json - request buffer * * * * Return value: SUCCEED - list of active checks sent successfully * * FAIL - an error occurred * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ int send_list_of_active_checks_json(zbx_socket_t *sock, struct zbx_json_parse *jp) { const char *__function_name = "send_list_of_active_checks_json"; char host[HOST_HOST_LEN_MAX], tmp[MAX_STRING_LEN], ip[INTERFACE_IP_LEN_MAX], error[MAX_STRING_LEN], *host_metadata = NULL; struct zbx_json json; int ret = FAIL, i; zbx_uint64_t hostid; size_t host_metadata_alloc = 1; /* for at least NUL-termination char */ unsigned short port; zbx_vector_uint64_t itemids; zbx_vector_ptr_t regexps; zbx_vector_str_t names; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); zbx_vector_ptr_create(®exps); zbx_vector_str_create(&names); if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOST, host, sizeof(host))) { zbx_snprintf(error, MAX_STRING_LEN, "%s", zbx_json_strerror()); goto error; } host_metadata = zbx_malloc(host_metadata, host_metadata_alloc); if (FAIL == zbx_json_value_by_name_dyn(jp, ZBX_PROTO_TAG_HOST_METADATA, &host_metadata, &host_metadata_alloc)) { *host_metadata = '\0'; } if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_IP, ip, sizeof(ip))) strscpy(ip, sock->peer); if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_PORT, tmp, sizeof(tmp))) *tmp = '\0'; if (FAIL == is_ushort(tmp, &port)) port = ZBX_DEFAULT_AGENT_PORT; if (FAIL == get_hostid_by_host(sock, host, ip, port, host_metadata, &hostid, error)) goto error; zbx_vector_uint64_create(&itemids); get_list_of_active_checks(hostid, &itemids); zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN); zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING); zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA); if (0 != itemids.values_num) { DC_ITEM *dc_items; int *errcodes, now; zbx_config_t cfg; dc_items = zbx_malloc(NULL, sizeof(DC_ITEM) * itemids.values_num); errcodes = zbx_malloc(NULL, sizeof(int) * itemids.values_num); DCconfig_get_items_by_itemids(dc_items, itemids.values, errcodes, itemids.values_num); zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED); now = time(NULL); for (i = 0; i < itemids.values_num; i++) { if (SUCCEED != errcodes[i]) { zabbix_log(LOG_LEVEL_DEBUG, "%s() Item [" ZBX_FS_UI64 "] was not found in the" " server cache. Not sending now.", __function_name, itemids.values[i]); continue; } if (ITEM_STATUS_ACTIVE != dc_items[i].status) continue; if (HOST_STATUS_MONITORED != dc_items[i].host.status) continue; if (ITEM_STATE_NOTSUPPORTED == dc_items[i].state) { if (0 == cfg.refresh_unsupported) continue; if (dc_items[i].lastclock + cfg.refresh_unsupported > now) continue; } dc_items[i].key = zbx_strdup(dc_items[i].key, dc_items[i].key_orig); substitute_key_macros(&dc_items[i].key, NULL, &dc_items[i], NULL, MACRO_TYPE_ITEM_KEY, NULL, 0); zbx_json_addobject(&json, NULL); zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, dc_items[i].key, ZBX_JSON_TYPE_STRING); if (0 != strcmp(dc_items[i].key, dc_items[i].key_orig)) { zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY_ORIG, dc_items[i].key_orig, ZBX_JSON_TYPE_STRING); } zbx_json_adduint64(&json, ZBX_PROTO_TAG_DELAY, dc_items[i].delay); /* The agent expects ALWAYS to have lastlogsize and mtime tags. */ /* Removing those would cause older agents to fail. */ zbx_json_adduint64(&json, ZBX_PROTO_TAG_LASTLOGSIZE, dc_items[i].lastlogsize); zbx_json_adduint64(&json, ZBX_PROTO_TAG_MTIME, dc_items[i].mtime); zbx_json_close(&json); zbx_itemkey_extract_global_regexps(dc_items[i].key, &names); zbx_free(dc_items[i].key); } zbx_config_clean(&cfg); DCconfig_clean_items(dc_items, errcodes, itemids.values_num); zbx_free(errcodes); zbx_free(dc_items); } zbx_vector_uint64_destroy(&itemids); zbx_json_close(&json); DCget_expressions_by_names(®exps, (const char * const *)names.values, names.values_num); if (0 < regexps.values_num) { char buffer[32]; zbx_json_addarray(&json, ZBX_PROTO_TAG_REGEXP); for (i = 0; i < regexps.values_num; i++) { zbx_expression_t *regexp = regexps.values[i]; zbx_json_addobject(&json, NULL); zbx_json_addstring(&json, "name", regexp->name, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, "expression", regexp->expression, ZBX_JSON_TYPE_STRING); zbx_snprintf(buffer, sizeof(buffer), "%d", regexp->expression_type); zbx_json_addstring(&json, "expression_type", buffer, ZBX_JSON_TYPE_INT); zbx_snprintf(buffer, sizeof(buffer), "%c", regexp->exp_delimiter); zbx_json_addstring(&json, "exp_delimiter", buffer, ZBX_JSON_TYPE_STRING); zbx_snprintf(buffer, sizeof(buffer), "%d", regexp->case_sensitive); zbx_json_addstring(&json, "case_sensitive", buffer, ZBX_JSON_TYPE_INT); zbx_json_close(&json); } zbx_json_close(&json); } zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, json.buffer); zbx_alarm_on(CONFIG_TIMEOUT); if (SUCCEED != zbx_tcp_send(sock, json.buffer)) strscpy(error, zbx_socket_strerror()); else ret = SUCCEED; zbx_alarm_off(); zbx_json_free(&json); goto out; error: zabbix_log(LOG_LEVEL_WARNING, "cannot send list of active checks to \"%s\": %s", sock->peer, error); zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN); zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, ZBX_PROTO_TAG_INFO, error, ZBX_JSON_TYPE_STRING); zabbix_log(LOG_LEVEL_DEBUG, "%s() sending [%s]", __function_name, json.buffer); ret = zbx_tcp_send(sock, json.buffer); zbx_json_free(&json); out: for (i = 0; i < names.values_num; i++) zbx_free(names.values[i]); zbx_vector_str_destroy(&names); zbx_regexp_clean_expressions(®exps); zbx_vector_ptr_destroy(®exps); zbx_free(host_metadata); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }