--- /dev/null
+/*************************************************************************
+*
+* Copyright 2020 highstreet technologies GmbH and others
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+***************************************************************************/
+
+#define _GNU_SOURCE
+
+#include "faults.h"
+#include "utils/log_utils.h"
+#include "utils/sys_utils.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <cjson/cJSON.h>
+
+static char *fault_process_vars(const char *template, const fault_details_t *details);
+static char *fault_process_function(const char *function);
+
+fault_settings_t *faults_settings_read(const char *json_plain) {
+ if(json_plain == 0) {
+ return 0;
+ }
+
+ fault_settings_t *ret = (fault_settings_t *)malloc(sizeof(fault_settings_t));
+ if(ret == 0) {
+ log_error("malloc failed");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ ret->yang_notif_template = 0;
+ ret->choosing_method = 0;
+ ret->fault = 0;
+ ret->fault_count = 0;
+
+ cJSON *json = cJSON_Parse(json_plain);
+ if(!json) {
+ log_error("json parsing error: %s", cJSON_GetErrorPtr());
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ cJSON *main_node = cJSON_GetObjectItem(json, "fault-rules");
+ if(main_node == 0) {
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ cJSON *node = cJSON_GetObjectItem(main_node, "yang-notif-template");
+ if(node && cJSON_IsString(node)) {
+ ret->yang_notif_template = strdup(node->valuestring);
+ }
+ else {
+ log_error("could not find yang-notif-template");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ node = cJSON_GetObjectItem(main_node, "choosing-method");
+ if(node && cJSON_IsString(node)) {
+ ret->choosing_method = strdup(node->valuestring);
+ }
+ else {
+ log_error("could not find choosing-method");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ node = cJSON_GetObjectItem(main_node, "faults");
+ if(node && cJSON_IsArray(node)) {
+ cJSON *fault_detail;
+ cJSON_ArrayForEach(fault_detail, node) {
+ cJSON *object;
+ ret->fault_count++;
+ ret->fault = (fault_details_t *)realloc(ret->fault, sizeof(fault_details_t)*ret->fault_count);
+ if(ret->fault == 0) {
+ ret->fault_count--;
+ log_error("realloc failed");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ ret->fault[ret->fault_count - 1].condition = 0;
+ ret->fault[ret->fault_count - 1].object = 0;
+ ret->fault[ret->fault_count - 1].severity = 0;
+ ret->fault[ret->fault_count - 1].date_time = 0;
+ ret->fault[ret->fault_count - 1].specific_problem = 0;
+ ret->fault[ret->fault_count - 1].field_name = 0;
+ ret->fault[ret->fault_count - 1].field_value = 0;
+ ret->fault[ret->fault_count - 1].field_count = 0;
+ ret->fault[ret->fault_count - 1].yang_notif_processed = 0;
+
+ cJSON_ArrayForEach(object, fault_detail) {
+ ret->fault[ret->fault_count - 1].field_count++;
+ ret->fault[ret->fault_count - 1].field_name = (char **)realloc(ret->fault[ret->fault_count - 1].field_name, sizeof(char*) * ret->fault[ret->fault_count - 1].field_count);
+ if(ret->fault[ret->fault_count - 1].field_name == 0) {
+ ret->fault[ret->fault_count - 1].field_count--;
+ log_error("realloc failed");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ ret->fault[ret->fault_count - 1].field_value = (char **)realloc(ret->fault[ret->fault_count - 1].field_value, sizeof(char*) * ret->fault[ret->fault_count - 1].field_count);
+ if(ret->fault[ret->fault_count - 1].field_value == 0) {
+ ret->fault[ret->fault_count - 1].field_count--;
+ log_error("realloc failed");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ asprintf(&ret->fault[ret->fault_count - 1].field_name[ret->fault[ret->fault_count - 1].field_count - 1], "%%%%%s%%%%", object->string);
+ ret->fault[ret->fault_count - 1].field_value[ret->fault[ret->fault_count - 1].field_count - 1] = strdup(object->valuestring);
+ }
+ }
+ }
+ else {
+ log_error("could not find faults list");
+ goto faults_settings_read_failed_cleanup;
+ }
+
+ cJSON_free(json);
+ return ret;
+
+ faults_settings_read_failed_cleanup:
+ faults_settings_free(ret);
+ cJSON_free(json);
+ return 0;
+}
+
+void faults_settings_free(fault_settings_t *faults) {
+ if(faults) {
+ free(faults->yang_notif_template);
+ free(faults->choosing_method);
+
+ for(int i = 0; i < faults->fault_count; i++) {
+ free(faults->fault[i].condition);
+ free(faults->fault[i].object);
+ free(faults->fault[i].severity);
+ free(faults->fault[i].date_time);
+ free(faults->fault[i].specific_problem);
+
+ for(int j = 0; j < faults->fault[i].field_count; j++) {
+ free(faults->fault[i].field_name[j]);
+ free(faults->fault[i].field_value[j]);
+ }
+ free(faults->fault[i].field_name);
+ free(faults->fault[i].field_value);
+
+ free(faults->fault[i].yang_notif_processed);
+ }
+ }
+}
+
+int faults_settings_process(fault_settings_t *faults, int fault_no) {
+ assert(faults);
+ assert(fault_no < faults->fault_count);
+
+ free(faults->fault[fault_no].condition);
+ free(faults->fault[fault_no].object);
+ free(faults->fault[fault_no].severity);
+ free(faults->fault[fault_no].date_time);
+ free(faults->fault[fault_no].specific_problem);
+ free(faults->fault[fault_no].yang_notif_processed);
+
+ faults->fault[fault_no].condition = 0;
+ faults->fault[fault_no].object = 0;
+ faults->fault[fault_no].severity = 0;
+ faults->fault[fault_no].date_time = 0;
+ faults->fault[fault_no].specific_problem = 0;
+ faults->fault[fault_no].yang_notif_processed = 0;
+
+ for(int j = 0; j < faults->fault[fault_no].field_count; j++) {
+ if(strcmp(faults->fault[fault_no].field_name[j], "%%condition%%") == 0) {
+ faults->fault[fault_no].condition = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
+ }
+ else if(strcmp(faults->fault[fault_no].field_name[j], "%%object%%") == 0) {
+ faults->fault[fault_no].object = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
+ }
+ else if(strcmp(faults->fault[fault_no].field_name[j], "%%severity%%") == 0) {
+ faults->fault[fault_no].severity = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
+ }
+ else if(strcmp(faults->fault[fault_no].field_name[j], "%%date-time%%") == 0) {
+ faults->fault[fault_no].date_time = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
+ }
+ else if(strcmp(faults->fault[fault_no].field_name[j], "%%specific-problem%%") == 0) {
+ faults->fault[fault_no].specific_problem = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
+ }
+ }
+
+ faults->fault[fault_no].yang_notif_processed = fault_process_vars(faults->yang_notif_template, &faults->fault[fault_no]);
+
+ if(faults->fault[fault_no].condition == 0) {
+ log_error("could not find condition in fault");
+ return NTS_ERR_FAILED;
+ }
+
+ if(faults->fault[fault_no].object == 0) {
+ log_error("could not find object in fault");
+ return NTS_ERR_FAILED;
+ }
+
+ if(faults->fault[fault_no].severity == 0) {
+ log_error("could not find severity in fault");
+ return NTS_ERR_FAILED;
+ }
+
+ if(faults->fault[fault_no].date_time == 0) {
+ log_error("could not find date_time in fault");
+ return NTS_ERR_FAILED;
+ }
+
+ if(faults->fault[fault_no].specific_problem == 0) {
+ log_error("could not find specific_problem in fault");
+ return NTS_ERR_FAILED;
+ }
+
+ if(faults->fault[fault_no].yang_notif_processed == 0) {
+ log_error("could not find yang_notif_processed in fault");
+ return NTS_ERR_FAILED;
+ }
+
+ return NTS_ERR_OK;
+}
+
+static char *fault_process_vars(const char *template, const fault_details_t *details) {
+ assert(template);
+ assert(details);
+
+ char *ret = strdup(template);
+ if(ret == 0) {
+ log_error("strdup error");
+ return 0;
+ }
+
+ //if template is blank, do not process anything, means nc notif disabled
+ if(ret[0] == 0) {
+ return ret;
+ }
+
+ char **vars = 0;
+ int vars_count = 0;
+
+ char **funcs = 0;
+ int funcs_count = 0;
+
+ char *var = 0;
+ char *func = 0;
+
+ //do replacements until no replacement is done
+ int replaced = 1;
+ while(replaced) {
+ replaced = 0;
+
+ var = 0;
+ vars = 0;
+ vars_count = 0;
+ func = 0;
+ funcs = 0;
+ funcs_count = 0;
+
+ char *pos_start;
+
+ //look for vars
+ pos_start = strstr(ret, "%%");
+ while(pos_start) {
+ char *pos_end = strstr(pos_start + 2, "%%");
+ int var_size = pos_end - pos_start + 2;
+ var = (char *)malloc(sizeof(char) * (var_size + 1));
+ if(var == 0) {
+ log_error("bad malloc");
+ goto fault_process_vars_failed;
+ }
+
+ for(int i = 0; i < var_size; i++) {
+ var[i] = pos_start[i];
+ }
+ var[var_size] = 0;
+
+ // found var
+ vars_count++;
+ vars = (char **)realloc(vars, sizeof(char *) * vars_count);
+ if(!vars) {
+ vars_count = 0;
+ log_error("bad malloc");
+ goto fault_process_vars_failed;
+ }
+
+ vars[vars_count - 1] = strdup(var);
+ if(!vars[vars_count - 1]) {
+ vars_count--;
+ log_error("bad malloc");
+ goto fault_process_vars_failed;
+ }
+ free(var);
+ var = 0;
+
+ pos_start = strstr(pos_end + 2, "%%");
+ }
+
+ //look for functions
+ pos_start = strstr(ret, "$$");
+ while(pos_start) {
+ char *pos_end = strstr(pos_start + 2, "$$");
+ int func_size = pos_end - pos_start + 2;
+ func = (char *)malloc(sizeof(char) * (func_size + 1));
+ if(func == 0) {
+ log_error("bad malloc");
+ goto fault_process_vars_failed;
+ }
+
+ for(int i = 0; i < func_size; i++) {
+ func[i] = pos_start[i];
+ }
+ func[func_size] = 0;
+
+ // found func
+ funcs_count++;
+ funcs = (char **)realloc(funcs, sizeof(char *) * funcs_count);
+ if(!funcs) {
+ funcs_count = 0;
+ log_error("bad malloc");
+ goto fault_process_vars_failed;
+ }
+
+ funcs[funcs_count - 1] = strdup(func);
+ if(!funcs[funcs_count - 1]) {
+ funcs_count--;
+ log_error("bad malloc");
+ goto fault_process_vars_failed;
+ }
+ free(func);
+ func = 0;
+
+ pos_start = strstr(pos_end + 2, "$$");
+ }
+
+ //replace vars
+ for(int i = 0; i < vars_count; i++) {
+ char *var_value = 0;
+ for(int j = 0; j < details->field_count; j++) {
+ if(strcmp(details->field_name[j], vars[i]) == 0) {
+ var_value = strdup(details->field_value[j]);
+ }
+ }
+
+ if(var_value == 0) {
+ log_error("value %s not found", vars[i]);
+ goto fault_process_vars_failed;
+ }
+
+ ret = str_replace(ret, vars[i], var_value);
+ if(ret == 0) {
+ free(var_value);
+ var_value = 0;
+ goto fault_process_vars_failed;
+ }
+
+ free(var_value);
+ var_value = 0;
+ replaced++;
+ }
+
+ //replace functions
+ for(int i = 0; i < funcs_count; i++) {
+ char *func_value = fault_process_function(funcs[i]);
+ if(func_value == 0) {
+ log_error("function %s not found", vars[i]);
+ goto fault_process_vars_failed;
+ }
+
+ ret = str_replace(ret, funcs[i], func_value);
+ if(ret == 0) {
+ free(func_value);
+ goto fault_process_vars_failed;
+ }
+
+ free(func_value);
+ func_value = 0;
+ replaced++;
+ }
+
+ for(int i = 0; i < vars_count; i++) {
+ free(vars[i]);
+ }
+ free(vars);
+ vars = 0;
+ vars_count = 0;
+
+ for(int i = 0; i < funcs_count; i++) {
+ free(funcs[i]);
+ }
+ free(funcs);
+ funcs = 0;
+ funcs_count = 0;
+ }
+
+
+ free(var);
+ free(func);
+ for(int i = 0; i < vars_count; i++) {
+ free(vars[i]);
+ }
+ free(vars);
+
+ for(int i = 0; i < funcs_count; i++) {
+ free(funcs[i]);
+ }
+ free(funcs);
+ return ret;
+
+ fault_process_vars_failed:
+ free(var);
+ free(func);
+
+ for(int i = 0; i < vars_count; i++) {
+ free(vars[i]);
+ }
+ free(vars);
+
+ for(int i = 0; i < funcs_count; i++) {
+ free(funcs[i]);
+ }
+ free(funcs);
+ return 0;
+}
+
+static char *fault_process_function(const char *function) {
+ assert(function);
+
+ static uint8_t uint8_counter = 0;
+ static uint16_t uint16_counter = 0;
+ static uint32_t uint32_counter = 0;
+
+ if(strcmp(function, "$$time$$") == 0) {
+ return get_current_date_and_time();
+ }
+ else if(strcmp(function, "$$uint8_counter$$") == 0) {
+ char *ret = 0;
+ asprintf(&ret, "%d", uint8_counter);
+ uint8_counter++;
+ return ret;
+ }
+ else if(strcmp(function, "$$uint16_counter$$") == 0) {
+ char *ret = 0;
+ asprintf(&ret, "%d", uint16_counter);
+ uint16_counter++;
+ return ret;
+ }
+ else if(strcmp(function, "$$uint32_counter$$") == 0) {
+ char *ret = 0;
+ asprintf(&ret, "%d", uint32_counter);
+ uint32_counter++;
+ return ret;
+ }
+
+ return 0;
+}