4bfc075fe5808653a7ec4c3a97009befb0d1c5f2
[sim/o1-interface.git] / ntsimulator / ntsim-ng / features / ves_heartbeat / ves_heartbeat.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 "ves_heartbeat.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include "utils/http_client.h"
24 #include "utils/nts_utils.h"
25 #include <stdio.h>
26 #include <time.h>
27 #include <inttypes.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <pthread.h>
31
32 #include "core/session.h"
33 #include "core/framework.h"
34
35 #define HEARTBEAT_SCHEMA_XPATH      "/nts-network-function:simulation/network-function/ves/heartbeat-period" 
36
37 static volatile int ves_heartbeat_period;
38 static int ves_sequence_number;
39
40 static pthread_t ves_heartbeat_thread;
41 static pthread_mutex_t ves_heartbeat_lock;
42
43
44 //mutex-guarded access
45 static int ves_heartbeat_period_get(void);
46 static void ves_heartbeat_period_set(int new_period);
47
48 static int ves_heartbeat_send_ves_message(void);
49 static void *ves_heartbeat_thread_routine(void *arg);
50 static cJSON* ves_create_heartbeat_fields(int heartbeat_period);
51 static int heartbeat_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data);
52
53 int ves_heartbeat_feature_start(sr_session_ctx_t *current_session) {
54     assert_session();
55
56     sr_val_t *value = 0;
57     if(pthread_mutex_init(&ves_heartbeat_lock, NULL) != 0) { 
58         log_error("mutex init has failed"); 
59         return NTS_ERR_FAILED; 
60     }
61
62     ves_heartbeat_period = 0;
63     ves_sequence_number = 0;
64
65     int rc = sr_get_item(current_session, HEARTBEAT_SCHEMA_XPATH, 0, &value);
66     if(rc == SR_ERR_OK) {
67         ves_heartbeat_period_set(value->data.uint16_val);
68         sr_free_val(value);
69     }
70     else if(rc != SR_ERR_NOT_FOUND) {
71         log_error("sr_get_item failed");
72     }
73
74     rc = sr_module_change_subscribe(current_session, "nts-network-function", HEARTBEAT_SCHEMA_XPATH, heartbeat_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
75     if(rc != SR_ERR_OK) {
76         log_error("could not subscribe to heartbeat");
77         return NTS_ERR_FAILED;
78     }
79
80     if(pthread_create(&ves_heartbeat_thread, 0, ves_heartbeat_thread_routine, 0)) {
81         log_error("could not create thread for heartbeat");
82         return NTS_ERR_FAILED;
83     }
84
85     return NTS_ERR_OK;
86 }
87
88 static int ves_heartbeat_period_get(void) {
89     pthread_mutex_lock(&ves_heartbeat_lock);
90     int ret = ves_heartbeat_period;
91     pthread_mutex_unlock(&ves_heartbeat_lock);
92     return ret;
93 }
94
95 static void ves_heartbeat_period_set(int new_period) {
96     pthread_mutex_lock(&ves_heartbeat_lock);
97     ves_heartbeat_period = new_period;
98     pthread_mutex_unlock(&ves_heartbeat_lock);
99 }
100
101 static int ves_heartbeat_send_ves_message(void) {
102     char *hostname_string = framework_environment.hostname;
103     cJSON *post_data_json = cJSON_CreateObject();
104     if(post_data_json == 0) {
105         log_error("cJSON_CreateObject failed");
106         return NTS_ERR_FAILED;
107     }
108
109     cJSON *event = cJSON_CreateObject();
110     if(event == 0) {
111         log_error("cJSON_CreateObject failed");
112         cJSON_Delete(post_data_json);
113         return NTS_ERR_FAILED;
114     }
115     
116     if(cJSON_AddItemToObject(post_data_json, "event", event) == 0) {
117         log_error("cJOSN_AddItemToObject failed");
118         cJSON_Delete(post_data_json);
119         return NTS_ERR_FAILED;
120     }
121
122     cJSON *common_event_header = ves_create_common_event_header("heartbeat", "Controller", hostname_string, "Low", ves_sequence_number++);
123     if(common_event_header == 0) {
124         log_error("ves_create_common_event_header failed");
125         cJSON_Delete(post_data_json);
126         return NTS_ERR_FAILED;
127     }
128     
129     if(cJSON_AddItemToObject(event, "commonEventHeader", common_event_header) == 0) {
130         log_error("cJOSN_AddItemToObject failed");
131         cJSON_Delete(post_data_json);
132         return NTS_ERR_FAILED;
133     }
134
135     cJSON *heartbeat_fields = ves_create_heartbeat_fields(ves_heartbeat_period_get());
136     if(heartbeat_fields == 0) {
137         log_error("ves_create_heartbeat_fields failed");
138         cJSON_Delete(post_data_json);
139         return NTS_ERR_FAILED;
140     }
141     
142     if(cJSON_AddItemToObject(event, "heartbeatFields", heartbeat_fields) == 0) {
143         log_error("cJOSN_AddItemToObject failed");
144         cJSON_Delete(post_data_json);
145         return NTS_ERR_FAILED;
146     }
147
148     char *post_data = cJSON_PrintUnformatted(post_data_json);
149     cJSON_Delete(post_data_json);
150     if(post_data == 0) {
151         log_error("cJSON_PrintUnformatted failed");
152         return NTS_ERR_FAILED;
153     }
154
155     ves_details_t *ves_details = ves_endpoint_details_get(0);
156     if(!ves_details) {
157         log_error("ves_endpoint_details_get failed");
158         free(post_data);
159         return NTS_ERR_FAILED;
160     }
161     
162     int rc = http_request(ves_details->url, ves_details->username, ves_details->password, "POST", post_data, 0, 0);
163     ves_details_free(ves_details);
164     free(post_data);
165     
166     if(rc != NTS_ERR_OK) {
167         log_error("http_request failed");
168         return NTS_ERR_FAILED;
169     }
170
171     return NTS_ERR_OK;
172 }
173
174 static void *ves_heartbeat_thread_routine(void *arg) {
175     int current_heartbeat_period = 0;
176     unsigned int timer_counter = 0;
177
178     while(!framework_sigint) {
179         current_heartbeat_period = ves_heartbeat_period_get();
180         timer_counter++;
181
182         if((timer_counter >= current_heartbeat_period) && (current_heartbeat_period > 0)) {
183             timer_counter = 0;
184
185             int rc = ves_heartbeat_send_ves_message();
186             if(rc != NTS_ERR_FAILED) {
187                 log_error("could not send VES heartbeat");
188             }
189         }
190
191         sleep(1);
192     }
193
194     return 0;
195 }
196
197 static cJSON* ves_create_heartbeat_fields(int heartbeat_period) {
198     cJSON *heartbeat_fields = cJSON_CreateObject();
199     if(heartbeat_fields == 0) {
200         log_error("could not create JSON object");
201         return 0;
202     }
203
204     if(cJSON_AddStringToObject(heartbeat_fields, "heartbeatFieldsVersion", "3.0") == 0) {
205         log_error("cJSON_Add*ToObject failed");
206         cJSON_Delete(heartbeat_fields);
207         return 0;
208     }
209
210     if(cJSON_AddNumberToObject(heartbeat_fields, "heartbeatInterval", (double)(heartbeat_period)) == 0) {
211         log_error("cJSON_Add*ToObject failed");
212         cJSON_Delete(heartbeat_fields);
213         return 0;
214     }
215
216     cJSON *additional_fields = cJSON_CreateObject();
217     if(additional_fields == 0) {
218         log_error("could not create JSON object");
219         log_error("cJSON_Add*ToObject failed");
220         cJSON_Delete(heartbeat_fields);
221         return 0;
222     }
223     
224     if(cJSON_AddItemToObject(heartbeat_fields, "additionalFields", additional_fields) == 0) {
225         log_error("cJSON_Add*ToObject failed");
226         cJSON_Delete(heartbeat_fields);
227         return 0;
228     }
229
230     char *current_date_and_time = get_current_date_and_time();
231     if(current_date_and_time == 0) {
232         log_error("get_current_date_and_time failed");
233         cJSON_Delete(heartbeat_fields);
234         return 0;
235     }
236
237     if(cJSON_AddStringToObject(additional_fields, "eventTime", current_date_and_time) == 0) {
238         log_error("cJSON_Add*ToObject failed");
239         cJSON_Delete(heartbeat_fields);
240         free(current_date_and_time);
241         return 0;
242     }
243     free(current_date_and_time);
244
245     return heartbeat_fields;
246 }
247
248 static int heartbeat_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
249     sr_change_iter_t *it = 0;
250     int rc = SR_ERR_OK;
251     sr_change_oper_t oper;
252     sr_val_t *old_value = 0;
253     sr_val_t *new_value = 0;
254
255     if(event == SR_EV_DONE) {
256         rc = sr_get_changes_iter(session, HEARTBEAT_SCHEMA_XPATH, &it);
257         if(rc != SR_ERR_OK) {
258             log_error("sr_get_changes_iter failed");
259             return SR_ERR_VALIDATION_FAILED;
260         }
261
262         while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
263             ves_heartbeat_period_set(new_value->data.uint16_val);
264             sr_free_val(old_value);
265             sr_free_val(new_value);
266         }
267
268         sr_free_change_iter(it);
269     }
270
271     return SR_ERR_OK;
272 }