/************************************************************************* * * Copyright 2019 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. ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "sysrepo.h" #include "sysrepo/values.h" #include "libyang/libyang.h" #include "utils.h" #define EMEM printf("Memory allocation failed (%s:%d)", __FILE__, __LINE__); static int op_set_srval(struct lyd_node *node, char *path, int dup, sr_val_t *val, char **val_buf) { uint32_t i; struct lyd_node_leaf_list *leaf; const char *str; if (!dup) { assert(val_buf); (*val_buf) = NULL; } if (!dup) { val->xpath = path; } else { sr_val_set_xpath(val, path); } val->dflt = 0; val->data.int64_val = 0; switch (node->schema->nodetype) { case LYS_CONTAINER: val->type = ((struct lys_node_container *)node->schema)->presence ? SR_CONTAINER_PRESENCE_T : SR_CONTAINER_T; break; case LYS_LIST: val->type = SR_LIST_T; break; case LYS_LEAF: case LYS_LEAFLIST: leaf = (struct lyd_node_leaf_list *)node; settype: switch (leaf->value_type) { case LY_TYPE_BINARY: val->type = SR_BINARY_T; str = leaf->value.binary; if (dup) { sr_val_set_str_data(val, val->type, str); } else { val->data.string_val = (char *)str; } if (NULL == val->data.binary_val) { EMEM; return -1; } break; case LY_TYPE_BITS: val->type = SR_BITS_T; str = leaf->value_str; if (dup) { sr_val_set_str_data(val, val->type, str); } else { val->data.string_val = (char *)str; } break; case LY_TYPE_BOOL: val->type = SR_BOOL_T; val->data.bool_val = leaf->value.bln; break; case LY_TYPE_DEC64: val->type = SR_DECIMAL64_T; val->data.decimal64_val = (double)leaf->value.dec64; for (i = 0; i < ((struct lys_node_leaf *)leaf->schema)->type.info.dec64.dig; i++) { /* shift decimal point */ val->data.decimal64_val *= 0.1; } break; case LY_TYPE_EMPTY: val->type = SR_LEAF_EMPTY_T; break; case LY_TYPE_ENUM: val->type = SR_ENUM_T; str = leaf->value.enm->name; if (dup) { sr_val_set_str_data(val, val->type, str); } else { val->data.string_val = (char *)str; } if (NULL == val->data.enum_val) { EMEM; return -1; } break; case LY_TYPE_IDENT: val->type = SR_IDENTITYREF_T; str = malloc(strlen(lys_main_module(leaf->value.ident->module)->name) + 1 + strlen(leaf->value.ident->name) + 1); if (NULL == str) { EMEM; return -1; } sprintf((char *)str, "%s:%s", lys_main_module(leaf->value.ident->module)->name, leaf->value.ident->name); val->data.identityref_val = (char *)str; if (!dup) { (*val_buf) = (char *)str; } break; case LY_TYPE_INST: val->type = SR_INSTANCEID_T; if (dup) { sr_val_set_str_data(val, val->type, leaf->value_str); } else { val->data.string_val = (char *)leaf->value_str; } break; case LY_TYPE_STRING: val->type = SR_STRING_T; str = leaf->value.string; if (dup) { sr_val_set_str_data(val, val->type, str); } else { val->data.string_val = (char *)str; } if (NULL == val->data.string_val) { EMEM; return -1; } break; case LY_TYPE_INT8: val->type = SR_INT8_T; val->data.int8_val = leaf->value.int8; break; case LY_TYPE_UINT8: val->type = SR_UINT8_T; val->data.uint8_val = leaf->value.uint8; break; case LY_TYPE_INT16: val->type = SR_INT16_T; val->data.int16_val = leaf->value.int16; break; case LY_TYPE_UINT16: val->type = SR_UINT16_T; val->data.uint16_val = leaf->value.uint16; break; case LY_TYPE_INT32: val->type = SR_INT32_T; val->data.int32_val = leaf->value.int32; break; case LY_TYPE_UINT32: val->type = SR_UINT32_T; val->data.uint32_val = leaf->value.uint32; break; case LY_TYPE_INT64: val->type = SR_INT64_T; val->data.int64_val = leaf->value.int64; break; case LY_TYPE_UINT64: val->type = SR_UINT64_T; val->data.uint64_val = leaf->value.uint64; break; case LY_TYPE_LEAFREF: leaf = (struct lyd_node_leaf_list *)leaf->value.leafref; goto settype; default: //LY_DERIVED, LY_UNION val->type = SR_UNKNOWN_T; break; } break; default: val->type = SR_UNKNOWN_T; break; } return 0; } static int op_add_srval(sr_val_t **values, size_t *values_cnt, struct lyd_node *node) { char *path, *buf = NULL; int ret; if (sr_realloc_values(*values_cnt, *values_cnt + 1, values) != SR_ERR_OK) { return -1; } ++(*values_cnt); path = lyd_path(node); ret = op_set_srval(node, path, 1, &(*values)[*values_cnt - 1], &buf); free(path); free(buf); return ret; } static void add_attrtibutes(sr_val_t **values_list, size_t *values_cnt, struct lyd_node *node) { struct lyd_node *iter = NULL; LY_TREE_FOR(node->child, iter) { if (op_add_srval(values_list, values_cnt, iter)) { printf("Could not transform libyang into sysrepo values...\n"); return; } if (iter->schema->nodetype == LYS_CONTAINER || iter->schema->nodetype == LYS_LIST) { add_attrtibutes(values_list, values_cnt, iter); } } } static int send_dummy_notif(sr_session_ctx_t *sess, const char *module_name, const char *notif_object) { int rc = SR_ERR_OK; struct ly_ctx *ctx = NULL; struct lyd_node *data = NULL, *iter = NULL; sr_schema_t *schemas = NULL; size_t schema_cnt = 0; sr_val_t *vnotif = NULL; size_t num_values= 0; ctx = ly_ctx_new("/etc/sysrepo/yang", LY_CTX_ALLIMPLEMENTED); if (!ctx) { printf("Creating context failed...\n"); return SR_ERR_OPERATION_FAILED; } rc = sr_list_schemas(sess, &schemas, &schema_cnt); if (rc != SR_ERR_OK) { printf("Could not list the schemas from the sysrepo session...\n"); return SR_ERR_OPERATION_FAILED; } const char *schema_path = NULL; for (size_t i = 0; i < schema_cnt; i++) { schema_path = schemas[i].revision.file_path_yang; if (NULL != schema_path && 0 == strcmp(module_name, schemas[i].module_name)) { printf("Trying to install schema: %s\n", schema_path); if (NULL == lys_parse_path(ctx, schema_path, LYS_IN_YANG)) { fprintf(stderr, "Failed to parse schema file '%s': %s (%s)", schema_path, ly_errmsg(ctx), ly_errpath(ctx)); return SR_ERR_OPERATION_FAILED; // continue; } break; } } printf("Successfully loaded schemas, trying now to parse the JSON...\n"); data = lyd_parse_mem(ctx, notif_object, LYD_JSON, LYD_OPT_NOTIF, NULL); if (data == NULL) { printf("Could not create JSON object, not valid!\n"); return SR_ERR_VALIDATION_FAILED; } printf("Successfully parsed the JSON notification object...\n"); add_attrtibutes(&vnotif, &num_values, data); if (num_values == 0) { printf("Could not generate objects for sending inside the notif...\n"); return SR_ERR_OPERATION_FAILED; } rc = sr_event_notif_send(sess, lyd_path(data), vnotif, num_values, SR_EV_NOTIF_DEFAULT); if (rc != SR_ERR_OK) { printf("Error: could not send notification...\n"); return SR_ERR_OPERATION_FAILED; } lyd_free(data); ly_ctx_destroy(ctx, NULL); sr_free_values(vnotif, num_values); printf("Successfully sent notification from module=%s with %d number of atttributes\n", module_name, num_values); return rc; } int main(int argc, char **argv) { sr_conn_ctx_t *connection = NULL; sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; setbuf(stdout, NULL); setbuf(stderr, NULL); const char *notif_object = NULL; const char *module_name = NULL; if (argc != 3) { printf("%s \n", argv[0]); return EXIT_FAILURE; } module_name = argv[1]; notif_object = argv[2]; /* connect to sysrepo */ rc = sr_connect("generic_notifications", SR_CONN_DEFAULT, &connection); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc)); goto cleanup; } /* start session */ rc = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT, &session); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc)); goto cleanup; } rc = send_dummy_notif(session, module_name, notif_object); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by send_dummy_notif: %s\n", sr_strerror(rc)); goto cleanup; } printf("Application exit reached, exiting.\n"); return 0; cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } if (NULL != session) { sr_session_stop(session); } if (NULL != connection) { sr_disconnect(connection); } printf("Error encountered. Exiting..."); return rc; }