int main(int argc, char **argv) { sr_conn_ctx_t *connection = NULL; sr_session_ctx_t *session = NULL; int rc = SR_ERR_OK; /* connect to sysrepo */ rc = sr_connect("example_application", 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; } /* run as an event notification subscriber */ printf("This application will be a subscriber for the 'paused' event notification of 'turing-machine'.\n"); printf("This notification is sent by the RPC handler in rpc_example and rpc_tree_example.\n"); rc = event_notif_subscriber(session); cleanup: if (NULL != session) { sr_session_stop(session); } if (NULL != connection) { sr_disconnect(connection); } return rc; }
/** * Add a device instance to a session. * * @param session The session to add to. Must not be NULL. * @param sdi The device instance to add to a session. Must not * be NULL. Also, sdi->driver and sdi->driver->dev_open must * not be NULL. * * @retval SR_OK Success. * @retval SR_ERR_ARG Invalid argument. * * @since 0.4.0 */ SR_API int sr_session_dev_add(struct sr_session *session, struct sr_dev_inst *sdi) { int ret; if (!sdi) { sr_err("%s: sdi was NULL", __func__); return SR_ERR_ARG; } if (!session) { sr_err("%s: session was NULL", __func__); return SR_ERR_ARG; } /* If sdi->session is not NULL, the device is already in this or * another session. */ if (sdi->session) { sr_err("%s: already assigned to session", __func__); return SR_ERR_ARG; } /* If sdi->driver is NULL, this is a virtual device. */ if (!sdi->driver) { /* Just add the device, don't run dev_open(). */ session->devs = g_slist_append(session->devs, sdi); sdi->session = session; return SR_OK; } /* sdi->driver is non-NULL (i.e. we have a real device). */ if (!sdi->driver->dev_open) { sr_err("%s: sdi->driver->dev_open was NULL", __func__); return SR_ERR_BUG; } session->devs = g_slist_append(session->devs, sdi); sdi->session = session; /* TODO: This is invalid if the session runs in a different thread. * The usage semantics and restrictions need to be documented. */ if (session->running) { /* Adding a device to a running session. Commit settings * and start acquisition on that device now. */ if ((ret = sr_config_commit(sdi)) != SR_OK) { sr_err("Failed to commit device settings before " "starting acquisition in running session (%s)", sr_strerror(ret)); return ret; } if ((ret = sr_dev_acquisition_start(sdi)) != SR_OK) { sr_err("Failed to start acquisition of device in " "running session (%s)", sr_strerror(ret)); return ret; } } return SR_OK; }
static int rpc_handler(sr_session_ctx_t *session) { sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; /* subscribe for handling RPC */ rc = sr_rpc_subscribe_tree(session, "/turing-machine:run-until", rpc_cb, (void *)session, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } printf("\n\n ========== SUBSCRIBED FOR HANDLING RPC ==========\n\n"); /* loop until ctrl-c is pressed / SIGINT is received */ signal(SIGINT, sigint_handler); signal(SIGPIPE, SIG_IGN); while (!exit_application) { sleep(1000); /* or do some more useful work... */ } printf("Application exit requested, exiting.\n"); cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } return rc; }
/** * @brief Callback called by the event loop watcher when health check timer expires. */ static void sr_pd_health_check_timer_cb(struct ev_loop *loop, ev_timer *w, int revents) { sr_pd_ctx_t *ctx = NULL; bool init_retry_needed = false; int rc = SR_ERR_OK; CHECK_NULL_ARG_VOID2(w, w->data); ctx = (sr_pd_ctx_t*)w->data; CHECK_NULL_ARG_VOID(ctx); for (size_t i = 0; i < ctx->plugins_cnt; i++) { if (ctx->plugins[i].initialized && (NULL != ctx->plugins[i].health_check_cb)) { rc = ctx->plugins[i].health_check_cb(ctx->session, ctx->plugins[i].private_ctx); if (SR_ERR_OK != rc) { SR_LOG_ERR("Health check of the plugin '%s' returned an error: %s", ctx->plugins[i].filename, sr_strerror(rc)); sr_pd_cleanup_plugin(ctx, &(ctx->plugins[i])); init_retry_needed = true; } } } if (init_retry_needed) { SR_LOG_DBG("Scheduling plugin init retry after %d seconds.", SR_PLUGIN_INIT_RETRY_TIMEOUT); ev_timer_start(ctx->event_loop, &ctx->init_retry_timer); } }
static int event_notif_subscriber(sr_session_ctx_t *session) { sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; /* subscribe for the notification */ rc = sr_event_notif_subscribe(session, "/turing-machine:paused", event_notif_cb, NULL, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_event_notif_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } printf("\n\n ========== SUBSCRIBED FOR EVENT NOTIFICATION ==========\n\n"); /* loop until ctrl-c is pressed / SIGINT is received */ signal(SIGINT, sigint_handler); signal(SIGPIPE, SIG_IGN); while (!exit_application) { sleep(1000); /* or do some more useful work... */ } printf("Application exit requested, exiting.\n"); cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } return rc; }
/** * @brief Check the session and reconnect if it is needed. */ static void sr_pd_session_check(sr_pd_ctx_t *ctx) { int rc = SR_ERR_OK; CHECK_NULL_ARG_VOID(ctx); rc = sr_session_check(ctx->session); if (SR_ERR_OK != rc) { SR_LOG_DBG_MSG("Reconnecting to Sysrepo Engine."); /* disconnect */ sr_session_stop(ctx->session); sr_disconnect(ctx->connection); ctx->session = NULL; ctx->connection = NULL; /* reconnect */ rc = sr_connect("sysrepo-plugind", connect_options, &ctx->connection); if (SR_ERR_OK == rc) { rc = sr_session_start(ctx->connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &ctx->session); } if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by reconnecting to Sysrepo Engine: %s", sr_strerror(rc)); } } }
/** * Start a session. * * There can only be one session at a time. * * @return SR_OK upon success, SR_ERR upon errors. */ SR_API int sr_session_start(void) { struct sr_dev_inst *sdi; GSList *l; int ret; if (!session) { sr_err("%s: session was NULL; a session must be " "created before starting it.", __func__); return SR_ERR_BUG; } if (!session->devs) { sr_err("%s: session->devs was NULL; a session " "cannot be started without devices.", __func__); return SR_ERR_BUG; } sr_info("Starting..."); ret = SR_OK; for (l = session->devs; l; l = l->next) { sdi = l->data; if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) { sr_err("%s: could not start an acquisition " "(%d)", __func__, sr_strerror(ret)); break; } } /* TODO: What if there are multiple devices? Which return code? */ return ret; }
/** * @brief Convert data tree difference of type LYD_DIFF_DELETED to corresponding set of Sysrepo public API calls. */ static int srcfg_convert_lydiff_deleted(const char *xpath) { CHECK_NULL_ARG(xpath); int rc = sr_delete_item(srcfg_session, xpath, SR_EDIT_STRICT); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_delete_item: %s.", sr_strerror(rc)); } return rc; }
/** * @brief Convert data tree difference of type LYD_DIFF_MOVEDAFTER1 or LYD_DIFF_MOVEDAFTER2 to corresponding * set of Sysrepo public API calls. */ static int srcfg_convert_lydiff_movedafter(const char *target_xpath, const char *after_xpath) { CHECK_NULL_ARG(target_xpath); int rc = sr_move_item(srcfg_session, target_xpath, after_xpath ? SR_MOVE_AFTER : SR_MOVE_FIRST, after_xpath); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_move_item: %s.", sr_strerror(rc)); } return rc; }
static int dev_open(struct sr_dev_inst *sdi) { int ret; struct sr_scpi_dev_inst *scpi = sdi->conn; if ((ret = sr_scpi_open(scpi)) < 0) { sr_err("Failed to open SCPI device: %s.", sr_strerror(ret)); return SR_ERR; } if ((ret = rigol_ds_get_dev_cfg(sdi)) < 0) { sr_err("Failed to get device config: %s.", sr_strerror(ret)); return SR_ERR; } sdi->status = SR_ST_ACTIVE; return SR_OK; }
int main(int argc, char **argv) { sr_conn_ctx_t *connection = NULL; sr_session_ctx_t *session = NULL; int rc = SR_ERR_OK; /* connect to sysrepo */ rc = sr_connect("example_application", 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; } if (1 == argc) { /* run as a RPC handler */ printf("This application will be an RPC handler for 'run-until' operation of 'turing-machine'.\n"); printf("Run the same executable (or rpc_example) with one (any) argument to execute the RPC.\n"); rc = rpc_handler(session); } else { /* run as a RPC caller */ printf("Executing RPC 'run-until' of 'turing-machine':\n"); rc = rpc_caller(session); } cleanup: if (NULL != session) { sr_session_stop(session); } if (NULL != connection) { sr_disconnect(connection); } return rc; }
/** * @brief Reports (prints to stderr) the (sysrepo) error stored within the session or given one. */ static void srcfg_report_error(int rc) { const sr_error_info_t *error = NULL; if (NULL == srcfg_session) { SR_LOG_ERR("%s.", sr_strerror(rc)); } else { sr_get_last_error(srcfg_session, &error); SR_LOG_ERR("%s.", error->message); } }
/** * @brief Convert data tree difference of type LYD_DIFF_CHANGED to corresponding set of Sysrepo public API calls. */ static int srcfg_convert_lydiff_changed(const char *xpath, struct lyd_node *node) { int rc = SR_ERR_INTERNAL; sr_val_t value = { 0, SR_UNKNOWN_T }; struct lyd_node_leaf_list *data_leaf = NULL; CHECK_NULL_ARG2(xpath, node); switch (node->schema->nodetype) { case LYS_LEAF: case LYS_LEAFLIST: data_leaf = (struct lyd_node_leaf_list *) node; value.type = sr_libyang_leaf_get_type(data_leaf); rc = sr_libyang_leaf_copy_value(data_leaf, &value); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc)); goto cleanup; } break; case LYS_ANYXML: SR_LOG_ERR_MSG("The anyxml statement is not yet supported by Sysrepo."); goto cleanup; default: SR_LOG_ERR_MSG("Unexpected node type for LYD_DIFF_CHANGED."); goto cleanup; } rc = sr_set_item(srcfg_session, xpath, &value, SR_EDIT_NON_RECURSIVE); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_set_item: %s.", sr_strerror(rc)); } cleanup: sr_free_val_content(&value); return rc; }
static void get_option(void) { struct sr_dev_inst *sdi; struct sr_channel_group *cg; const struct sr_config_info *ci; GSList *devices; GVariant *gvar; GHashTable *devargs; int ret; char *s; struct sr_dev_driver *driver; if (!(devices = device_scan())) { g_critical("No devices found."); return; } sdi = devices->data; g_slist_free(devices); driver = sr_dev_inst_driver_get(sdi); if (sr_dev_open(sdi) != SR_OK) { g_critical("Failed to open device."); return; } cg = select_channel_group(sdi); if (!(ci = sr_config_info_name_get(opt_get))) g_critical("Unknown option '%s'", opt_get); if ((devargs = parse_generic_arg(opt_config, FALSE))) set_dev_options(sdi, devargs); else devargs = NULL; if ((ret = maybe_config_get(driver, sdi, cg, ci->key, &gvar)) != SR_OK) g_critical("Failed to get '%s': %s", opt_get, sr_strerror(ret)); s = g_variant_print(gvar, FALSE); printf("%s\n", s); g_free(s); g_variant_unref(gvar); sr_dev_close(sdi); if (devargs) g_hash_table_destroy(devargs); }
int cl_request_process(sr_session_ctx_t *session, Sr__Msg *msg_req, Sr__Msg **msg_resp, sr_mem_ctx_t *sr_mem_resp, const Sr__Operation expected_response_op) { int rc = SR_ERR_OK; struct timeval tv = { 0, }; CHECK_NULL_ARG4(session, session->conn_ctx, msg_req, msg_resp); SR_LOG_DBG("Sending %s request.", sr_gpb_operation_name(expected_response_op)); pthread_mutex_lock(&session->conn_ctx->lock); /* some operation may take more time, raise the timeout */ if (SR__OPERATION__COMMIT == expected_response_op || SR__OPERATION__COPY_CONFIG == expected_response_op || SR__OPERATION__RPC == expected_response_op || SR__OPERATION__ACTION == expected_response_op) { tv.tv_sec = SR_LONG_REQUEST_TIMEOUT; tv.tv_usec = 0; rc = setsockopt(session->conn_ctx->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); if (-1 == rc) { SR_LOG_WRN("Unable to set timeout for socket operations: %s", sr_strerror_safe(errno)); } } /* send the request */ rc = cl_message_send(session->conn_ctx, msg_req); if (SR_ERR_OK != rc) { SR_LOG_ERR("Unable to send the message with request (session id=%"PRIu32", operation=%s).", session->id, sr_gpb_operation_name(msg_req->request->operation)); pthread_mutex_unlock(&session->conn_ctx->lock); return rc; } SR_LOG_DBG("%s request sent, waiting for response.", sr_gpb_operation_name(expected_response_op)); /* receive the response */ rc = cl_message_recv(session->conn_ctx, msg_resp, sr_mem_resp); if (SR_ERR_OK != rc) { SR_LOG_ERR("Unable to receive the message with response (session id=%"PRIu32", operation=%s).", session->id, sr_gpb_operation_name(msg_req->request->operation)); pthread_mutex_unlock(&session->conn_ctx->lock); return rc; } /* change socket timeout to the standard value */ if (SR__OPERATION__COMMIT == expected_response_op || SR__OPERATION__COPY_CONFIG == expected_response_op || SR__OPERATION__RPC == expected_response_op || SR__OPERATION__ACTION == expected_response_op) { tv.tv_sec = SR_REQUEST_TIMEOUT; rc = setsockopt(session->conn_ctx->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); if (-1 == rc) { SR_LOG_WRN("Unable to set timeout for socket operations: %s", sr_strerror_safe(errno)); } } pthread_mutex_unlock(&session->conn_ctx->lock); SR_LOG_DBG("%s response received, processing.", sr_gpb_operation_name(expected_response_op)); /* validate the response */ rc = sr_gpb_msg_validate(*msg_resp, SR__MSG__MSG_TYPE__RESPONSE, expected_response_op); if (SR_ERR_OK != rc) { SR_LOG_ERR("Malformed message with response received (session id=%"PRIu32", operation=%s).", session->id, sr_gpb_operation_name(msg_req->request->operation)); return rc; } /* check for errors */ if (SR_ERR_OK != (*msg_resp)->response->result) { if (NULL != (*msg_resp)->response->error) { /* set detailed error information into session */ rc = cl_session_set_error(session, (*msg_resp)->response->error->message, (*msg_resp)->response->error->xpath); } /* log the error (except expected ones) */ if (SR_ERR_NOT_FOUND != (*msg_resp)->response->result && SR_ERR_VALIDATION_FAILED != (*msg_resp)->response->result && SR_ERR_UNAUTHORIZED != (*msg_resp)->response->result && SR_ERR_OPERATION_FAILED != (*msg_resp)->response->result) { SR_LOG_ERR("Error by processing of the %s request (session id=%"PRIu32"): %s.", sr_gpb_operation_name(msg_req->request->operation), session->id, (NULL != (*msg_resp)->response->error && NULL != (*msg_resp)->response->error->message) ? (*msg_resp)->response->error->message : sr_strerror((*msg_resp)->response->result)); } return (*msg_resp)->response->result; } return rc; }
/** * Session start / stop negative test. */ static void cm_session_neg_test(void **state) { Sr__Msg *msg = NULL; uint8_t *msg_buf = NULL; size_t msg_size = 0; int fd1 = 0, fd2 = 0; uint32_t session_id1 = 0, session_id2 = 0; fd1 = cm_connect_to_server(0); /* try invalid version */ cm_version_verify_generate("invalid", &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); msg = cm_message_recv(fd1); assert_non_null(msg); assert_int_equal(msg->type, SR__MSG__MSG_TYPE__RESPONSE); assert_non_null(msg->response); assert_int_equal(msg->response->result, SR_ERR_VERSION_MISMATCH); assert_int_equal(msg->response->operation, SR__OPERATION__VERSION_VERIFY); assert_non_null(msg->response->version_verify_resp); assert_string_equal_bt(msg->response->version_verify_resp->soname, SR_COMPAT_VERSION); sr__msg__free_unpacked(msg, NULL); /* disconnect expected */ msg = cm_message_recv(fd1); assert_null(msg); close(fd1); fd1 = cm_connect_to_server(1); /* try a message with NULL request */ msg = calloc(1, sizeof(*msg)); assert_non_null(msg); sr__msg__init(msg); msg->type = SR__MSG__MSG_TYPE__REQUEST; /* send the message */ cm_msg_pack_to_buff(msg, &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd1); /* disconnect expected */ assert_null(msg); close(fd1); fd1 = cm_connect_to_server(1); /* try a message with bad session id */ cm_session_stop_generate(999, &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd1); /* disconnect expected */ assert_null(msg); close(fd1); fd1 = cm_connect_to_server(1); /* try a session_start request with non-existing username */ cm_session_start_generate("non-existing-username", &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd1); assert_non_null(msg); assert_non_null(msg->response); assert_non_null(msg->response->session_start_resp); /* expect invalid user error */ assert_int_equal(msg->response->result, SR_ERR_INVAL_USER); sr__msg__free_unpacked(msg, NULL); close(fd1); fd1 = cm_connect_to_server(1); fd2 = cm_connect_to_server(1); /* try to stop session via another connection */ /* session_start request */ cm_session_start_generate("nobody", &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd1); assert_non_null(msg); assert_non_null(msg->response); assert_non_null(msg->response->session_start_resp); session_id1 = msg->response->session_start_resp->session_id; sr__msg__free_unpacked(msg, NULL); /* stop via another connection */ cm_session_stop_generate(session_id1, &msg_buf, &msg_size); cm_message_send(fd2, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd2); /* disconnect expected */ assert_null(msg); close(fd2); fd2 = cm_connect_to_server(1); /* try sending a response */ /* session_start request */ cm_session_start_generate("nobody", &msg_buf, &msg_size); cm_message_send(fd2, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd2); assert_non_null(msg); assert_non_null(msg->response); assert_non_null(msg->response->session_start_resp); session_id2 = msg->response->session_start_resp->session_id; sr__msg__free_unpacked(msg, NULL); /* send BAD response */ sr_gpb_resp_alloc(NULL, SR__OPERATION__SESSION_STOP, session_id2, &msg); cm_msg_pack_to_buff(msg, &msg_buf, &msg_size); cm_message_send(fd2, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd2); /* disconnect expected */ assert_null(msg); close(fd2); /* try to stop another session id */ sr_gpb_req_alloc(NULL, SR__OPERATION__SESSION_STOP, session_id1, &msg); assert_non_null(msg); assert_non_null(msg->request); assert_non_null(msg->request->session_stop_req); msg->request->session_stop_req->session_id = 0; /* should be invalid */ cm_msg_pack_to_buff(msg, &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); /* receive the response - error is expected */ msg = cm_message_recv(fd1); assert_non_null(msg); assert_non_null(msg->response); assert_int_not_equal(msg->response->result, SR_ERR_OK); assert_non_null(sr_strerror(msg->response->result)); assert_non_null(msg->response->error); assert_non_null(msg->response->error->message); sr__msg__free_unpacked(msg, NULL); /* try sending a message with invalid type */ sr_gpb_resp_alloc(NULL, SR__OPERATION__SESSION_STOP, session_id1, &msg); msg->type = 53; cm_msg_pack_to_buff(msg, &msg_buf, &msg_size); cm_message_send(fd1, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd1); /* disconnect expected */ assert_null(msg); close(fd1); fd2 = cm_connect_to_server(1); /* try not closing a connection with an open session (auto cleanup) */ /* session_start request */ cm_session_start_generate(NULL, &msg_buf, &msg_size); cm_message_send(fd2, msg_buf, msg_size); free(msg_buf); /* receive the response */ msg = cm_message_recv(fd2); assert_non_null(msg); assert_non_null(msg->response); assert_non_null(msg->response->session_start_resp); session_id2 = msg->response->session_start_resp->session_id; sr__msg__free_unpacked(msg, NULL); cm_teardown(state); close(fd2); }
/** * @brief Main routine of the sysrepo daemon. */ int main(int argc, char* argv[]) { sr_pd_ctx_t ctx = { 0, }; pid_t parent_pid = 0; int pidfile_fd = -1; int c = 0; bool debug_mode = false; int log_level = -1; int rc = SR_ERR_OK; while ((c = getopt (argc, argv, "hvdDl:")) != -1) { switch (c) { case 'v': sr_pd_print_version(); return 0; break; case 'd': debug_mode = true; break; case 'D': connect_options |= SR_CONN_DAEMON_START; break; case 'l': log_level = atoi(optarg); break; default: sr_pd_print_help(); return 0; } } /* init logger */ sr_logger_init("sysrepo-plugind"); /* daemonize the process */ parent_pid = sr_daemonize(debug_mode, log_level, SR_PLUGIN_DAEMON_PID_FILE, &pidfile_fd); SR_LOG_DBG_MSG("Sysrepo plugin daemon initialization started."); /* init the event loop */ ctx.event_loop = ev_loop_new(EVFLAG_AUTO); /* init signal watchers */ ev_signal_init(&ctx.signal_watcher[0], sr_pd_signal_cb, SIGTERM); ev_signal_start(ctx.event_loop, &ctx.signal_watcher[0]); ev_signal_init(&ctx.signal_watcher[1], sr_pd_signal_cb, SIGINT); ev_signal_start(ctx.event_loop, &ctx.signal_watcher[1]); /* init timers */ ev_timer_init(&ctx.health_check_timer, sr_pd_health_check_timer_cb, SR_PLUGIN_HEALTH_CHECK_TIMEOUT, SR_PLUGIN_HEALTH_CHECK_TIMEOUT); ctx.health_check_timer.data = &ctx; ev_timer_init(&ctx.init_retry_timer, sr_pd_init_retry_timer_cb, SR_PLUGIN_INIT_RETRY_TIMEOUT, SR_PLUGIN_INIT_RETRY_TIMEOUT); ctx.init_retry_timer.data = &ctx; /* connect to sysrepo */ rc = sr_connect("sysrepo-plugind", connect_options, &ctx.connection); CHECK_RC_LOG_GOTO(rc, cleanup, "Unable to connect to sysrepod: %s", sr_strerror(rc)); /* start the session */ rc = sr_session_start(ctx.connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &ctx.session); CHECK_RC_LOG_GOTO(rc, cleanup, "Unable to connect to sysrepo: %s", sr_strerror(rc)); /* tell the parent process that we are okay */ if (!debug_mode) { sr_daemonize_signal_success(parent_pid); } /* load the plugins */ rc = sr_pd_load_plugins(&ctx); SR_LOG_INF_MSG("Sysrepo plugin daemon initialized successfully."); /* start health check timer */ ev_timer_start(ctx.event_loop, &ctx.health_check_timer); /* run the event loop */ ev_run(ctx.event_loop, 0); ev_loop_destroy(ctx.event_loop); /* check whether the session is still valid & reconnect if needed */ sr_pd_session_check(&ctx); cleanup: sr_pd_cleanup_plugins(&ctx); if (NULL != ctx.session) { sr_session_stop(ctx.session); } if (NULL != ctx.connection) { sr_disconnect(ctx.connection); } SR_LOG_INF_MSG("Sysrepo plugin daemon terminated."); sr_logger_cleanup(); unlink(SR_PLUGIN_DAEMON_PID_FILE); if (-1 != pidfile_fd) { close(pidfile_fd); } exit((SR_ERR_OK == rc) ? EXIT_SUCCESS : EXIT_FAILURE); }
/** * @brief Import content of the specified datastore for the given module from a file * referenced by the descriptor 'fd_in' */ static int srcfg_import_datastore(struct ly_ctx *ly_ctx, int fd_in, const char *module_name, srcfg_datastore_t datastore, LYD_FORMAT format, bool permanent) { int rc = SR_ERR_INTERNAL; unsigned i = 0; struct lyd_node *new_data_tree = NULL; struct lyd_node *current_data_tree = NULL; struct lyd_difflist *diff = NULL; char *first_xpath = NULL, *second_xpath = NULL; char *input_data = NULL; int ret = 0; struct stat info; CHECK_NULL_ARG2(ly_ctx, module_name); /* parse input data */ ret = fstat(fd_in, &info); CHECK_NOT_MINUS1_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Unable to obtain input file info: %s.", sr_strerror_safe(errno)); ly_errno = LY_SUCCESS; if (S_ISREG(info.st_mode)) { /* load (using mmap) and parse the input data in one step */ new_data_tree = lyd_parse_fd(ly_ctx, fd_in, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } else { /* most likely STDIN */ /* load input data into the memory first */ ret = srcfg_read_file_content(fd_in, &input_data); CHECK_RC_MSG_GOTO(ret, cleanup, "Unable to read the input data."); /* parse the input data stored inside memory buffer */ new_data_tree = lyd_parse_mem(ly_ctx, input_data, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } if (NULL == new_data_tree && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Unable to parse the input data: %s", ly_errmsg()); goto cleanup; } /* validate input data */ if (NULL != new_data_tree) { ret = lyd_validate(&new_data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Input data are not valid: %s", ly_errmsg()); } /* remove default nodes */ lyd_wd_cleanup(&new_data_tree, 0); /* get data tree of currently stored configuration */ rc = srcfg_get_module_data(ly_ctx, module_name, ¤t_data_tree); if (SR_ERR_OK != rc) { goto cleanup; } /* get the list of changes made by the user */ diff = lyd_diff(current_data_tree, new_data_tree, 0); if (NULL == diff) { SR_LOG_ERR("Unable to get the list of changes: %s", ly_errmsg()); goto cleanup; } /* iterate over the list of differences and for each issue corresponding Sysrepo command(s) */ while (diff->type && LYD_DIFF_END != diff->type[i]) { if (NULL != diff->first[i]) { first_xpath = lyd_path(diff->first[i]); if (NULL == first_xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } if (NULL != diff->second[i]) { second_xpath = lyd_path(diff->second[i]); if (NULL == second_xpath) { free(first_xpath); first_xpath = NULL; SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } switch (diff->type[i]) { case LYD_DIFF_DELETED: SR_LOG_DBG("<LYD_DIFF_DELETED> node: %s", first_xpath); rc = srcfg_convert_lydiff_deleted(first_xpath); break; case LYD_DIFF_CHANGED: SR_LOG_DBG("<LYD_DIFF_CHANGED> orig: %s, new: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_changed(first_xpath, diff->second[i]); break; case LYD_DIFF_MOVEDAFTER1: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER1> moved: %s, after: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(first_xpath, second_xpath); break; case LYD_DIFF_CREATED: SR_LOG_DBG("<LYD_DIFF_CREATED> parent: %s, new node: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_created(diff->second[i]); break; case LYD_DIFF_MOVEDAFTER2: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER2> after: %s, this new node was inserted: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(second_xpath, first_xpath); break; default: assert(0 && "not reachable"); } free(first_xpath); free(second_xpath); first_xpath = second_xpath = NULL; if (SR_ERR_OK != rc) { goto cleanup; } ++i; } if (0 == i) { SR_LOG_DBG_MSG("No changes were made."); } else { /* commit the changes */ rc = sr_commit(srcfg_session); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_commit: %s.", sr_strerror(rc)); goto cleanup; } if (SRCFG_STORE_RUNNING == datastore && permanent) { /* copy running datastore data into the startup datastore */ rc = sr_copy_config(srcfg_session, module_name, SR_DS_RUNNING, SR_DS_STARTUP); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_copy_config: %s.", sr_strerror(rc)); goto cleanup; } } } rc = SR_ERR_OK; cleanup: if (NULL != diff) { lyd_free_diff(diff); } if (NULL != current_data_tree) { lyd_free_withsiblings(current_data_tree); } if (NULL != new_data_tree) { lyd_free_withsiblings(new_data_tree); } if (input_data) { free(input_data); } return rc; }
/** * @brief Initializes a plugin. */ static int sr_pd_init_plugin(sr_session_ctx_t *session, sr_pd_plugin_ctx_t *plugin_ctx) { int rc = SR_ERR_OK; CHECK_NULL_ARG2(session, plugin_ctx); /* call init callback */ rc = plugin_ctx->init_cb(session, &plugin_ctx->private_ctx); if (SR_ERR_OK != rc) { SR_LOG_ERR("'%s' in '%s' returned an error: %s.", SR_PLUGIN_INIT_FN_NAME, plugin_ctx->filename, sr_strerror(rc)); plugin_ctx->initialized = false; } else { plugin_ctx->initialized = true; } return rc; }
int cl_request_process(sr_session_ctx_t *session, Sr__Msg *msg_req, Sr__Msg **msg_resp, sr_mem_ctx_t *sr_mem_resp, const Sr__Operation expected_response_op) { int rc = SR_ERR_OK; CHECK_NULL_ARG4(session, session->conn_ctx, msg_req, msg_resp); SR_LOG_DBG("Sending %s request.", sr_gpb_operation_name(expected_response_op)); pthread_mutex_lock(&session->conn_ctx->lock); /* send the request */ rc = cl_message_send(session->conn_ctx, msg_req); if (SR_ERR_OK != rc) { SR_LOG_ERR("Unable to send the message with request (session id=%"PRIu32", operation=%s).", session->id, sr_gpb_operation_name(msg_req->request->operation)); pthread_mutex_unlock(&session->conn_ctx->lock); return rc; } SR_LOG_DBG("%s request sent, waiting for response.", sr_gpb_operation_name(expected_response_op)); /* receive the response */ rc = cl_message_recv(session->conn_ctx, msg_resp, sr_mem_resp); if (SR_ERR_OK != rc) { SR_LOG_ERR("Unable to receive the message with response (session id=%"PRIu32", operation=%s).", session->id, sr_gpb_operation_name(msg_req->request->operation)); pthread_mutex_unlock(&session->conn_ctx->lock); return rc; } pthread_mutex_unlock(&session->conn_ctx->lock); SR_LOG_DBG("%s response received, processing.", sr_gpb_operation_name(expected_response_op)); /* validate the response */ rc = sr_gpb_msg_validate(*msg_resp, SR__MSG__MSG_TYPE__RESPONSE, expected_response_op); if (SR_ERR_OK != rc) { SR_LOG_ERR("Malformed message with response received (session id=%"PRIu32", operation=%s).", session->id, sr_gpb_operation_name(msg_req->request->operation)); return rc; } /* check for errors */ if (SR_ERR_OK != (*msg_resp)->response->result) { if (NULL != (*msg_resp)->response->error) { /* set detailed error information into session */ rc = cl_session_set_error(session, (*msg_resp)->response->error->message, (*msg_resp)->response->error->xpath); } /* log the error (except expected ones) */ if (SR_ERR_NOT_FOUND != (*msg_resp)->response->result && SR_ERR_VALIDATION_FAILED != (*msg_resp)->response->result && SR_ERR_UNAUTHORIZED != (*msg_resp)->response->result && SR_ERR_OPERATION_FAILED != (*msg_resp)->response->result) { SR_LOG_ERR("Error by processing of the %s request (session id=%"PRIu32"): %s.", sr_gpb_operation_name(msg_req->request->operation), session->id, (NULL != (*msg_resp)->response->error && NULL != (*msg_resp)->response->error->message) ? (*msg_resp)->response->error->message : sr_strerror((*msg_resp)->response->result)); } return (*msg_resp)->response->result; } return rc; }
/** * @brief Get complete libyang data tree of a specified module from sysrepo. */ static int srcfg_get_module_data(struct ly_ctx *ly_ctx, const char *module_name, struct lyd_node **data_tree) { int rc = SR_ERR_OK, ret = 0; sr_val_t *value = NULL; sr_val_iter_t *iter = NULL; struct lyd_node *node = NULL; const struct lys_node *schema = NULL; char query[PATH_MAX] = { 0, }; char *string_val = NULL; snprintf(query, PATH_MAX, "/%s:*//.", module_name); rc = sr_get_items_iter(srcfg_session, query, &iter); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by sr_get_items_iter: %s", sr_strerror(rc)); goto cleanup; } *data_tree = NULL; ly_errno = LY_SUCCESS; ly_diminish_errors = true; while (SR_ERR_OK == (rc = sr_get_item_next(srcfg_session, iter, &value))) { ly_diminish_errors = false; if (NULL == value) { goto next; } /* get node schema */ schema = ly_ctx_get_node2(ly_ctx, NULL, value->xpath, 0); if (!schema) { SR_LOG_ERR("Error by ly_ctx_get_node2: %s", ly_errmsg()); goto fail; } /* skip default values */ if (schema->nodetype == LYS_LEAF && value->dflt) { goto next; } /* skip non-presence containers */ if (value->type == SR_CONTAINER_T) { goto next; } /* convert value to string */ rc = sr_val_to_str(value, schema, &string_val); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by sr_val_to_str: %s", sr_strerror(rc)); goto fail; } /* add node to data tree */ ly_errno = LY_SUCCESS; node = lyd_new_path(*data_tree, ly_ctx, value->xpath, string_val, LYD_PATH_OPT_UPDATE); if (!node && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Error by lyd_new_path: %s", ly_errmsg()); goto fail; } if (NULL == *data_tree) { *data_tree = node; } next: /* cleanup before next iteration */ if (NULL != string_val) { free(string_val); string_val = NULL; } if (NULL != value) { sr_free_val(value); value = NULL; } ly_diminish_errors = true; } ly_diminish_errors = false; if (SR_ERR_NOT_FOUND == rc) { rc = SR_ERR_OK; } if (SR_ERR_OK == rc) { if (NULL != *data_tree) { /* validate returned data, but most importantly resolve leafrefs */ ret = lyd_validate(data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, fail, "Received data tree from sysrepo is not valid: %s", ly_errmsg()); /* remove default nodes added by validation */ lyd_wd_cleanup(data_tree, 0); } goto cleanup; } fail: rc = SR_ERR_INTERNAL; if (NULL != *data_tree) { lyd_free_withsiblings(*data_tree); *data_tree = NULL; } cleanup: if (NULL != string_val) { free(string_val); } if (NULL != value) { sr_free_val(value); } if (NULL != iter) { sr_free_val_iter(iter); } return rc; }
/** * @brief Convert data tree difference of type LYD_DIFF_CREATED to corresponding set of Sysrepo public API calls. */ static int srcfg_convert_lydiff_created(struct lyd_node *node) { int rc = SR_ERR_INTERNAL; struct lyd_node *elem = node; bool process_children = true; sr_val_t value = { 0, SR_UNKNOWN_T }; struct lyd_node_leaf_list *data_leaf = NULL; struct lys_node_list *slist = NULL; char *xpath = NULL, *delim = NULL; CHECK_NULL_ARG(node); /* non-recursive DFS post-order */ do { /* go as deep as possible */ if (process_children) { while (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) && elem->child) { elem = elem->child; } } /* get appropriate xpath and value */ free(xpath); xpath = value.xpath = NULL; value.type = SR_UNKNOWN_T; switch (elem->schema->nodetype) { case LYS_LEAF: /* e.g.: /test-module:user[name='nameE']/name */ /* get value */ data_leaf = (struct lyd_node_leaf_list *)elem; value.type = sr_libyang_leaf_get_type(data_leaf); rc = sr_libyang_leaf_copy_value(data_leaf, &value); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc)); goto cleanup; } /* get xpath */ xpath = lyd_path(elem); if (NULL == xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } /* key value of a list cannot be set directly */ if (elem->parent && (elem->parent->schema->nodetype == LYS_LIST)) { slist = (struct lys_node_list *)elem->parent->schema; for (unsigned i = 0; i < slist->keys_size; ++i) { if (slist->keys[i]->name == elem->schema->name) { /* key */ if (i == 0) { delim = strrchr(xpath, '/'); if (delim) { *delim = '\0'; } goto set_value; } else { /* create list instance (directly) only once - with the first key */ goto next_node; } } } } break; case LYS_LEAFLIST: /* e.g.: /test-module:main/numbers[.='10'] */ /* get value */ data_leaf = (struct lyd_node_leaf_list *)elem; value.type = sr_libyang_leaf_get_type(data_leaf); rc = sr_libyang_leaf_copy_value(data_leaf, &value); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc)); goto cleanup; } /* get xpath */ xpath = lyd_path(elem); if (NULL == xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } /* strip away the predicate */ delim = strrchr(xpath, '['); if (delim) { *delim = '\0'; } break; case LYS_ANYXML: SR_LOG_ERR_MSG("The anyxml statement is not yet supported by Sysrepo."); goto cleanup; case LYS_CONTAINER: /* explicitly create only presence containers */ if (((struct lys_node_container *)elem->schema)->presence) { xpath = lyd_path(elem); } else { goto next_node; } break; default: /* no data to set */ goto next_node; } set_value: /* set value */ rc = sr_set_item(srcfg_session, xpath, SR_UNKNOWN_T != value.type ? &value : NULL, SR_EDIT_DEFAULT); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_set_item: %s.", sr_strerror(rc)); goto cleanup; } next_node: /* backtracking + automatically moving to the next sibling if there is any */ if (elem != node) { if (elem->next) { elem = elem->next; process_children = true; } else { assert(elem->parent); elem = elem->parent; process_children = false; } } else { break; } } while (true); rc = SR_ERR_OK; cleanup: if (NULL != xpath) { free(xpath); } sr_free_val_content(&value); return rc; }
/** * Start a session. * * @param session The session to use. Must not be NULL. * * @retval SR_OK Success. * @retval SR_ERR_ARG Invalid session passed. * * @since 0.4.0 */ SR_API int sr_session_start(struct sr_session *session) { struct sr_dev_inst *sdi; struct sr_channel *ch; GSList *l, *c; int enabled_channels, ret; if (!session) { sr_err("%s: session was NULL", __func__); return SR_ERR_ARG; } if (!session->devs) { sr_err("%s: session->devs was NULL; a session " "cannot be started without devices.", __func__); return SR_ERR_ARG; } if (session->trigger && verify_trigger(session->trigger) != SR_OK) return SR_ERR; ret = set_main_context(session); if (ret != SR_OK) return ret; session->running = TRUE; sr_info("Starting."); for (l = session->devs; l; l = l->next) { sdi = l->data; enabled_channels = 0; for (c = sdi->channels; c; c = c->next) { ch = c->data; if (ch->enabled) { enabled_channels++; break; } } if (enabled_channels == 0) { ret = SR_ERR; sr_err("%s using connection %s has no enabled channels!", sdi->driver->name, sdi->connection_id); break; } if ((ret = sr_config_commit(sdi)) != SR_OK) { sr_err("Failed to commit device settings before " "starting acquisition (%s)", sr_strerror(ret)); break; } if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) { sr_err("%s: could not start an acquisition " "(%s)", __func__, sr_strerror(ret)); break; } } if (ret != SR_OK) { unset_main_context(session); session->running = FALSE; } /* TODO: What if there are multiple devices? Which return code? */ return ret; }