032f99c46e480ea2cf95e14183fc4e5029ea2a07
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / faults / faults_processing.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "faults.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26
27 #include <cjson/cJSON.h>
28
29 static char *fault_process_vars(const char *template, const fault_details_t *details);
30 static char *fault_process_function(const char *function);
31
32 fault_settings_t *faults_settings_read(const char *json_plain) {
33     if(json_plain == 0) {
34         return 0;
35     }
36
37     fault_settings_t *ret = (fault_settings_t *)malloc(sizeof(fault_settings_t));
38     if(ret == 0) {
39         log_error("malloc failed");
40         goto faults_settings_read_failed_cleanup;
41     }
42
43     ret->yang_notif_template = 0;
44     ret->choosing_method = 0;
45     ret->fault = 0;
46     ret->fault_count = 0;
47
48     cJSON *json = cJSON_Parse(json_plain);
49     if(!json) {
50         log_error("json parsing error: %s", cJSON_GetErrorPtr());
51         goto faults_settings_read_failed_cleanup;
52     }
53
54     cJSON *main_node = cJSON_GetObjectItem(json, "fault-rules");
55     if(main_node == 0) {
56         goto faults_settings_read_failed_cleanup;
57     }
58
59     cJSON *node = cJSON_GetObjectItem(main_node, "yang-notif-template");
60     if(node && cJSON_IsString(node)) {
61         ret->yang_notif_template = strdup(node->valuestring);
62     }
63     else {
64         log_error("could not find yang-notif-template");
65         goto faults_settings_read_failed_cleanup;
66     }
67
68     node = cJSON_GetObjectItem(main_node, "choosing-method");
69     if(node && cJSON_IsString(node)) {
70         ret->choosing_method = strdup(node->valuestring);
71     }
72     else {
73         log_error("could not find choosing-method");
74         goto faults_settings_read_failed_cleanup;
75     }
76
77     node = cJSON_GetObjectItem(main_node, "faults");
78     if(node && cJSON_IsArray(node)) {
79         cJSON *fault_detail;
80         cJSON_ArrayForEach(fault_detail, node) {
81             cJSON *object;
82             ret->fault_count++;
83             ret->fault = (fault_details_t *)realloc(ret->fault, sizeof(fault_details_t)*ret->fault_count);
84             if(ret->fault == 0) {
85                 ret->fault_count--;
86                 log_error("realloc failed");
87                 goto faults_settings_read_failed_cleanup;
88             }
89
90             ret->fault[ret->fault_count - 1].condition = 0;
91             ret->fault[ret->fault_count - 1].object = 0;
92             ret->fault[ret->fault_count - 1].severity = 0;
93             ret->fault[ret->fault_count - 1].date_time = 0;
94             ret->fault[ret->fault_count - 1].specific_problem = 0;
95             ret->fault[ret->fault_count - 1].field_name = 0;
96             ret->fault[ret->fault_count - 1].field_value = 0;
97             ret->fault[ret->fault_count - 1].field_count = 0;
98             ret->fault[ret->fault_count - 1].yang_notif_processed = 0;
99
100             cJSON_ArrayForEach(object, fault_detail) {
101                 ret->fault[ret->fault_count - 1].field_count++;
102                 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);
103                 if(ret->fault[ret->fault_count - 1].field_name == 0) {
104                     ret->fault[ret->fault_count - 1].field_count--;
105                     log_error("realloc failed");
106                     goto faults_settings_read_failed_cleanup;
107                 }
108
109                 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);
110                 if(ret->fault[ret->fault_count - 1].field_value == 0) {
111                     ret->fault[ret->fault_count - 1].field_count--;
112                     log_error("realloc failed");
113                     goto faults_settings_read_failed_cleanup;
114                 }
115
116                 asprintf(&ret->fault[ret->fault_count - 1].field_name[ret->fault[ret->fault_count - 1].field_count - 1], "%%%%%s%%%%", object->string);
117                 ret->fault[ret->fault_count - 1].field_value[ret->fault[ret->fault_count - 1].field_count - 1] = strdup(object->valuestring);
118             }
119         }
120     }
121     else {
122         log_error("could not find faults list");
123         goto faults_settings_read_failed_cleanup;
124     }
125
126     cJSON_free(json);
127     return ret;
128
129     faults_settings_read_failed_cleanup:
130     faults_settings_free(ret);
131     cJSON_free(json);
132     return 0;
133 }
134
135 void faults_settings_free(fault_settings_t *faults) {
136     if(faults) {
137         free(faults->yang_notif_template);
138         free(faults->choosing_method);
139
140         for(int i = 0; i < faults->fault_count; i++) {
141             free(faults->fault[i].condition);
142             free(faults->fault[i].object);
143             free(faults->fault[i].severity);
144             free(faults->fault[i].date_time);
145             free(faults->fault[i].specific_problem);
146
147             for(int j = 0; j < faults->fault[i].field_count; j++) {
148                 free(faults->fault[i].field_name[j]);
149                 free(faults->fault[i].field_value[j]);
150             }
151             free(faults->fault[i].field_name);
152             free(faults->fault[i].field_value);
153
154             free(faults->fault[i].yang_notif_processed);
155         }
156     }
157 }
158
159 int faults_settings_process(fault_settings_t *faults, int fault_no) {
160     assert(faults);
161     assert(fault_no < faults->fault_count);
162
163     free(faults->fault[fault_no].condition);
164     free(faults->fault[fault_no].object);
165     free(faults->fault[fault_no].severity);
166     free(faults->fault[fault_no].date_time);
167     free(faults->fault[fault_no].specific_problem);
168     free(faults->fault[fault_no].yang_notif_processed);
169
170     faults->fault[fault_no].condition = 0;
171     faults->fault[fault_no].object = 0;
172     faults->fault[fault_no].severity = 0;
173     faults->fault[fault_no].date_time = 0;
174     faults->fault[fault_no].specific_problem = 0;
175     faults->fault[fault_no].yang_notif_processed = 0;
176     
177     for(int j = 0; j < faults->fault[fault_no].field_count; j++) {
178         if(strcmp(faults->fault[fault_no].field_name[j], "%%condition%%") == 0) {
179             faults->fault[fault_no].condition = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
180         }
181         else if(strcmp(faults->fault[fault_no].field_name[j], "%%object%%") == 0) {
182             faults->fault[fault_no].object = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
183         }
184         else if(strcmp(faults->fault[fault_no].field_name[j], "%%severity%%") == 0) {
185             faults->fault[fault_no].severity = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
186         }
187         else if(strcmp(faults->fault[fault_no].field_name[j], "%%date-time%%") == 0) {
188             faults->fault[fault_no].date_time = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
189         }
190         else if(strcmp(faults->fault[fault_no].field_name[j], "%%specific-problem%%") == 0) {
191             faults->fault[fault_no].specific_problem = fault_process_vars(faults->fault[fault_no].field_value[j], &faults->fault[fault_no]);
192         }
193     }
194
195     faults->fault[fault_no].yang_notif_processed = fault_process_vars(faults->yang_notif_template, &faults->fault[fault_no]);
196
197     if(faults->fault[fault_no].condition == 0) {
198         log_error("could not find condition in fault");
199         return NTS_ERR_FAILED;
200     }
201
202     if(faults->fault[fault_no].object == 0) {
203         log_error("could not find object in fault");
204         return NTS_ERR_FAILED;
205     }
206
207     if(faults->fault[fault_no].severity == 0) {
208         log_error("could not find severity in fault");
209         return NTS_ERR_FAILED;
210     }
211
212     if(faults->fault[fault_no].date_time == 0) {
213         log_error("could not find date_time in fault");
214         return NTS_ERR_FAILED;
215     }
216
217     if(faults->fault[fault_no].specific_problem == 0) {
218         log_error("could not find specific_problem in fault");
219         return NTS_ERR_FAILED;
220     }
221
222     if(faults->fault[fault_no].yang_notif_processed == 0) {
223         log_error("could not find yang_notif_processed in fault");
224         return NTS_ERR_FAILED;
225     }
226
227     return NTS_ERR_OK;
228 }
229
230 static char *fault_process_vars(const char *template, const fault_details_t *details) {
231     assert(template);
232     assert(details);
233
234     char *ret = strdup(template);
235     if(ret == 0) {
236         log_error("strdup error");
237         return 0;
238     }
239
240     //if template is blank, do not process anything, means nc notif disabled
241     if(ret[0] == 0) {
242         return ret;
243     }
244
245     char **vars = 0;
246     int vars_count = 0;
247     
248     char **funcs = 0;
249     int funcs_count = 0;
250
251     char *var = 0;
252     char *func = 0;
253
254     //do replacements until no replacement is done
255     int replaced = 1;
256     while(replaced) {
257         replaced = 0;
258
259         var = 0;
260         vars = 0;
261         vars_count = 0;
262         func = 0;
263         funcs = 0;
264         funcs_count = 0;
265
266         char *pos_start;
267
268         //look for vars
269         pos_start = strstr(ret, "%%");
270         while(pos_start) {
271             char *pos_end = strstr(pos_start + 2, "%%");
272             int var_size = pos_end - pos_start + 2;
273             var = (char *)malloc(sizeof(char) * (var_size + 1));
274             if(var == 0) {
275                 log_error("bad malloc");
276                 goto fault_process_vars_failed;
277             }
278
279             for(int i = 0; i < var_size; i++) {
280                 var[i] = pos_start[i];
281             }
282             var[var_size] = 0;
283
284             // found var
285             vars_count++;
286             vars = (char **)realloc(vars, sizeof(char *) * vars_count);
287             if(!vars) {
288                 vars_count = 0;
289                 log_error("bad malloc");
290                 goto fault_process_vars_failed;
291             }
292
293             vars[vars_count - 1] = strdup(var);
294             if(!vars[vars_count - 1]) {
295                 vars_count--;
296                 log_error("bad malloc");
297                 goto fault_process_vars_failed;
298             }
299             free(var);
300             var = 0;
301
302             pos_start = strstr(pos_end + 2, "%%");
303         }
304
305         //look for functions
306         pos_start = strstr(ret, "$$");
307         while(pos_start) {
308             char *pos_end = strstr(pos_start + 2, "$$");
309             int func_size = pos_end - pos_start + 2;
310             func = (char *)malloc(sizeof(char) * (func_size + 1));
311             if(func == 0) {
312                 log_error("bad malloc");
313                 goto fault_process_vars_failed;
314             }
315
316             for(int i = 0; i < func_size; i++) {
317                 func[i] = pos_start[i];
318             }
319             func[func_size] = 0;
320
321             // found func
322             funcs_count++;
323             funcs = (char **)realloc(funcs, sizeof(char *) * funcs_count);
324             if(!funcs) {
325                 funcs_count = 0;
326                 log_error("bad malloc");
327                 goto fault_process_vars_failed;
328             }
329
330             funcs[funcs_count - 1] = strdup(func);
331             if(!funcs[funcs_count - 1]) {
332                 funcs_count--;
333                 log_error("bad malloc");
334                 goto fault_process_vars_failed;
335             }
336             free(func);
337             func = 0;
338
339             pos_start = strstr(pos_end + 2, "$$");
340         }
341
342         //replace vars
343         for(int i = 0; i < vars_count; i++) {
344             char *var_value = 0;
345             for(int j = 0; j < details->field_count; j++) {
346                 if(strcmp(details->field_name[j], vars[i]) == 0) {
347                     var_value = strdup(details->field_value[j]);
348                 }
349             }
350
351             if(var_value == 0) {
352                 log_error("value %s not found", vars[i]);
353                 goto fault_process_vars_failed;
354             }
355
356             ret = str_replace(ret, vars[i], var_value);
357             if(ret == 0) {
358                 free(var_value);
359                 var_value = 0;
360                 goto fault_process_vars_failed;
361             }
362
363             free(var_value);
364             var_value = 0;
365             replaced++;
366         }
367
368         //replace functions
369         for(int i = 0; i < funcs_count; i++) {
370             char *func_value = fault_process_function(funcs[i]);
371             if(func_value == 0) {
372                 log_error("function %s not found", vars[i]);
373                 goto fault_process_vars_failed;
374             }
375
376             ret = str_replace(ret, funcs[i], func_value);
377             if(ret == 0) {
378                 free(func_value);
379                 goto fault_process_vars_failed;
380             }
381
382             free(func_value);
383             func_value = 0;
384             replaced++;
385         }
386
387         for(int i = 0; i < vars_count; i++) {
388             free(vars[i]);
389         }
390         free(vars);
391         vars = 0;
392         vars_count = 0;
393
394         for(int i = 0; i < funcs_count; i++) {
395             free(funcs[i]);
396         }
397         free(funcs);
398         funcs = 0;
399         funcs_count = 0;
400     }
401
402
403     free(var);
404     free(func);
405     for(int i = 0; i < vars_count; i++) {
406         free(vars[i]);
407     }
408     free(vars);
409
410     for(int i = 0; i < funcs_count; i++) {
411         free(funcs[i]);
412     }
413     free(funcs);
414     return ret;
415
416     fault_process_vars_failed:
417     free(var);
418     free(func);
419
420     for(int i = 0; i < vars_count; i++) {
421         free(vars[i]);
422     }
423     free(vars);
424
425     for(int i = 0; i < funcs_count; i++) {
426         free(funcs[i]);
427     }
428     free(funcs);
429     return 0;
430 }
431
432 static char *fault_process_function(const char *function) {
433     assert(function);
434
435     static uint8_t uint8_counter = 0;
436     static uint16_t uint16_counter = 0;
437     static uint32_t uint32_counter = 0;
438
439     if(strcmp(function, "$$time$$") == 0) {
440         return get_current_date_and_time();
441     }
442     else if(strcmp(function, "$$uint8_counter$$") == 0) {
443         char *ret = 0;
444         asprintf(&ret, "%d", uint8_counter);
445         uint8_counter++;
446         return ret;
447     }
448     else if(strcmp(function, "$$uint16_counter$$") == 0) {
449         char *ret = 0;
450         asprintf(&ret, "%d", uint16_counter);
451         uint16_counter++;
452         return ret;
453     }
454     else if(strcmp(function, "$$uint32_counter$$") == 0) {
455         char *ret = 0;
456         asprintf(&ret, "%d", uint32_counter);
457         uint32_counter++;
458         return ret;
459     }
460
461     return 0;
462 }