Bugfix for SIM-63
[sim/o1-interface.git] / ntsimulator / ntsim-ng / features / ves_file_ready / ves_file_ready.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_file_ready.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 <assert.h>
27
28 #include <sysrepo.h>
29 #include <sysrepo/values.h>
30
31 #include "core/framework.h"
32 #include "core/session.h"
33
34 #define FILE_READY_RPC_SCHEMA_XPATH         "/nts-network-function:invoke-ves-pm-file-ready"
35
36 static int ves_file_ready_invoke_pm_cb(sr_session_ctx_t *session, const char *path, const sr_val_t *input, const size_t input_cnt, sr_event_t event, uint32_t request_id, sr_val_t **output, size_t *output_cnt, void *private_data);
37 static int ves_file_ready_send_message(sr_session_ctx_t *session, const char *file_location, int port);
38 static cJSON* ves_create_file_ready_fields(const char* file_location);
39 static void ves_file_ready_vsftp_daemon_init(void);
40 static void ves_file_ready_vsftp_daemon_deinit(void);
41
42 static sr_subscription_ctx_t *ves_file_ready_subscription = 0;
43
44 int ves_file_ready_feature_get_status(void) {
45     return (ves_file_ready_subscription != 0);
46 }
47
48 int ves_file_ready_feature_start(sr_session_ctx_t *current_session) {
49     assert(current_session);
50     assert_session();
51
52     if(ves_file_ready_subscription == 0) {
53         int rc = sr_rpc_subscribe(current_session, FILE_READY_RPC_SCHEMA_XPATH, ves_file_ready_invoke_pm_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &ves_file_ready_subscription);
54         if(rc != SR_ERR_OK) {
55             log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
56             return NTS_ERR_FAILED;
57         }
58
59         ves_file_ready_vsftp_daemon_init();
60     }
61
62     return NTS_ERR_OK;
63 }
64
65 int ves_file_ready_feature_stop(void) {
66     assert_session();
67
68     if(ves_file_ready_subscription) {
69         int rc = sr_unsubscribe(ves_file_ready_subscription);
70         if(rc != SR_ERR_OK) {
71             log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
72             return NTS_ERR_FAILED;
73         }
74
75         ves_file_ready_vsftp_daemon_deinit();
76         ves_file_ready_subscription = 0;
77     }
78
79     return NTS_ERR_OK;
80 }
81
82 static void ves_file_ready_vsftp_daemon_init(void) {
83     system("/usr/sbin/vsftpd &");
84 }
85
86 static void ves_file_ready_vsftp_daemon_deinit(void) {
87     system("killall -9 vsftpd");
88 }
89
90 static int ves_file_ready_invoke_pm_cb(sr_session_ctx_t *session, const char *path, const sr_val_t *input, const size_t input_cnt, sr_event_t event, uint32_t request_id, sr_val_t **output, size_t *output_cnt, void *private_data) {
91     int ssh_base_port = 0;
92     int tls_base_port = 0;
93     nts_mount_point_addressing_method_t mp = nts_mount_point_addressing_method_get(session);
94     if(mp == UNKNOWN_MAPPING) {
95         log_error("mount-point-addressing-method failed\n");
96         return NTS_ERR_FAILED;
97     }
98     else if(mp == DOCKER_MAPPING) {
99         ssh_base_port = STANDARD_NETCONF_PORT;
100         tls_base_port = ssh_base_port + framework_environment.settings.ssh_connections;
101     }
102     else {
103         ssh_base_port = framework_environment.host.ssh_base_port;
104         tls_base_port = framework_environment.host.tls_base_port;       
105     }
106
107     int failed = 0;
108
109     if((framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections) > 1) {
110         for(int port = ssh_base_port; port < ssh_base_port + framework_environment.settings.ssh_connections; port++) {
111             int rc = ves_file_ready_send_message(session, input[0].data.string_val, port);
112             if(rc != NTS_ERR_OK) {
113                 log_error("ves_file_ready_send_message failed\n");
114                 failed++;
115             }
116         }
117
118         for(int port = tls_base_port; port < tls_base_port + framework_environment.settings.tls_connections; port++) {
119             int rc = ves_file_ready_send_message(session, input[0].data.string_val, port);
120             if(rc != NTS_ERR_OK) {
121                 log_error("ves_file_ready_send_message failed\n");
122                 failed++;
123             }
124         }
125     }
126     else {
127         int rc = ves_file_ready_send_message(session, input[0].data.string_val, 0);
128         if(rc != NTS_ERR_OK) {
129             log_error("ves_file_ready_send_message failed\n");
130             failed++;
131         }
132     }
133     
134
135     *output_cnt = 1;
136     int rc = sr_new_values(*output_cnt, output);
137     if(SR_ERR_OK != rc) {
138         return rc;
139     }
140
141     rc = sr_val_set_xpath(output[0], FILE_READY_RPC_SCHEMA_XPATH"/status");
142     if(SR_ERR_OK != rc) {
143         return rc;
144     }
145     
146     if(failed != 0) {
147         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "ERROR");
148     }
149     else {
150         rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
151     }
152
153     return rc;
154 }
155
156 static int ves_file_ready_send_message(sr_session_ctx_t *session, const char *file_location, int port) {
157     assert(session);
158     assert(file_location);
159
160     int rc;
161     static int sequence_number = 0;
162
163     cJSON *post_data_json = cJSON_CreateObject();
164     if(post_data_json == 0) {
165         log_error("could not create cJSON object\n");
166         return NTS_ERR_FAILED;
167     }
168
169     cJSON *event = cJSON_CreateObject();
170     if(event == 0) {
171         log_error("could not create cJSON object\n");
172         cJSON_Delete(post_data_json);
173         return NTS_ERR_FAILED;
174     }
175     
176     if(cJSON_AddItemToObject(post_data_json, "event", event) == 0) {
177         log_error("cJSON_AddItemToObject failed\n");
178         cJSON_Delete(post_data_json);
179         return NTS_ERR_FAILED;
180     }
181
182     cJSON *common_event_header = ves_create_common_event_header("notification", "Notification-gnb_Nokia-FileReady", framework_environment.settings.hostname, port, "Normal", sequence_number++);
183     if(common_event_header == 0) {
184         log_error("could not create cJSON object\n");
185         cJSON_Delete(post_data_json);
186         return NTS_ERR_FAILED;
187     }
188     
189     if(cJSON_AddItemToObject(event, "commonEventHeader", common_event_header) == 0) {
190         log_error("cJSON_AddItemToObject failed\n");
191         cJSON_Delete(post_data_json);
192         return NTS_ERR_FAILED;
193     }
194
195     cJSON *file_ready_fields = ves_create_file_ready_fields(file_location);
196     if(file_ready_fields == 0) {
197         log_error("could not create cJSON object\n");
198         cJSON_Delete(post_data_json);
199         return NTS_ERR_FAILED;
200     }
201     
202     if(cJSON_AddItemToObject(event, "notificationFields", file_ready_fields) == 0) {
203         log_error("cJSON_AddItemToObject failed\n");
204         cJSON_Delete(post_data_json);
205         return NTS_ERR_FAILED;
206     }
207
208     char *post_data = cJSON_PrintUnformatted(post_data_json);
209     cJSON_Delete(post_data_json);
210     if(post_data == 0) {
211         log_error("cJSON_PrintUnformatted failed\n");
212         return NTS_ERR_FAILED;
213     }
214
215
216     ves_details_t *ves_details = ves_endpoint_details_get(session);
217     if(!ves_details) {
218         log_error("ves_endpoint_details_get failed\n");
219         free(post_data);
220         return NTS_ERR_FAILED;
221     }
222     
223     rc = http_request(ves_details->url, ves_details->username, ves_details->password, "POST", post_data, 0, 0);
224     ves_details_free(ves_details);
225     free(post_data);
226     
227     if(rc != NTS_ERR_OK) {
228         log_error("http_request failed\n");
229         return NTS_ERR_FAILED;
230     }
231
232     return NTS_ERR_OK;
233 }
234
235 static cJSON* ves_create_file_ready_fields(const char* file_location) {
236     assert(file_location);
237
238     cJSON *file_ready_fields = cJSON_CreateObject();
239     if(file_ready_fields == 0) {
240         log_error("could not create JSON object\n");
241         return 0;
242     }
243
244     if(cJSON_AddStringToObject(file_ready_fields, "changeIdentifier", "PM_MEAS_FILES") == 0) {
245         log_error("cJSON_AddStringToObject failed\n");
246         cJSON_Delete(file_ready_fields);
247         return 0;
248     }
249
250     if(cJSON_AddStringToObject(file_ready_fields, "changeType", "FileReady") == 0) {
251         log_error("cJSON_AddStringToObject failed\n");
252         cJSON_Delete(file_ready_fields);
253         return 0;
254     }
255
256     if(cJSON_AddStringToObject(file_ready_fields, "notificationFieldsVersion", "2.0") == 0) {
257         log_error("cJSON_AddStringToObject failed\n");
258         cJSON_Delete(file_ready_fields);
259         return 0;
260     }
261
262     cJSON *array_of_named_hash_map = cJSON_CreateArray();
263     if(array_of_named_hash_map == 0) {
264         log_error("could not create JSON object\n");
265         cJSON_Delete(file_ready_fields);
266         return 0;
267     }
268     
269     if(cJSON_AddItemToObject(file_ready_fields, "arrayOfNamedHashMap", array_of_named_hash_map) == 0) {
270         log_error("cJSON_AddStringToObject failed\n");
271         cJSON_Delete(file_ready_fields);
272         return 0;
273     }
274
275     cJSON *additional_fields_entry = cJSON_CreateObject();
276     if(additional_fields_entry == 0) {
277         log_error("could not create JSON object\n");
278         cJSON_Delete(file_ready_fields);
279         return 0;
280     }
281
282     char *filename = strrchr(file_location, '/');
283
284     if(filename == 0) {
285         if(cJSON_AddStringToObject(additional_fields_entry, "name", "dummy_file.tar.gz") == 0) {
286             log_error("cJSON_AddStringToObject failed\n");
287             cJSON_Delete(file_ready_fields);
288             return 0;
289         }
290     }
291     else {
292         if(cJSON_AddStringToObject(additional_fields_entry, "name", filename + 1) == 0) {
293             log_error("cJSON_AddStringToObject failed\n");
294             cJSON_Delete(file_ready_fields);
295             return 0;
296         }
297     }
298
299     cJSON *hash_map = cJSON_CreateObject();
300     if(hash_map == 0) {
301         log_error("could not create JSON object\n");
302         cJSON_Delete(file_ready_fields);
303         return 0;
304     }
305     
306     if(cJSON_AddItemToObject(additional_fields_entry, "hashMap", hash_map) == 0) {
307         log_error("cJSON_AddStringToObject failed\n");
308         cJSON_Delete(file_ready_fields);
309         return 0;
310     }
311
312     if(cJSON_AddStringToObject(hash_map, "location", file_location) == 0) {
313         log_error("cJSON_AddStringToObject failed\n");
314         cJSON_Delete(file_ready_fields);
315         return 0;
316     }
317
318     if(cJSON_AddStringToObject(hash_map, "compression", "gzip") == 0) {
319         log_error("cJSON_AddStringToObject failed\n");
320         cJSON_Delete(file_ready_fields);
321         return 0;
322     }
323
324     if(cJSON_AddStringToObject(hash_map, "fileFormatType", "org.3GPP.32.435#measCollec") == 0) {
325         log_error("cJSON_AddStringToObject failed\n");
326         cJSON_Delete(file_ready_fields);
327         return 0;
328     }
329
330     if(cJSON_AddStringToObject(hash_map, "fileFormatVersion", "V5") == 0) {
331         log_error("cJSON_AddStringToObject failed\n");
332         cJSON_Delete(file_ready_fields);
333         return 0;
334     }
335
336     if(cJSON_AddItemToArray(array_of_named_hash_map, additional_fields_entry) == 0) {
337         log_error("cJSON_AddStringToObject failed\n");
338         cJSON_Delete(file_ready_fields);
339         return 0;
340     }
341
342     return file_ready_fields;
343 }