/** * @brief Loads a plugin form provided filename. */ static int sr_pd_load_plugin(sr_session_ctx_t *session, const char *plugin_filename, sr_pd_plugin_ctx_t *plugin_ctx) { int rc = SR_ERR_OK; CHECK_NULL_ARG3(session, plugin_filename, plugin_ctx); plugin_ctx->filename = strdup(plugin_filename); CHECK_NULL_NOMEM_GOTO(plugin_ctx->filename, rc, cleanup); /* open the dynamic library with plugin */ plugin_ctx->dl_handle = dlopen(plugin_filename, RTLD_LAZY); if (NULL == plugin_ctx->dl_handle) { SR_LOG_WRN("Unable to load the plugin: %s.", dlerror()); rc = SR_ERR_INIT_FAILED; goto cleanup; } /* get init function pointer */ *(void **) (&plugin_ctx->init_cb) = dlsym(plugin_ctx->dl_handle, SR_PLUGIN_INIT_FN_NAME); if (NULL == plugin_ctx->init_cb) { SR_LOG_WRN("Unable to find '%s' function: %s.", SR_PLUGIN_INIT_FN_NAME, dlerror()); rc = SR_ERR_INIT_FAILED; goto cleanup; } /* get cleanup function pointer */ *(void **) (&plugin_ctx->cleanup_cb) = dlsym(plugin_ctx->dl_handle, SR_PLUGIN_CLEANUP_FN_NAME); if (NULL == plugin_ctx->cleanup_cb) { SR_LOG_WRN("Unable to find '%s' function: %s.", SR_PLUGIN_CLEANUP_FN_NAME, dlerror()); rc = SR_ERR_INIT_FAILED; goto cleanup; } /* get health check function pointer */ *(void **) (&plugin_ctx->health_check_cb) = dlsym(plugin_ctx->dl_handle, SR_PLUGIN_HEALTH_CHECK_FN_NAME); if (NULL != plugin_ctx->health_check_cb) { SR_LOG_DBG("'%s' function found, health checks will be applied.", SR_PLUGIN_HEALTH_CHECK_FN_NAME); } return SR_ERR_OK; cleanup: if (NULL != plugin_ctx->dl_handle) { dlclose(plugin_ctx->dl_handle); } free(plugin_ctx->filename); return rc; }
/** * @brief Removes a session from the session list of the connection. */ static void cl_conn_remove_session(sr_conn_ctx_t *connection, sr_session_ctx_t *session) { sr_session_list_t *tmp = NULL, *prev = NULL; CHECK_NULL_ARG_VOID2(connection, session); pthread_mutex_lock(&connection->lock); /* find matching session in linked list */ tmp = connection->session_list; while ((NULL != tmp) && (tmp->session != session)) { prev = tmp; tmp = tmp->next; } /* remove the session from linked-list */ if (NULL != tmp) { if (NULL != prev) { /* tmp is NOT the first item in list - skip it */ prev->next = tmp->next; } else if (NULL != tmp->next) { /* tmp is the first, but not last item in list - skip it */ connection->session_list = tmp->next; } else { /* tmp is the only item in the list */ connection->session_list = NULL; } free(tmp); } else { SR_LOG_WRN("Session %p not found in session list of connection.", (void*)session); } pthread_mutex_unlock(&connection->lock); }
/** * @brief Logging callback called from libyang for each log entry. */ static void srcfg_ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) { switch (level) { case LY_LLERR: if (ly_diminish_errors) SR_LOG_WRN("libyang: %s", msg); else SR_LOG_ERR("libyang: %s", msg); break; case LY_LLWRN: SR_LOG_WRN("libyang: %s", msg); break; case LY_LLVRB: SR_LOG_INF("libyang: %s", msg); break; case LY_LLDBG: SR_LOG_DBG("libyang: %s", msg); break; default: break; } }
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; }
/** * @brief Loads all plugins in plugins directory. */ static int sr_pd_load_plugins(sr_pd_ctx_t *ctx) { DIR *dir; struct dirent entry, *result; char *env_str = NULL; char plugins_dir[PATH_MAX - 256] = { 0, }; char plugin_filename[PATH_MAX + 1] = { 0, }; sr_pd_plugin_ctx_t *tmp = NULL; bool init_retry_needed = false; int ret = 0; int rc = SR_ERR_OK; CHECK_NULL_ARG(ctx); /* get plugins dir from environment variable, or use default one */ env_str = getenv("SR_PLUGINS_DIR"); if (NULL != env_str) { strncat(plugins_dir, env_str, PATH_MAX - 257); } else { strncat(plugins_dir, SR_PLUGINS_DIR, PATH_MAX - 257); } SR_LOG_DBG("Loading plugins from '%s'.", plugins_dir); dir = opendir(plugins_dir); if (NULL == dir) { SR_LOG_ERR("Error by opening plugin directory: %s.", sr_strerror_safe(errno)); return SR_ERR_INVAL_ARG; } do { ret = readdir_r(dir, &entry, &result); if (0 != ret) { SR_LOG_ERR("Error by reading plugin directory: %s.", sr_strerror_safe(errno)); break; } if ((NULL != result) && (DT_DIR != entry.d_type) && (0 != strcmp(entry.d_name, ".")) && (0 != strcmp(entry.d_name, ".."))) { SR_LOG_DBG("Loading plugin from file '%s'.", entry.d_name); snprintf(plugin_filename, PATH_MAX, "%s/%s", plugins_dir, entry.d_name); /* realloc plugins array */ tmp = realloc(ctx->plugins, sizeof(*ctx->plugins) * (ctx->plugins_cnt + 1)); if (NULL == tmp) { SR_LOG_ERR_MSG("Unable to realloc plugins array, skipping the rest of plugins."); break; } ctx->plugins = tmp; /* load the plugin */ rc = sr_pd_load_plugin(ctx->session, plugin_filename, &(ctx->plugins[ctx->plugins_cnt])); if (SR_ERR_OK != rc) { SR_LOG_WRN("Ignoring the file '%s'.", plugin_filename); continue; } /* initialize the plugin */ rc = sr_pd_init_plugin(ctx->session, &(ctx->plugins[ctx->plugins_cnt])); if (SR_ERR_OK != rc) { init_retry_needed = true; } ctx->plugins_cnt += 1; } } while (NULL != result); closedir(dir); 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); } return SR_ERR_OK; }