b6b545927531ca0bc904691353905d6e1f666168
[sim/o1-interface.git] / ntsimulator / src / generic-notifications / generic-notifications.c
1 /*************************************************************************
2 *
3 * Copyright 2019 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 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <inttypes.h>
23 #include <time.h>
24 #include <math.h>
25 #include <sys/time.h>
26 #include <cjson/cJSON.h>
27 #include <string.h>
28 #include <assert.h>
29
30 #include "sysrepo.h"
31 #include "sysrepo/values.h"
32 #include "libyang/libyang.h"
33
34 #include "utils.h"
35
36 #define EMEM printf("Memory allocation failed (%s:%d)", __FILE__, __LINE__);
37
38 static int op_set_srval(struct lyd_node *node, char *path, int dup, sr_val_t *val, char **val_buf)
39 {
40     uint32_t i;
41     struct lyd_node_leaf_list *leaf;
42     const char *str;
43
44     if (!dup) {
45         assert(val_buf);
46         (*val_buf) = NULL;
47     }
48
49     if (!dup) {
50         val->xpath = path;
51     } else {
52         sr_val_set_xpath(val, path);
53     }
54     val->dflt = 0;
55     val->data.int64_val = 0;
56
57     switch (node->schema->nodetype) {
58     case LYS_CONTAINER:
59         val->type = ((struct lys_node_container *)node->schema)->presence ? SR_CONTAINER_PRESENCE_T : SR_CONTAINER_T;
60         break;
61     case LYS_LIST:
62         val->type = SR_LIST_T;
63         break;
64     case LYS_LEAF:
65     case LYS_LEAFLIST:
66         leaf = (struct lyd_node_leaf_list *)node;
67 settype:
68         switch (leaf->value_type) {
69         case LY_TYPE_BINARY:
70             val->type = SR_BINARY_T;
71             str = leaf->value.binary;
72             if (dup) {
73                 sr_val_set_str_data(val, val->type, str);
74             } else {
75                 val->data.string_val = (char *)str;
76             }
77             if (NULL == val->data.binary_val) {
78                 EMEM;
79                 return -1;
80             }
81             break;
82         case LY_TYPE_BITS:
83             val->type = SR_BITS_T;
84             str = leaf->value_str;
85             if (dup) {
86                 sr_val_set_str_data(val, val->type, str);
87             } else {
88                 val->data.string_val = (char *)str;
89             }
90             break;
91         case LY_TYPE_BOOL:
92             val->type = SR_BOOL_T;
93             val->data.bool_val = leaf->value.bln;
94             break;
95         case LY_TYPE_DEC64:
96             val->type = SR_DECIMAL64_T;
97             val->data.decimal64_val = (double)leaf->value.dec64;
98             for (i = 0; i < ((struct lys_node_leaf *)leaf->schema)->type.info.dec64.dig; i++) {
99                 /* shift decimal point */
100                 val->data.decimal64_val *= 0.1;
101             }
102             break;
103         case LY_TYPE_EMPTY:
104             val->type = SR_LEAF_EMPTY_T;
105             break;
106         case LY_TYPE_ENUM:
107             val->type = SR_ENUM_T;
108             str = leaf->value.enm->name;
109             if (dup) {
110                 sr_val_set_str_data(val, val->type, str);
111             } else {
112                 val->data.string_val = (char *)str;
113             }
114             if (NULL == val->data.enum_val) {
115                 EMEM;
116                 return -1;
117             }
118             break;
119         case LY_TYPE_IDENT:
120             val->type = SR_IDENTITYREF_T;
121
122             str = malloc(strlen(lys_main_module(leaf->value.ident->module)->name) + 1 + strlen(leaf->value.ident->name) + 1);
123             if (NULL == str) {
124                 EMEM;
125                 return -1;
126             }
127             sprintf((char *)str, "%s:%s", lys_main_module(leaf->value.ident->module)->name, leaf->value.ident->name);
128             val->data.identityref_val = (char *)str;
129             if (!dup) {
130                 (*val_buf) = (char *)str;
131             }
132             break;
133         case LY_TYPE_INST:
134             val->type = SR_INSTANCEID_T;
135             if (dup) {
136                 sr_val_set_str_data(val, val->type, leaf->value_str);
137             } else {
138                 val->data.string_val = (char *)leaf->value_str;
139             }
140             break;
141         case LY_TYPE_STRING:
142             val->type = SR_STRING_T;
143             str = leaf->value.string;
144             if (dup) {
145                 sr_val_set_str_data(val, val->type, str);
146             } else {
147                 val->data.string_val = (char *)str;
148             }
149             if (NULL == val->data.string_val) {
150                 EMEM;
151                 return -1;
152             }
153             break;
154         case LY_TYPE_INT8:
155             val->type = SR_INT8_T;
156             val->data.int8_val = leaf->value.int8;
157             break;
158         case LY_TYPE_UINT8:
159             val->type = SR_UINT8_T;
160             val->data.uint8_val = leaf->value.uint8;
161             break;
162         case LY_TYPE_INT16:
163             val->type = SR_INT16_T;
164             val->data.int16_val = leaf->value.int16;
165             break;
166         case LY_TYPE_UINT16:
167             val->type = SR_UINT16_T;
168             val->data.uint16_val = leaf->value.uint16;
169             break;
170         case LY_TYPE_INT32:
171             val->type = SR_INT32_T;
172             val->data.int32_val = leaf->value.int32;
173             break;
174         case LY_TYPE_UINT32:
175             val->type = SR_UINT32_T;
176             val->data.uint32_val = leaf->value.uint32;
177             break;
178         case LY_TYPE_INT64:
179             val->type = SR_INT64_T;
180             val->data.int64_val = leaf->value.int64;
181             break;
182         case LY_TYPE_UINT64:
183             val->type = SR_UINT64_T;
184             val->data.uint64_val = leaf->value.uint64;
185             break;
186         case LY_TYPE_LEAFREF:
187             leaf = (struct lyd_node_leaf_list *)leaf->value.leafref;
188             goto settype;
189         default:
190             //LY_DERIVED, LY_UNION
191             val->type = SR_UNKNOWN_T;
192             break;
193         }
194         break;
195     default:
196         val->type = SR_UNKNOWN_T;
197         break;
198     }
199
200     return 0;
201 }
202
203 static int op_add_srval(sr_val_t **values, size_t *values_cnt, struct lyd_node *node)
204 {
205     char *path, *buf = NULL;
206     int ret;
207
208     if (sr_realloc_values(*values_cnt, *values_cnt + 1, values) != SR_ERR_OK) {
209         return -1;
210     }
211     ++(*values_cnt);
212
213     path = lyd_path(node);
214     ret = op_set_srval(node, path, 1, &(*values)[*values_cnt - 1], &buf);
215     free(path);
216     free(buf);
217
218     return ret;
219 }
220
221
222 static int send_dummy_notif(sr_session_ctx_t *sess, const char *module_name, const char *notif_object)
223 {
224         int rc = SR_ERR_OK;
225
226     struct ly_ctx *ctx = NULL;
227     struct lyd_node *data = NULL, *iter = NULL;
228     sr_schema_t *schemas = NULL;
229     size_t schema_cnt = 0;
230     sr_val_t *vnotif = NULL;
231         size_t num_values= 0;
232
233     ctx = ly_ctx_new("/etc/sysrepo/yang", LY_CTX_ALLIMPLEMENTED);
234     if (!ctx) 
235     {
236        printf("Creating context failed...\n");
237        return SR_ERR_OPERATION_FAILED;
238     }
239
240     rc = sr_list_schemas(sess, &schemas, &schema_cnt);
241     if (rc != SR_ERR_OK)
242     {
243         printf("Could not list the schemas from the sysrepo session...\n");
244         return SR_ERR_OPERATION_FAILED;
245     }
246
247     const char *schema_path = NULL;
248
249     for (size_t i = 0; i < schema_cnt; i++) 
250     {
251         schema_path = schemas[i].revision.file_path_yang;
252
253         if (NULL != schema_path && 0 == strcmp(module_name, schemas[i].module_name)) {
254             printf("Trying to install schema: %s\n", schema_path);
255             if (NULL == lys_parse_path(ctx, schema_path, LYS_IN_YANG)) 
256             {
257                 fprintf(stderr, "Failed to parse schema file '%s': %s (%s)",
258                         schema_path, ly_errmsg(ctx), ly_errpath(ctx));
259                 return SR_ERR_OPERATION_FAILED;
260                 // continue;
261             }
262             break;
263         }
264     }
265
266     data = lyd_parse_mem(ctx, notif_object, LYD_JSON, LYD_OPT_NOTIF);
267     if (data == NULL)
268     {
269         printf("Could not create JSON object, not valid!\n");
270         return SR_ERR_VALIDATION_FAILED;
271     }
272
273     LY_TREE_FOR(data->child, iter) {
274         if (op_add_srval(&vnotif, &num_values, iter)) {
275             printf("Could not transform libyang into sysrepo values...\n");
276             return SR_ERR_OPERATION_FAILED;
277         }
278     }
279
280     if (num_values == 0)
281     {
282         printf("Could not generate objects for sending inside the notif...\n");
283         return SR_ERR_OPERATION_FAILED;
284     }
285
286     rc = sr_event_notif_send(sess, lyd_path(data), vnotif, num_values, SR_EV_NOTIF_DEFAULT);
287     if (rc != SR_ERR_OK)
288     {
289         printf("Error: could not send notification...\n");
290         return SR_ERR_OPERATION_FAILED;
291     }
292
293         return rc;
294 }
295
296 int
297 main(int argc, char **argv)
298 {
299     sr_conn_ctx_t *connection = NULL;
300     sr_session_ctx_t *session = NULL;
301     sr_subscription_ctx_t *subscription = NULL;
302     int rc = SR_ERR_OK;
303
304     setbuf(stdout, NULL);
305     setbuf(stderr, NULL);
306
307     const char *notif_object = NULL;
308     const char *module_name = NULL;
309
310     if (argc != 3) {
311         printf("%s <module_name> <notification-object>\n", argv[0]);
312         return EXIT_FAILURE;
313     }
314     module_name = argv[1];
315     notif_object = argv[2];
316
317     /* connect to sysrepo */
318     rc = sr_connect("generic_notifications", SR_CONN_DEFAULT, &connection);
319     if (SR_ERR_OK != rc) {
320         fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc));
321         goto cleanup;
322     }
323
324     /* start session */
325     rc = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT, &session);
326     if (SR_ERR_OK != rc) {
327         fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc));
328         goto cleanup;
329     }
330
331     rc = send_dummy_notif(session, module_name, notif_object);
332     if (SR_ERR_OK != rc) {
333         fprintf(stderr, "Error by send_dummy_notif: %s\n", sr_strerror(rc));
334         goto cleanup;
335     }
336  
337     printf("Application exit reached, exiting.\n");
338
339     return 0;
340
341 cleanup:
342     if (NULL != subscription) {
343         sr_unsubscribe(session, subscription);
344     }
345     if (NULL != session) {
346         sr_session_stop(session);
347     }
348     if (NULL != connection) {
349         sr_disconnect(connection);
350     }
351     printf("Error encountered. Exiting...");
352     return rc;
353 }
354
355
356
357