CHANGE major update
All commands are bulk (for more sessions),
new merge and query commands, get and
get-config return merged sJSON configs,
formatting.
TODO metadata generation is not complete.
diff --git a/src/mod_netconf.c b/src/mod_netconf.c
index da63bd0..0cbb875 100644
--- a/src/mod_netconf.c
+++ b/src/mod_netconf.c
@@ -52,8 +52,10 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/fcntl.h>
+#include <sys/stat.h>
#include <pwd.h>
#include <errno.h>
+#include <limits.h>
#include <grp.h>
#include <signal.h>
#include <pthread.h>
@@ -71,12 +73,13 @@
#include "message_type.h"
#include "mod_netconf.h"
+#define SCHEMA_DIR "/tmp/yang_models"
#define MAX_PROCS 5
#define SOCKET_FILENAME "/var/run/mod_netconf.sock"
#define MAX_SOCKET_CL 10
#define BUFFER_SIZE 4096
-#define ACTIVITY_CHECK_INTERVAL 10 /**< timeout in seconds, how often activity is checked */
-#define ACTIVITY_TIMEOUT (60*60) /**< timeout in seconds, after this time, session is automaticaly closed. */
+#define ACTIVITY_CHECK_INTERVAL 10 /**< timeout in seconds, how often activity is checked */
+#define ACTIVITY_TIMEOUT (60*60) /**< timeout in seconds, after this time, session is automaticaly closed. */
/* sleep in master process for non-blocking socket reading, in msec */
#define SLEEP_TIME 200
@@ -88,8 +91,7 @@
/* timeout in msec */
struct timeval timeout = { 1, 0 };
-#define NCWITHDEFAULTS NCWD_MODE_NOTSET
-
+#define NCWITHDEFAULTS NCWD_MODE_NOTSET
#define MSG_OK 0
#define MSG_OPEN 1
@@ -103,209 +105,269 @@
pthread_mutex_t ntf_hist_clbc_mutex; /**< mutex protecting notification history list */
pthread_mutex_t json_lock; /**< mutex for protecting json-c calls */
+unsigned int session_key_generator = 1;
struct session_with_mutex *netconf_sessions_list = NULL;
-
static const char *sockname;
-
static pthread_key_t notif_history_key;
-
pthread_key_t err_reply_key;
-
volatile int isterminated = 0;
-
static char* password;
-static void signal_handler(int sign)
+json_object *create_ok_reply(void);
+json_object *create_data_reply(const char *data);
+static char *netconf_getschema(unsigned int session_key, const char *identifier, const char *version,
+ const char *format, json_object **err);
+static void node_add_metadata_recursive(struct lyd_node *data_tree, struct lys_module *module,
+ json_object *data_json_parent);
+
+static void
+signal_handler(int sign)
{
- switch (sign) {
- case SIGINT:
- case SIGTERM:
- isterminated = 1;
- break;
- }
+ switch (sign) {
+ case SIGINT:
+ case SIGTERM:
+ isterminated = 1;
+ break;
+ }
}
-int netconf_callback_ssh_hostkey_check(const char* UNUSED(hostname), ssh_session UNUSED(session))
+int
+netconf_callback_ssh_hostkey_check(const char* UNUSED(hostname), ssh_session UNUSED(session))
{
- /* always approve */
- return (EXIT_SUCCESS);
+ /* always approve */
+ return (EXIT_SUCCESS);
}
-char *netconf_callback_sshauth_passphrase(const char *UNUSED(username), const char *UNUSED(hostname), const char *UNUSED(priv_key_file))
+char *
+netconf_callback_sshauth_passphrase(const char *UNUSED(username), const char *UNUSED(hostname), const char *UNUSED(priv_key_file))
{
- char *buf;
- buf = strdup(password);
- return (buf);
+ char *buf;
+ buf = strdup(password);
+ return (buf);
}
-char *netconf_callback_sshauth_password(const char* UNUSED(username), const char* UNUSED(hostname))
+char *
+netconf_callback_sshauth_password(const char *UNUSED(username), const char *UNUSED(hostname))
{
- char *buf;
- buf = strdup(password);
- return (buf);
+ char *buf;
+ buf = strdup(password);
+ return (buf);
}
-char *netconf_callback_sshauth_interactive(const char *UNUSED(name), const char *UNUSED(instruction),
- const char *UNUSED(prompt), int UNUSED(echo))
+char *
+netconf_callback_sshauth_interactive(const char *UNUSED(name), const char *UNUSED(instruction),
+ const char *UNUSED(prompt), int UNUSED(echo))
{
- char *buf;
- buf = strdup(password);
- return (buf);
+ char *buf;
+ buf = strdup(password);
+ return (buf);
}
-void netconf_callback_error_process(const char *UNUSED(tag),
- const char *UNUSED(type),
- const char *UNUSED(severity),
- const char *UNUSED(apptag),
- const char *UNUSED(path),
- const char *message,
- const char *UNUSED(attribute),
- const char *UNUSED(element),
- const char *UNUSED(ns),
- const char *UNUSED(sid))
+void
+netconf_callback_error_process(const char *UNUSED(tag),
+ const char *UNUSED(type),
+ const char *UNUSED(severity),
+ const char *UNUSED(apptag),
+ const char *UNUSED(path),
+ const char *message,
+ const char *UNUSED(attribute),
+ const char *UNUSED(element),
+ const char *UNUSED(ns),
+ const char *UNUSED(sid))
{
- json_object **err_reply_p = (json_object **) pthread_getspecific(err_reply_key);
- if (err_reply_p == NULL) {
- ERROR("Error message was not allocated. %s", __func__);
- return;
- }
- json_object *err_reply = *err_reply_p;
+ json_object **err_reply_p = (json_object **) pthread_getspecific(err_reply_key);
+ if (err_reply_p == NULL) {
+ ERROR("Error message was not allocated. %s", __func__);
+ return;
+ }
+ json_object *err_reply = *err_reply_p;
- json_object *array = NULL;
- if (err_reply == NULL) {
- ERROR("error calback: empty error list");
- pthread_mutex_lock(&json_lock);
- err_reply = json_object_new_object();
- array = json_object_new_array();
- json_object_object_add(err_reply, "type", json_object_new_int(REPLY_ERROR));
- json_object_object_add(err_reply, "errors", array);
- if (message != NULL) {
- json_object_array_add(array, json_object_new_string(message));
- }
- pthread_mutex_unlock(&json_lock);
- (*err_reply_p) = err_reply;
- } else {
- ERROR("error calback: nonempty error list");
- pthread_mutex_lock(&json_lock);
- if (json_object_object_get_ex(err_reply, "errors", &array) == TRUE) {
- if (message != NULL) {
- json_object_array_add(array, json_object_new_string(message));
- }
- }
- pthread_mutex_unlock(&json_lock);
- }
- pthread_setspecific(err_reply_key, err_reply_p);
- return;
+ json_object *array = NULL;
+ if (err_reply == NULL) {
+ ERROR("error calback: empty error list");
+ pthread_mutex_lock(&json_lock);
+ err_reply = json_object_new_object();
+ array = json_object_new_array();
+ json_object_object_add(err_reply, "type", json_object_new_int(REPLY_ERROR));
+ json_object_object_add(err_reply, "errors", array);
+ if (message != NULL) {
+ json_object_array_add(array, json_object_new_string(message));
+ }
+ pthread_mutex_unlock(&json_lock);
+ (*err_reply_p) = err_reply;
+ } else {
+ ERROR("error calback: nonempty error list");
+ pthread_mutex_lock(&json_lock);
+ if (json_object_object_get_ex(err_reply, "errors", &array) == TRUE) {
+ if (message != NULL) {
+ json_object_array_add(array, json_object_new_string(message));
+ }
+ }
+ pthread_mutex_unlock(&json_lock);
+ }
+ pthread_setspecific(err_reply_key, err_reply_p);
+ return;
}
/**
* should be used in locked area
*/
-void prepare_status_message(struct session_with_mutex *s, struct nc_session *session)
+void
+prepare_status_message(struct session_with_mutex *s, struct nc_session *session)
{
- json_object *json_obj = NULL;
- json_object *js_tmp = NULL;
- char *old_sid = NULL;
- const char *j_old_sid = NULL;
- const char *cpbltstr;
- struct nc_cpblts* cpblts = NULL;
+ json_object *json_obj = NULL;
+ json_object *js_tmp = NULL;
+ char *old_sid = NULL;
+ const char *j_old_sid = NULL;
+ const char *cpbltstr;
+ struct nc_cpblts* cpblts = NULL;
- if (s == NULL) {
- ERROR("No session given.");
- return;
- }
+ if (s == NULL) {
+ ERROR("No session given.");
+ return;
+ }
- pthread_mutex_lock(&json_lock);
- if (s->hello_message != NULL) {
- ERROR("clean previous hello message");
- //json_object_put(s->hello_message);
- if (json_object_object_get_ex(s->hello_message, "sid", &js_tmp) == TRUE) {
- j_old_sid = json_object_get_string(js_tmp);
- if (j_old_sid != NULL) {
- old_sid = strdup(j_old_sid);
- }
- json_object_put(s->hello_message);
- json_object_put(js_tmp);
- }
- s->hello_message = NULL;
- }
- s->hello_message = json_object_get(json_object_new_object());
- if (session != NULL) {
- if (old_sid != NULL) {
- /* use previous sid */
- json_object_object_add(s->hello_message, "sid", json_object_new_string(old_sid));
- free(old_sid);
- old_sid = NULL;
- } else {
- /* we don't have old sid */
- json_object_object_add(s->hello_message, "sid", json_object_new_string(nc_session_get_id(session)));
- }
- json_object_object_add(s->hello_message, "version", json_object_new_string((nc_session_get_version(session) == 0)?"1.0":"1.1"));
- json_object_object_add(s->hello_message, "host", json_object_new_string(nc_session_get_host(session)));
- json_object_object_add(s->hello_message, "port", json_object_new_string(nc_session_get_port(session)));
- json_object_object_add(s->hello_message, "user", json_object_new_string(nc_session_get_user(session)));
- cpblts = nc_session_get_cpblts (session);
- if (cpblts != NULL) {
- json_obj = json_object_new_array();
- nc_cpblts_iter_start (cpblts);
- while ((cpbltstr = nc_cpblts_iter_next (cpblts)) != NULL) {
- json_object_array_add(json_obj, json_object_new_string(cpbltstr));
- }
- json_object_object_add(s->hello_message, "capabilities", json_obj);
- }
- DEBUG("%s", json_object_to_json_string(s->hello_message));
- } else {
- ERROR("Session was not given.");
- json_object_object_add(s->hello_message, "type", json_object_new_int(REPLY_ERROR));
- json_object_object_add(s->hello_message, "error-message", json_object_new_string("Invalid session identifier."));
- }
- DEBUG("Status info from hello message prepared");
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_lock(&json_lock);
+ if (s->hello_message != NULL) {
+ ERROR("clean previous hello message");
+ if (json_object_object_get_ex(s->hello_message, "sid", &js_tmp) == TRUE) {
+ j_old_sid = json_object_get_string(js_tmp);
+ if (j_old_sid != NULL) {
+ old_sid = strdup(j_old_sid);
+ }
+ }
+ json_object_put(s->hello_message);
+ s->hello_message = NULL;
+ }
+ s->hello_message = json_object_new_object();
+ if (session != NULL) {
+ if (old_sid != NULL) {
+ /* use previous sid */
+ json_object_object_add(s->hello_message, "sid", json_object_new_string(old_sid));
+ free(old_sid);
+ old_sid = NULL;
+ } else {
+ /* we don't have old sid */
+ json_object_object_add(s->hello_message, "sid", json_object_new_string(nc_session_get_id(session)));
+ }
+ json_object_object_add(s->hello_message, "version", json_object_new_string((nc_session_get_version(session) == 0)?"1.0":"1.1"));
+ json_object_object_add(s->hello_message, "host", json_object_new_string(nc_session_get_host(session)));
+ json_object_object_add(s->hello_message, "port", json_object_new_string(nc_session_get_port(session)));
+ json_object_object_add(s->hello_message, "user", json_object_new_string(nc_session_get_user(session)));
+ cpblts = nc_session_get_cpblts (session);
+ if (cpblts != NULL) {
+ json_obj = json_object_new_array();
+ nc_cpblts_iter_start (cpblts);
+ while ((cpbltstr = nc_cpblts_iter_next (cpblts)) != NULL) {
+ json_object_array_add(json_obj, json_object_new_string(cpbltstr));
+ }
+ json_object_object_add(s->hello_message, "capabilities", json_obj);
+ }
+ DEBUG("%s", json_object_to_json_string(s->hello_message));
+ } else {
+ ERROR("Session was not given.");
+ json_object_object_add(s->hello_message, "type", json_object_new_int(REPLY_ERROR));
+ json_object_object_add(s->hello_message, "error-message", json_object_new_string("Invalid session identifier."));
+ }
+ DEBUG("Status info from hello message prepared");
+ pthread_mutex_unlock(&json_lock);
}
-void create_err_reply_p()
+void
+create_err_reply_p()
{
- json_object **err_reply = calloc(1, sizeof(json_object **));
- if (err_reply == NULL) {
- ERROR("Allocation of err_reply storage failed!");
- return;
- }
- if (pthread_setspecific(err_reply_key, err_reply) != 0) {
- ERROR("cannot set thread-specific value.");
- }
+ json_object **err_reply = calloc(1, sizeof(json_object **));
+ if (err_reply == NULL) {
+ ERROR("Allocation of err_reply storage failed!");
+ return;
+ }
+ if (pthread_setspecific(err_reply_key, err_reply) != 0) {
+ ERROR("cannot set thread-specific value.");
+ }
}
-void clean_err_reply()
+void
+clean_err_reply()
{
- json_object **err_reply = (json_object **) pthread_getspecific(err_reply_key);
- if (err_reply != NULL) {
- if (*err_reply != NULL) {
- pthread_mutex_lock(&json_lock);
- json_object_put(*err_reply);
- pthread_mutex_unlock(&json_lock);
- }
- if (pthread_setspecific(err_reply_key, err_reply) != 0) {
- ERROR("Cannot set thread-specific hash value.");
- }
- }
+ json_object **err_reply = (json_object **) pthread_getspecific(err_reply_key);
+ if (err_reply != NULL) {
+ if (*err_reply != NULL) {
+ pthread_mutex_lock(&json_lock);
+ json_object_put(*err_reply);
+ pthread_mutex_unlock(&json_lock);
+ }
+ if (pthread_setspecific(err_reply_key, err_reply) != 0) {
+ ERROR("Cannot set thread-specific hash value.");
+ }
+ }
}
-void free_err_reply()
+void
+free_err_reply()
{
- json_object **err_reply = (json_object **) pthread_getspecific(err_reply_key);
- if (err_reply != NULL) {
- if (*err_reply != NULL) {
- pthread_mutex_lock(&json_lock);
- json_object_put(*err_reply);
- pthread_mutex_unlock(&json_lock);
- }
- free(err_reply);
- err_reply = NULL;
- if (pthread_setspecific(err_reply_key, err_reply) != 0) {
- ERROR("Cannot set thread-specific hash value.");
- }
- }
+ json_object **err_reply = (json_object **) pthread_getspecific(err_reply_key);
+ if (err_reply != NULL) {
+ if (*err_reply != NULL) {
+ pthread_mutex_lock(&json_lock);
+ json_object_put(*err_reply);
+ pthread_mutex_unlock(&json_lock);
+ }
+ free(err_reply);
+ err_reply = NULL;
+ if (pthread_setspecific(err_reply_key, err_reply) != 0) {
+ ERROR("Cannot set thread-specific hash value.");
+ }
+ }
+}
+
+static struct session_with_mutex *
+session_get_locked(unsigned int session_key, json_object **err)
+{
+ struct session_with_mutex *locked_session;
+
+ /* get non-exclusive (read) access to sessions_list (conns) */
+ DEBUG("LOCK wrlock %s", __func__);
+ if (pthread_rwlock_rdlock(&session_lock) != 0) {
+ if (*err) {
+ *err = create_error_reply("Locking failed.");
+ }
+ return NULL;
+ }
+ /* get session where send the RPC */
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
+ locked_session = locked_session->next);
+ if (!locked_session) {
+ if (*err) {
+ *err = create_error_reply("Session not found.");
+ }
+ return NULL;
+ }
+
+ /* get exclusive access to session */
+ DEBUG("LOCK mutex %s", __func__);
+ if (pthread_mutex_lock(&locked_session->lock) != 0) {
+ if (*err) {
+ *err = create_error_reply("Locking failed.");
+ }
+ goto wrlock_fail;
+ }
+ return locked_session;
+
+wrlock_fail:
+ DEBUG("UNLOCK wrlock %s", __func__);
+ pthread_rwlock_unlock(&session_lock);
+ return NULL;
+}
+
+static void
+session_unlock(struct session_with_mutex *locked_session)
+{
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("UNLOCK wrlock %s", __func__);
+ pthread_rwlock_unlock(&session_lock);
}
/**
@@ -324,27 +386,267 @@
* \return Value from nc_session_recv_reply() or NC_MSG_UNKNOWN when send_rpc() fails.
* On success, it returns NC_MSG_REPLY.
*/
-NC_MSG_TYPE netconf_send_recv_timed(struct nc_session *session, nc_rpc *rpc,
- int timeout, nc_reply **reply)
+NC_MSG_TYPE
+netconf_send_recv_timed(struct nc_session *session, nc_rpc *rpc, int timeout, nc_reply **reply)
{
- const nc_msgid msgid = NULL;
- NC_MSG_TYPE ret = NC_MSG_UNKNOWN;
- msgid = nc_session_send_rpc(session, rpc);
- if (msgid == NULL) {
- return ret;
- }
- do {
- ret = nc_session_recv_reply(session, timeout, reply);
- if (ret == NC_MSG_HELLO) {
- ERROR("<hello> received instead reply, it will be lost.");
- nc_reply_free(*reply);
- }
- if (ret == NC_MSG_WOULDBLOCK) {
- ERROR("Timeout for receiving RPC reply expired.");
- break;
- }
- } while (ret == NC_MSG_HELLO || ret == NC_MSG_NOTIFICATION);
- return ret;
+ const nc_msgid msgid = NULL;
+ NC_MSG_TYPE ret = NC_MSG_UNKNOWN;
+ msgid = nc_session_send_rpc(session, rpc);
+ if (msgid == NULL) {
+ return ret;
+ }
+ do {
+ ret = nc_session_recv_reply(session, timeout, reply);
+ if (ret == NC_MSG_HELLO) {
+ ERROR("<hello> received instead reply, it will be lost.");
+ nc_reply_free(*reply);
+ }
+ if (ret == NC_MSG_WOULDBLOCK) {
+ ERROR("Timeout for receiving RPC reply expired.");
+ break;
+ }
+ } while (ret == NC_MSG_HELLO || ret == NC_MSG_NOTIFICATION);
+ return ret;
+}
+
+static int
+ctx_download_module(struct session_with_mutex *session, const char *model_name, const char *revision, const char *schema_dir)
+{
+ json_object *err = NULL;
+ char *model_data = NULL, *model_path;
+ size_t length;
+ FILE *file;
+
+ DEBUG("UNLOCK rwlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ return 1;
+ }
+
+ model_data = netconf_getschema(session->session_key, model_name, revision, "yin", &err);
+
+ DEBUG("LOCK rwlock %s", __func__);
+ if (pthread_rwlock_wrlock(&session_lock) != 0) {
+ ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
+ return 1;
+ }
+
+ if (!model_data) {
+ if (err) {
+ json_object_put(err);
+ }
+ ERROR("Failed to get-schema of \"%s\".", model_name);
+ return 1;
+ }
+
+ if (revision) {
+ asprintf(&model_path, "%s/%s@%s.yin", schema_dir, model_name, revision);
+ } else {
+ asprintf(&model_path, "%s/%s.yin", schema_dir, model_name);
+ }
+
+ file = fopen(model_path, "w");
+ if (!file) {
+ ERROR("Failed to open \"%s\" for writing (%s).", model_path, strerror(errno));
+ free(model_data);
+ free(model_path);
+ return 1;
+ }
+ free(model_path);
+
+ length = strlen(model_data);
+ if (fwrite(model_data, 1, length, file) < length) {
+ ERROR("Failed to store the model \"%s\".", model_name);
+ free(model_data);
+ fclose(file);
+ return 1;
+ }
+
+ free(model_data);
+ fclose(file);
+ return 0;
+}
+
+static void
+ctx_enable_features(struct lys_module *module, const char *cpblt)
+{
+ char *ptr, *ptr2, *features = NULL;
+
+ /* parse features */
+ ptr = strstr(cpblt, "features=");
+ if (ptr) {
+ ptr += 9;
+ ptr2 = strchr(ptr, '&');
+ if (!ptr2) {
+ ptr2 = ptr + strlen(ptr);
+ }
+ features = strndup(ptr, ptr2 - ptr);
+ }
+
+ /* enable features */
+ if (features) {
+ /* basically manual strtok_r (to avoid macro) */
+ ptr2 = features;
+ for (ptr = features; *ptr; ++ptr) {
+ if (*ptr == ',') {
+ *ptr = '\0';
+ /* remember last feature */
+ ptr2 = ptr + 1;
+ }
+ }
+
+ ptr = features;
+ lys_features_enable(module, ptr);
+ while (ptr != ptr2) {
+ ptr += strlen(ptr) + 1;
+ lys_features_enable(module, ptr);
+ }
+
+ free(features);
+ }
+}
+
+static void
+ctx_enable_capabs(struct lys_module *ietfnc, json_object *cpb_array)
+{
+ json_object *item;
+ int i;
+ const char *capab;
+
+ /* set supported capabilities from ietf-netconf */
+ for (i = 0; i < json_object_array_length(cpb_array); ++i) {
+ item = json_object_array_get_idx(cpb_array, i);
+ capab = json_object_get_string(item);
+
+ if (!strncmp(capab, "urn:ietf:params:netconf:capability:", 35)) {
+ if (!strncmp(capab, "writable-running", 16)) {
+ lys_features_enable(ietfnc, "writable-running");
+ } else if (!strncmp(capab, "candidate", 9)) {
+ lys_features_enable(ietfnc, "candidate");
+ } else if (!strcmp(capab, "confirmed-commit:1.1")) {
+ lys_features_enable(ietfnc, "confirmed-commit");
+ } else if (!strncmp(capab, "rollback-on-error", 17)) {
+ lys_features_enable(ietfnc, "rollback-on-error");
+ } else if (!strcmp(capab, "validate:1.1")) {
+ lys_features_enable(ietfnc, "validate");
+ } else if (!strncmp(capab, "startup", 7)) {
+ lys_features_enable(ietfnc, "startup");
+ } else if (!strncmp(capab, "url", 3)) {
+ lys_features_enable(ietfnc, "url");
+ } else if (!strncmp(capab, "xpath", 5)) {
+ lys_features_enable(ietfnc, "xpath");
+ }
+ }
+ }
+}
+
+static int
+prepare_context(struct session_with_mutex *session)
+{
+ struct lys_module *module;
+ json_object *array, *item;
+ char *ptr, *ptr2;
+ char *model_name = NULL, *revision = NULL;
+ const char *capab;
+ int i, get_schema_support;
+
+ if (json_object_object_get_ex(session->hello_message, "capabilities", &array) == FALSE) {
+ return 1;
+ }
+
+ get_schema_support = 0;
+ for (i = 0; i < json_object_array_length(array); ++i) {
+ item = json_object_array_get_idx(array, i);
+ capab = json_object_get_string(item);
+
+ if (!strncmp(capab, "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", 51)) {
+ get_schema_support = 1;
+ break;
+ }
+ }
+
+ if (get_schema_support) {
+ errno = 0;
+ if (eaccess(SCHEMA_DIR, W_OK)) {
+ if (errno == ENOENT) {
+ if (mkdir(SCHEMA_DIR, 00755)) {
+ ERROR("Failed to create temp model dir \"%s\" (%s).", SCHEMA_DIR, strerror(errno));
+ return 1;
+ }
+ } else {
+ ERROR("Unable to write to temp model dir \"%s\" (%s).", SCHEMA_DIR, strerror(errno));
+ return 1;
+ }
+ }
+
+ session->ctx = ly_ctx_new(SCHEMA_DIR);
+ } else {
+ /* TODO */
+ session->ctx = ly_ctx_new(NULL);
+ }
+
+loop:
+ /* download all the models first or load them directly */
+ for (i = 0; i < json_object_array_length(array); ++i) {
+ item = json_object_array_get_idx(array, i);
+ capab = json_object_get_string(item);
+ if (!strncmp(capab, "urn:ietf:params:netconf:capability", 34)
+ || !strncmp(capab, "urn:ietf:params:netconf:base", 28)) {
+ continue;
+ }
+
+ /* get module */
+ ptr = strstr(capab, "module=");
+ if (!ptr) {
+ ERROR("Unknown capability \"%s\" could not be parsed.", capab);
+ continue;
+ }
+ ptr += 7;
+ ptr2 = strchr(ptr, '&');
+ if (!ptr2) {
+ ptr2 = ptr + strlen(ptr);
+ }
+ model_name = strndup(ptr, ptr2 - ptr);
+
+ /* get revision */
+ ptr = strstr(capab, "revision=");
+ if (ptr) {
+ ptr += 9;
+ ptr2 = strchr(ptr, '&');
+ if (!ptr2) {
+ ptr2 = ptr + strlen(ptr);
+ }
+ revision = strndup(ptr, ptr2 - ptr);
+ }
+
+ if (get_schema_support) {
+ ctx_download_module(session, model_name, revision, SCHEMA_DIR);
+ } else {
+ module = ly_ctx_get_module(session->ctx, model_name, revision);
+ if (!module) {
+ module = ly_ctx_load_module(session->ctx, NULL, model_name, revision);
+ if (module) {
+ if (!strcmp(module->name, "ietf-netconf")) {
+ ctx_enable_capabs(module, array);
+ } else {
+ ctx_enable_features(module, capab);
+ }
+ }
+ }
+ }
+
+ free(model_name);
+ free(revision);
+ revision = NULL;
+ }
+
+ if (get_schema_support) {
+ /* we have downloaded all the models, load them now */
+ get_schema_support = 0;
+ goto loop;
+ }
+
+ return 0;
}
/**
@@ -352,139 +654,152 @@
*
* \warning Session_key hash is not bound with caller identification. This could be potential security risk.
*/
-static const char *netconf_connect(const char* host, const char* port, const char* user, const char* pass, struct nc_cpblts * cpblts)
+static unsigned int
+netconf_connect(const char *host, const char *port, const char *user, const char *pass, struct nc_cpblts *cpblts)
{
- struct nc_session* session = NULL;
- struct session_with_mutex * locked_session, *last_session;
+ struct nc_session* session = NULL;
+ struct session_with_mutex *locked_session, *last_session;
- /* connect to the requested NETCONF server */
- password = (char*)pass;
- DEBUG("prepare to connect %s@%s:%s", user, host, port);
- session = nc_session_connect(host, (unsigned short) atoi (port), user, cpblts);
- DEBUG("nc_session_connect done");
+ /* connect to the requested NETCONF server */
+ password = (char*)pass;
+ DEBUG("prepare to connect %s@%s:%s", user, host, port);
+ session = nc_session_connect(host, (unsigned short) atoi (port), user, cpblts);
+ DEBUG("nc_session_connect done");
- /* if connected successful, add session to the list */
- if (session != NULL) {
- if ((locked_session = calloc(1, sizeof(struct session_with_mutex))) == NULL || pthread_mutex_init (&locked_session->lock, NULL) != 0) {
- nc_session_free(session);
- session = NULL;
- free(locked_session);
- locked_session = NULL;
- ERROR("Creating structure session_with_mutex failed %d (%s)", errno, strerror(errno));
- return 0;
- }
- locked_session->session = session;
- locked_session->last_activity = time(NULL);
- locked_session->hello_message = NULL;
- locked_session->closed = 0;
- pthread_mutex_init (&locked_session->lock, NULL);
- DEBUG("Before session_lock");
- /* get exclusive access to sessions_list (conns) */
- DEBUG("LOCK wrlock %s", __func__);
- if (pthread_rwlock_wrlock(&session_lock) != 0) {
- nc_session_free(session);
- free (locked_session);
- ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
- return 0;
- }
- locked_session->ntfc_subscribed = 0;
- DEBUG("Add connection to the list");
- if (!netconf_sessions_list) {
+ /* if connected successful, add session to the list */
+ if (session != NULL) {
+ if ((locked_session = calloc(1, sizeof(struct session_with_mutex))) == NULL || pthread_mutex_init (&locked_session->lock, NULL) != 0) {
+ nc_session_free(session);
+ session = NULL;
+ free(locked_session);
+ locked_session = NULL;
+ ERROR("Creating structure session_with_mutex failed %d (%s)", errno, strerror(errno));
+ return 0;
+ }
+ locked_session->session = session;
+ locked_session->last_activity = time(NULL);
+ locked_session->hello_message = NULL;
+ locked_session->closed = 0;
+ pthread_mutex_init(&locked_session->lock, NULL);
+ DEBUG("Before session_lock");
+ /* get exclusive access to sessions_list (conns) */
+ DEBUG("LOCK wrlock %s", __func__);
+ if (pthread_rwlock_wrlock(&session_lock) != 0) {
+ nc_session_free(session);
+ free(locked_session);
+ ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
+ return 0;
+ }
+ locked_session->ntfc_subscribed = 0;
+ DEBUG("Add connection to the list");
+ if (!netconf_sessions_list) {
netconf_sessions_list = locked_session;
} else {
for (last_session = netconf_sessions_list; last_session->next; last_session = last_session->next);
last_session->next = locked_session;
locked_session->prev = last_session;
}
- DEBUG("Before session_unlock");
+ DEBUG("Before session_unlock");
- /* lock session */
- DEBUG("LOCK mutex %s", __func__);
- pthread_mutex_lock(&locked_session->lock);
+ /* no need to lock session, noone can read it while we have wrlock */
- /* unlock session list */
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock (&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
+ /* store information about session from hello message for future usage */
+ prepare_status_message(locked_session, session);
- /* store information about session from hello message for future usage */
- prepare_status_message(locked_session, session);
+ /* create context from the hello message cpabilities */
+ if (prepare_context(locked_session)) {
+ nc_session_free(session);
+ free(locked_session);
+ DEBUG("UNLOCK wrlock %s", __func__);
+ pthread_rwlock_unlock(&session_lock);
+ ERROR("Failed to prepare context");
+ return 0;
+ }
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("NETCONF session established");
+ locked_session->session_key = session_key_generator;
+ ++session_key_generator;
+ if (session_key_generator == UINT_MAX) {
+ session_key_generator = 1;
+ }
- DEBUG("NETCONF session established");
- return nc_session_get_id(session);
- } else {
- ERROR("Connection could not be established");
- return 0;
- }
+ /* unlock session list */
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ return locked_session->session_key;
+ }
+
+ ERROR("Connection could not be established");
+ return 0;
}
-static int close_and_free_session(struct session_with_mutex *locked_session)
+static int
+close_and_free_session(struct session_with_mutex *locked_session)
{
- DEBUG("lock private lock.");
- DEBUG("LOCK mutex %s", __func__);
- if (pthread_mutex_lock(&locked_session->lock) != 0) {
- ERROR("Error while locking rwlock");
- }
- locked_session->ntfc_subscribed = 0;
- locked_session->closed = 1;
- if (locked_session->session != NULL) {
- nc_session_free(locked_session->session);
- locked_session->session = NULL;
- }
- DEBUG("session closed.");
- DEBUG("unlock private lock.");
- DEBUG("UNLOCK mutex %s", __func__);
- if (pthread_mutex_unlock(&locked_session->lock) != 0) {
- ERROR("Error while locking rwlock");
- }
+ DEBUG("lock private lock.");
+ DEBUG("LOCK mutex %s", __func__);
+ if (pthread_mutex_lock(&locked_session->lock) != 0) {
+ ERROR("Error while locking rwlock");
+ }
+ locked_session->ntfc_subscribed = 0;
+ locked_session->closed = 1;
+ if (locked_session->session != NULL) {
+ nc_session_free(locked_session->session);
+ locked_session->session = NULL;
+ }
+ DEBUG("session closed.");
+ DEBUG("unlock private lock.");
+ DEBUG("UNLOCK mutex %s", __func__);
+ if (pthread_mutex_unlock(&locked_session->lock) != 0) {
+ ERROR("Error while locking rwlock");
+ }
- DEBUG("unlock session lock.");
- DEBUG("closed session, disabled notif(?), wait 2s");
- usleep(500000); /* let notification thread stop */
+ DEBUG("unlock session lock.");
+ DEBUG("closed session, disabled notif(?), wait 0.5s");
+ usleep(500000); /* let notification thread stop */
- /* session shouldn't be used by now */
- /** \todo free all notifications from queue */
- free(locked_session->notifications);
- pthread_mutex_destroy(&locked_session->lock);
- if (locked_session->hello_message != NULL) {
- /** \todo free hello_message */
- //json_object_put(locked_session->hello_message);
- locked_session->hello_message = NULL;
- }
- locked_session->session = NULL;
- free(locked_session);
- locked_session = NULL;
- DEBUG("NETCONF session closed, everything cleared.");
- return (EXIT_SUCCESS);
+ /* session shouldn't be used by now */
+ /** \todo free all notifications from queue */
+ free(locked_session->notifications);
+ pthread_mutex_destroy(&locked_session->lock);
+ if (locked_session->hello_message != NULL) {
+ json_object_put(locked_session->hello_message);
+ locked_session->hello_message = NULL;
+ }
+ locked_session->session = NULL;
+ ly_ctx_destroy(locked_session->ctx);
+ free(locked_session);
+ locked_session = NULL;
+ DEBUG("NETCONF session closed, everything cleared.");
+ return (EXIT_SUCCESS);
}
-static int netconf_close(const char *session_id, json_object **reply)
+static int
+netconf_close(unsigned int session_key, json_object **reply)
{
- struct session_with_mutex *locked_session;
+ struct session_with_mutex *locked_session;
- DEBUG("Session to close: %s", session_id);
+ DEBUG("Session to close: %u", session_key);
- /* get exclusive (write) access to sessions_list (conns) */
- DEBUG("lock session lock.");
- DEBUG("LOCK wrlock %s", __func__);
- if (pthread_rwlock_wrlock (&session_lock) != 0) {
- ERROR("Error while locking rwlock");
- (*reply) = create_error("Internal: Error while locking.");
- return EXIT_FAILURE;
- }
- /* remove session from the active sessions list -> nobody new can now work with session */
- for (locked_session = netconf_sessions_list;
- locked_session && strcmp(nc_session_get_id(locked_session->session), session_id);
+ /* get exclusive (write) access to sessions_list (conns) */
+ DEBUG("lock session lock.");
+ DEBUG("LOCK wrlock %s", __func__);
+ if (pthread_rwlock_wrlock (&session_lock) != 0) {
+ ERROR("Error while locking rwlock");
+ (*reply) = create_error_reply("Internal: Error while locking.");
+ return EXIT_FAILURE;
+ }
+ /* remove session from the active sessions list -> nobody new can now work with session */
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
locked_session = locked_session->next);
if (!locked_session) {
- ERROR("Could not find the session \"%s\" to close.", session_id);
- (*reply) = create_error("Internal: Error while finding a session.");
+ ERROR("Could not find the session %u to close.", session_key);
+ (*reply) = create_error_reply("Internal: Error while finding a session.");
return EXIT_FAILURE;
}
@@ -498,1607 +813,2216 @@
}
}
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock (&session_lock) != 0) {
- ERROR("Error while unlocking rwlock");
- (*reply) = create_error("Internal: Error while unlocking.");
- }
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock (&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock");
+ (*reply) = create_error_reply("Internal: Error while unlocking.");
+ }
- if ((locked_session != NULL) && (locked_session->session != NULL)) {
- return close_and_free_session(locked_session);
- } else {
- ERROR("Unknown session to close");
- (*reply) = create_error("Internal: Unkown session to close.");
- return (EXIT_FAILURE);
- }
- (*reply) = NULL;
+ if ((locked_session != NULL) && (locked_session->session != NULL)) {
+ return close_and_free_session(locked_session);
+ } else {
+ ERROR("Unknown session to close");
+ (*reply) = create_error_reply("Internal: Unkown session to close.");
+ return (EXIT_FAILURE);
+ }
+ (*reply) = NULL;
}
/**
* Test reply message type and return error message.
*
- * \param[in] session nc_session internal struct
+ * \param[in] session nc_session internal struct
* \param[in] session_key session ID, 0 to disable disconnect on error
- * \param[in] msgt RPC-REPLY message type
+ * \param[in] msgt RPC-REPLY message type
* \param[out] data
* \return NULL on success
*/
-json_object *netconf_test_reply(struct nc_session *session, const char *session_id, NC_MSG_TYPE msgt, nc_reply *reply, char **data)
+json_object *
+netconf_test_reply(struct nc_session *session, unsigned int session_key, NC_MSG_TYPE msgt, nc_reply *reply, char **data)
{
- NC_REPLY_TYPE replyt;
- json_object *err = NULL;
+ NC_REPLY_TYPE replyt;
+ json_object *err = NULL;
- /* process the result of the operation */
- switch (msgt) {
- case NC_MSG_UNKNOWN:
- if (nc_session_get_status(session) != NC_SESSION_STATUS_WORKING) {
- ERROR("mod_netconf: receiving rpc-reply failed");
- if (session_id) {
- netconf_close(session_id, &err);
- }
- if (err != NULL) {
- return err;
- }
- return create_error("Internal: Receiving RPC-REPLY failed.");
- }
- case NC_MSG_NONE:
- /* there is error handled by callback */
- if (data != NULL) {
- free(*data);
- (*data) = NULL;
- }
- return NULL;
- case NC_MSG_REPLY:
- switch (replyt = nc_reply_get_type(reply)) {
- case NC_REPLY_OK:
- if ((data != NULL) && (*data != NULL)) {
- free(*data);
- (*data) = NULL;
- }
- return create_ok();
- case NC_REPLY_DATA:
- if (((*data) = nc_reply_get_data(reply)) == NULL) {
- ERROR("mod_netconf: no data from reply");
- return create_error("Internal: No data from reply received.");
- } else {
- return NULL;
- }
- break;
- case NC_REPLY_ERROR:
- ERROR("mod_netconf: unexpected rpc-reply (%d)", replyt);
- if (data != NULL) {
- free(*data);
- (*data) = NULL;
- }
- return create_error(nc_reply_get_errormsg(reply));
- default:
- ERROR("mod_netconf: unexpected rpc-reply (%d)", replyt);
- if (data != NULL) {
- free(*data);
- (*data) = NULL;
- }
- return create_error("Unknown type of NETCONF reply.");
- }
- break;
- default:
- ERROR("mod_netconf: unexpected reply message received (%d)", msgt);
- if (data != NULL) {
- free(*data);
- (*data) = NULL;
- }
- return create_error("Internal: Unexpected RPC-REPLY message type.");
- }
+ /* process the result of the operation */
+ switch (msgt) {
+ case NC_MSG_UNKNOWN:
+ if (nc_session_get_status(session) != NC_SESSION_STATUS_WORKING) {
+ ERROR("mod_netconf: receiving rpc-reply failed");
+ if (session_key) {
+ netconf_close(session_key, &err);
+ }
+ if (err != NULL) {
+ return err;
+ }
+ return create_error_reply("Internal: Receiving RPC-REPLY failed.");
+ }
+ case NC_MSG_NONE:
+ /* there is error handled by callback */
+ if (data != NULL) {
+ free(*data);
+ (*data) = NULL;
+ }
+ return NULL;
+ case NC_MSG_REPLY:
+ switch (replyt = nc_reply_get_type(reply)) {
+ case NC_REPLY_OK:
+ if ((data != NULL) && (*data != NULL)) {
+ free(*data);
+ (*data) = NULL;
+ }
+ return create_ok_reply();
+ case NC_REPLY_DATA:
+ if (((*data) = nc_reply_get_data(reply)) == NULL) {
+ ERROR("mod_netconf: no data from reply");
+ return create_error_reply("Internal: No data from reply received.");
+ } else {
+ return NULL;
+ }
+ break;
+ case NC_REPLY_ERROR:
+ ERROR("mod_netconf: unexpected rpc-reply (%d)", replyt);
+ if (data != NULL) {
+ free(*data);
+ (*data) = NULL;
+ }
+ return create_error_reply(nc_reply_get_errormsg(reply));
+ default:
+ ERROR("mod_netconf: unexpected rpc-reply (%d)", replyt);
+ if (data != NULL) {
+ free(*data);
+ (*data) = NULL;
+ }
+ return create_error_reply("Unknown type of NETCONF reply.");
+ }
+ break;
+ default:
+ ERROR("mod_netconf: unexpected reply message received (%d)", msgt);
+ if (data != NULL) {
+ free(*data);
+ (*data) = NULL;
+ }
+ return create_error_reply("Internal: Unexpected RPC-REPLY message type.");
+ }
}
-json_object *netconf_unlocked_op(struct nc_session *session, nc_rpc* rpc)
+json_object *
+netconf_unlocked_op(struct nc_session *session, nc_rpc *rpc)
{
- nc_reply* reply = NULL;
- NC_MSG_TYPE msgt;
+ nc_reply* reply = NULL;
+ NC_MSG_TYPE msgt;
- /* check requests */
- if (rpc == NULL) {
- ERROR("mod_netconf: rpc is not created");
- return create_error("Internal error: RPC is not created");
- }
+ /* check requests */
+ if (rpc == NULL) {
+ ERROR("mod_netconf: rpc is not created");
+ return create_error_reply("Internal error: RPC is not created");
+ }
- if (session != NULL) {
- /* send the request and get the reply */
- msgt = netconf_send_recv_timed(session, rpc, 5000, &reply);
- /* process the result of the operation */
- return netconf_test_reply(session, 0, msgt, reply, NULL);
- } else {
- ERROR("Unknown session to process.");
- return create_error("Internal error: Unknown session to process.");
- }
+ if (session != NULL) {
+ /* send the request and get the reply */
+ msgt = netconf_send_recv_timed(session, rpc, 50000, &reply);
+ /* process the result of the operation */
+ return netconf_test_reply(session, 0, msgt, reply, NULL);
+ } else {
+ ERROR("Unknown session to process.");
+ return create_error_reply("Internal error: Unknown session to process.");
+ }
}
/**
* Perform RPC method that returns data.
*
- * \param[in] session_id session identifier
- * \param[in] rpc RPC message to perform
- * \param[out] received_data received data string, can be NULL when no data expected, value can be set to NULL if no data received
+ * \param[in] session_id session identifier
+ * \param[in] rpc RPC message to perform
+ * \param[out] received_data received data string, can be NULL when no data expected, value can be set to NULL if no data received
* \return NULL on success, json object with error otherwise
*/
-static json_object *netconf_op(const char *session_id, nc_rpc* rpc, char **received_data)
+static json_object *
+netconf_op(unsigned int session_key, nc_rpc *rpc, char **received_data)
{
- struct nc_session *session = NULL;
- struct session_with_mutex * locked_session;
- nc_reply* reply = NULL;
- json_object *res = NULL;
- char *data = NULL;
- NC_MSG_TYPE msgt;
+ struct session_with_mutex * locked_session;
+ nc_reply* reply = NULL;
+ json_object *res = NULL;
+ char *data = NULL;
+ NC_MSG_TYPE msgt;
- /* check requests */
- if (rpc == NULL) {
- ERROR("mod_netconf: rpc is not created");
- res = create_error("Internal: RPC could not be created.");
- data = NULL;
- goto finished;
- }
+ /* check requests */
+ if (rpc == NULL) {
+ ERROR("mod_netconf: rpc is not created");
+ res = create_error_reply("Internal: RPC could not be created.");
+ data = NULL;
+ goto finished;
+ }
- /* get non-exclusive (read) access to sessions_list (conns) */
- DEBUG("LOCK wrlock %s", __func__);
- if (pthread_rwlock_rdlock(&session_lock) != 0) {
- ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
- res = create_error("Internal: Lock failed.");
- data = NULL;
- goto finished;
- }
- /* get session where send the RPC */
- for (locked_session = netconf_sessions_list;
- locked_session && strcmp(nc_session_get_id(locked_session->session), session_id);
- locked_session = locked_session->next);
- if (locked_session != NULL) {
- session = locked_session->session;
- }
- if (session != NULL) {
- /* get exclusive access to session */
- DEBUG("LOCK mutex %s", __func__);
- if (pthread_mutex_lock(&locked_session->lock) != 0) {
- /* unlock before returning error */
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock (&session_lock) != 0) {
+ locked_session = session_get_locked(session_key, &res);
+ if (!locked_session) {
+ ERROR("Unknown session or locking failed.");
+ goto finished;
+ }
- ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
- res = create_error("Internal: Could not unlock.");
- goto finished;
- }
- res = create_error("Internal: Could not unlock.");
- }
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
+ locked_session->last_activity = time(NULL);
- ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
- res = create_error("Internal: Could not unlock.");
- }
+ /* send the request and get the reply */
+ msgt = netconf_send_recv_timed(locked_session->session, rpc, 2000000, &reply);
- locked_session->last_activity = time(NULL);
+ session_unlock(locked_session);
- /* send the request and get the reply */
- msgt = netconf_send_recv_timed(session, rpc, 5000, &reply);
+ res = netconf_test_reply(locked_session->session, session_key, msgt, reply, &data);
- /* first release exclusive lock for this session */
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- /* end of critical section */
-
- res = netconf_test_reply(session, session_id, msgt, reply, &data);
- } else {
- /* release lock on failure */
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- ERROR("Unknown session to process.");
- res = create_error("Unknown session to process.");
- data = NULL;
- }
finished:
- nc_reply_free(reply);
- if (received_data != NULL) {
- (*received_data) = data;
- } else {
- if (data != NULL) {
- free(data);
- data = NULL;
- }
- }
- return res;
+ nc_reply_free(reply);
+ if (received_data != NULL) {
+ (*received_data) = data;
+ } else {
+ if (data != NULL) {
+ free(data);
+ data = NULL;
+ }
+ }
+ return res;
}
-static char* netconf_getconfig(const char* session_key, NC_DATASTORE source, const char* filter, json_object **err)
+static char *
+netconf_getconfig(unsigned int session_key, NC_DATASTORE source, const char *filter, int strict, json_object **err)
{
- nc_rpc* rpc;
- struct nc_filter *f = NULL;
- char* data = NULL;
- json_object *res = NULL;
+ nc_rpc* rpc;
+ struct nc_filter *f = NULL;
+ struct session_with_mutex *locked_session;
+ char* data = NULL, *data_xml;
+ json_object *res = NULL, *data_cjson;
+ enum json_tokener_error tok_err;
+ struct lyd_node *node, *sibling, *next;
- /* create filter if set */
- if (filter != NULL) {
- f = nc_filter_new(NC_FILTER_SUBTREE, filter);
- }
+ /* create filter if set */
+ if (filter != NULL) {
+ f = nc_filter_new(NC_FILTER_SUBTREE, filter);
+ }
- /* create requests */
- rpc = nc_rpc_getconfig (source, f);
- nc_filter_free(f);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return (NULL);
- }
+ /* create requests */
+ rpc = nc_rpc_getconfig(source, f);
+ nc_filter_free(f);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return (NULL);
+ }
- /* tell server to show all elements even if they have default values */
+ /* tell server to show all elements even if they have default values */
#ifdef HAVE_WITHDEFAULTS_TAGGED
- if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL_TAGGED))
+ if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL_TAGGED))
#else
- if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_NOTSET))
- //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL))
+ if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_NOTSET))
+ //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL))
#endif
{
- ERROR("mod_netconf: setting withdefaults failed");
- }
+ ERROR("mod_netconf: setting withdefaults failed");
+ }
- res = netconf_op(session_key, rpc, &data);
- nc_rpc_free (rpc);
- if (res != NULL) {
- (*err) = res;
- } else {
- (*err) = NULL;
- }
+ res = netconf_op(session_key, rpc, &data);
+ nc_rpc_free(rpc);
+ if (res != NULL) {
+ (*err) = res;
+ } else {
+ (*err) = NULL;
+ }
- return (data);
+ if (data) {
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
+ locked_session = locked_session->next);
+ /* won't fail */
+
+ asprintf(&data_xml, "<get-config>%s</get-config>", data);
+ node = lyd_parse(locked_session->ctx, data_xml, LYD_XML, LYD_OPT_GETCONFIG | (strict ? LYD_OPT_STRICT : 0));
+ free(data_xml);
+ free(data);
+ if (!node) {
+ ERROR("Parsing <get-config> data failed.");
+ return NULL;
+ }
+
+ /* replace XML data with JSON data */
+ if (lyd_print_mem(&data, node, LYD_JSON)) {
+ ERROR("Printing JSON <get-config> data failed.");
+ LY_TREE_FOR(node, sibling) {
+ lyd_free(sibling);
+ }
+ return NULL;
+ }
+
+ /* parse JSON data into cjson */
+ pthread_mutex_lock(&json_lock);
+ data_cjson = json_tokener_parse_verbose(data, &tok_err);
+ if (!data_cjson) {
+ ERROR("Parsing JSON config failed (%s).", json_tokener_error_desc(tok_err));
+ pthread_mutex_unlock(&json_lock);
+ LY_TREE_FOR(node, sibling) {
+ lyd_free(sibling);
+ }
+ free(data);
+ return NULL;
+ }
+ free(data);
+
+ /* go simultaneously through both trees and add metadata */
+ LY_TREE_FOR_SAFE(node, next, sibling) {
+ node_add_metadata_recursive(sibling, NULL, data_cjson);
+ lyd_free(sibling);
+ }
+
+ data = strdup(json_object_to_json_string_ext(data_cjson, 0));
+ json_object_put(data_cjson);
+ pthread_mutex_unlock(&json_lock);
+ }
+
+ return (data);
}
-static char* netconf_getschema(const char* session_key, const char* identifier, const char* version, const char* format, json_object **err)
+static char *
+netconf_getschema(unsigned int session_key, const char *identifier, const char *version, const char *format, json_object **err)
{
- nc_rpc* rpc;
- char* data = NULL;
- json_object *res = NULL;
+ nc_rpc* rpc;
+ char* data = NULL;
+ json_object *res = NULL;
- /* create requests */
- rpc = nc_rpc_getschema(identifier, version, format);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return (NULL);
- }
+ /* create requests */
+ rpc = nc_rpc_getschema(identifier, version, format);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return (NULL);
+ }
- res = netconf_op(session_key, rpc, &data);
- nc_rpc_free (rpc);
- if (res != NULL) {
- (*err) = res;
- } else {
- (*err) = NULL;
- }
+ res = netconf_op(session_key, rpc, &data);
+ nc_rpc_free (rpc);
+ if (res != NULL) {
+ (*err) = res;
+ } else {
+ (*err) = NULL;
+ }
- return (data);
+ return (data);
}
-static char* netconf_get(const char* session_key, const char* filter, json_object **err)
+static char *
+netconf_get(unsigned int session_key, const char* filter, int strict, json_object **err)
{
- nc_rpc* rpc;
- struct nc_filter *f = NULL;
- char* data = NULL;
- json_object *res = NULL;
+ nc_rpc* rpc;
+ struct nc_filter *f = NULL;
+ char* data = NULL, *data_xml;
+ json_object *res = NULL, *data_cjson;
+ enum json_tokener_error tok_err;
+ struct session_with_mutex *locked_session;
+ struct lyd_node *node, *sibling, *next;
- /* create filter if set */
- if (filter != NULL) {
- f = nc_filter_new(NC_FILTER_SUBTREE, filter);
- }
+ /* create filter if set */
+ if (filter != NULL) {
+ f = nc_filter_new(NC_FILTER_SUBTREE, filter);
+ }
- /* create requests */
- rpc = nc_rpc_get (f);
- nc_filter_free(f);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return (NULL);
- }
+ /* create requests */
+ rpc = nc_rpc_get(f);
+ nc_filter_free(f);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return (NULL);
+ }
- /* tell server to show all elements even if they have default values */
- if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_NOTSET)) {
- //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL)) {
- //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL_TAGGED)) {
- ERROR("mod_netconf: setting withdefaults failed");
- }
+ /* tell server to show all elements even if they have default values */
+ if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_NOTSET)) {
+ //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL)) {
+ //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL_TAGGED)) {
+ ERROR("mod_netconf: setting withdefaults failed");
+ }
- res = netconf_op(session_key, rpc, &data);
- nc_rpc_free (rpc);
- if (res == NULL) {
- (*err) = res;
- } else {
- (*err) = NULL;
- }
+ res = netconf_op(session_key, rpc, &data);
+ nc_rpc_free(rpc);
+ if (res != NULL) {
+ (*err) = res;
+ } else {
+ (*err) = NULL;
+ }
- return (data);
+ if (data) {
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
+ locked_session = locked_session->next);
+ /* won't fail */
+
+ asprintf(&data_xml, "<get>%s</get>", data);
+ node = lyd_parse(locked_session->ctx, data_xml, LYD_XML, LYD_OPT_GET | (strict ? LYD_OPT_STRICT : 0));
+ free(data_xml);
+ free(data);
+ if (!node) {
+ ERROR("Parsing <get> data failed.");
+ return NULL;
+ }
+
+ /* replace XML data with JSON data */
+ if (lyd_print_mem(&data, node, LYD_JSON)) {
+ ERROR("Printing JSON <get> data failed.");
+ LY_TREE_FOR(node, sibling) {
+ lyd_free(sibling);
+ }
+ return NULL;
+ }
+
+ /* parse JSON data into cjson */
+ pthread_mutex_lock(&json_lock);
+ data_cjson = json_tokener_parse_verbose(data, &tok_err);
+ if (!data_cjson) {
+ ERROR("Parsing JSON config failed (%s).", json_tokener_error_desc(tok_err));
+ pthread_mutex_unlock(&json_lock);
+ LY_TREE_FOR(node, sibling) {
+ lyd_free(sibling);
+ }
+ free(data);
+ return NULL;
+ }
+ free(data);
+
+ /* go simultaneously through both trees and add metadata */
+ LY_TREE_FOR_SAFE(node, next, sibling) {
+ node_add_metadata_recursive(sibling, NULL, data_cjson);
+ lyd_free(sibling);
+ }
+
+ data = strdup(json_object_to_json_string_ext(data_cjson, 0));
+ json_object_put(data_cjson);
+ pthread_mutex_unlock(&json_lock);
+ }
+
+ return data;
}
-static json_object *netconf_copyconfig(const char* session_key, NC_DATASTORE source, NC_DATASTORE target, const char* config, const char *uri_src, const char *uri_trg)
+static json_object *
+netconf_copyconfig(unsigned int session_key, NC_DATASTORE source, NC_DATASTORE target, const char *config,
+ const char *uri_src, const char *uri_trg)
{
- nc_rpc* rpc;
- json_object *res = NULL;
+ nc_rpc* rpc;
+ json_object *res = NULL;
- /* create requests */
- if (source == NC_DATASTORE_CONFIG) {
- if (target == NC_DATASTORE_URL) {
- /* config, url */
- rpc = nc_rpc_copyconfig(source, target, config, uri_trg);
- } else {
- /* config, datastore */
- rpc = nc_rpc_copyconfig(source, target, config);
- }
- } else if (source == NC_DATASTORE_URL) {
- if (target == NC_DATASTORE_URL) {
- /* url, url */
- rpc = nc_rpc_copyconfig(source, target, uri_src, uri_trg);
- } else {
- /* url, datastore */
- rpc = nc_rpc_copyconfig(source, target, uri_src);
- }
- } else {
- if (target == NC_DATASTORE_URL) {
- /* datastore, url */
- rpc = nc_rpc_copyconfig(source, target, uri_trg);
- } else {
- /* datastore, datastore */
- rpc = nc_rpc_copyconfig(source, target);
- }
- }
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return create_error("Internal: Creating rpc request failed");
- }
+ /* create requests */
+ if (source == NC_DATASTORE_CONFIG) {
+ if (target == NC_DATASTORE_URL) {
+ /* config, url */
+ rpc = nc_rpc_copyconfig(source, target, config, uri_trg);
+ } else {
+ /* config, datastore */
+ rpc = nc_rpc_copyconfig(source, target, config);
+ }
+ } else if (source == NC_DATASTORE_URL) {
+ if (target == NC_DATASTORE_URL) {
+ /* url, url */
+ rpc = nc_rpc_copyconfig(source, target, uri_src, uri_trg);
+ } else {
+ /* url, datastore */
+ rpc = nc_rpc_copyconfig(source, target, uri_src);
+ }
+ } else {
+ if (target == NC_DATASTORE_URL) {
+ /* datastore, url */
+ rpc = nc_rpc_copyconfig(source, target, uri_trg);
+ } else {
+ /* datastore, datastore */
+ rpc = nc_rpc_copyconfig(source, target);
+ }
+ }
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return create_error_reply("Internal: Creating rpc request failed");
+ }
- res = netconf_op(session_key, rpc, NULL);
- nc_rpc_free (rpc);
+ res = netconf_op(session_key, rpc, NULL);
+ nc_rpc_free(rpc);
- return res;
+ return res;
}
-static json_object *netconf_editconfig(const char* session_key, NC_DATASTORE source, NC_DATASTORE target, NC_EDIT_DEFOP_TYPE defop, NC_EDIT_ERROPT_TYPE erropt, NC_EDIT_TESTOPT_TYPE testopt, const char* config_or_url)
+static json_object *
+netconf_editconfig(unsigned int session_key, NC_DATASTORE source, NC_DATASTORE target, NC_EDIT_DEFOP_TYPE defop,
+ NC_EDIT_ERROPT_TYPE erropt, NC_EDIT_TESTOPT_TYPE testopt, const char *config_or_url)
{
- nc_rpc* rpc;
- json_object *res = NULL;
+ nc_rpc* rpc;
+ json_object *res = NULL;
- /* create requests */
- rpc = nc_rpc_editconfig(target, source, defop, erropt, testopt, config_or_url);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return create_error("Internal: Creating rpc request failed");
- }
+ /* create requests */
+ rpc = nc_rpc_editconfig(target, source, defop, erropt, testopt, config_or_url);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return create_error_reply("Internal: Creating rpc request failed");
+ }
- res = netconf_op(session_key, rpc, NULL);
- nc_rpc_free (rpc);
+ res = netconf_op(session_key, rpc, NULL);
+ nc_rpc_free (rpc);
- return res;
+ return res;
}
-static json_object *netconf_killsession(const char* session_key, const char* sid)
+static json_object *
+netconf_killsession(unsigned int session_key, const char *sid)
{
- nc_rpc* rpc;
- json_object *res = NULL;
+ nc_rpc *rpc;
+ json_object *res = NULL;
- /* create requests */
- rpc = nc_rpc_killsession(sid);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return create_error("Internal: Creating rpc request failed");
- }
+ /* create requests */
+ rpc = nc_rpc_killsession(sid);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return create_error_reply("Internal: Creating rpc request failed");
+ }
- res = netconf_op(session_key, rpc, NULL);
- nc_rpc_free (rpc);
- return res;
+ res = netconf_op(session_key, rpc, NULL);
+ nc_rpc_free(rpc);
+ return res;
}
-static json_object *netconf_onlytargetop(const char* session_key, NC_DATASTORE target, nc_rpc* (*op_func)(NC_DATASTORE))
+static json_object *
+netconf_onlytargetop(unsigned int session_key, NC_DATASTORE target, nc_rpc *(*op_func)(NC_DATASTORE))
{
- nc_rpc* rpc;
- json_object *res = NULL;
+ nc_rpc* rpc;
+ json_object *res = NULL;
- /* create requests */
- rpc = op_func(target);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return create_error("Internal: Creating rpc request failed");
- }
+ /* create requests */
+ rpc = op_func(target);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return create_error_reply("Internal: Creating rpc request failed");
+ }
- res = netconf_op(session_key, rpc, NULL);
- nc_rpc_free (rpc);
- return res;
+ res = netconf_op(session_key, rpc, NULL);
+ nc_rpc_free (rpc);
+ return res;
}
-static json_object *netconf_deleteconfig(const char* session_key, NC_DATASTORE target, const char *url)
+static json_object *
+netconf_deleteconfig(unsigned int session_key, NC_DATASTORE target, const char *url)
{
- nc_rpc *rpc = NULL;
- json_object *res = NULL;
- if (target != NC_DATASTORE_URL) {
- rpc = nc_rpc_deleteconfig(target);
- } else {
- rpc = nc_rpc_deleteconfig(target, url);
- }
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return create_error("Internal: Creating rpc request failed");
- }
+ nc_rpc *rpc = NULL;
+ json_object *res = NULL;
+ if (target != NC_DATASTORE_URL) {
+ rpc = nc_rpc_deleteconfig(target);
+ } else {
+ rpc = nc_rpc_deleteconfig(target, url);
+ }
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return create_error_reply("Internal: Creating rpc request failed");
+ }
- res = netconf_op(session_key, rpc, NULL);
- nc_rpc_free (rpc);
- return res;
+ res = netconf_op(session_key, rpc, NULL);
+ nc_rpc_free (rpc);
+ return res;
}
-static json_object *netconf_lock(const char* session_key, NC_DATASTORE target)
+static json_object *
+netconf_lock(unsigned int session_key, NC_DATASTORE target)
{
- return (netconf_onlytargetop(session_key, target, nc_rpc_lock));
+ return (netconf_onlytargetop(session_key, target, nc_rpc_lock));
}
-static json_object *netconf_unlock(const char* session_key, NC_DATASTORE target)
+static json_object *
+netconf_unlock(unsigned int session_key, NC_DATASTORE target)
{
- return (netconf_onlytargetop(session_key, target, nc_rpc_unlock));
+ return (netconf_onlytargetop(session_key, target, nc_rpc_unlock));
}
-static json_object *netconf_generic(const char* session_key, const char* content, char** data)
+static json_object *
+netconf_generic(unsigned int session_key, const char *content, char **data)
{
- nc_rpc* rpc = NULL;
- json_object *res = NULL;
+ nc_rpc* rpc = NULL;
+ json_object *res = NULL;
- /* create requests */
- rpc = nc_rpc_generic(content);
- if (rpc == NULL) {
- ERROR("mod_netconf: creating rpc request failed");
- return create_error("Internal: Creating rpc request failed");
- }
+ /* create requests */
+ rpc = nc_rpc_generic(content);
+ if (rpc == NULL) {
+ ERROR("mod_netconf: creating rpc request failed");
+ return create_error_reply("Internal: Creating rpc request failed");
+ }
- if (data != NULL) {
- // TODO ?free(*data);
- (*data) = NULL;
- }
+ if (data != NULL) {
+ // TODO ?free(*data);
+ (*data) = NULL;
+ }
- /* get session where send the RPC */
- res = netconf_op(session_key, rpc, data);
- nc_rpc_free (rpc);
- return res;
+ /* get session where send the RPC */
+ res = netconf_op(session_key, rpc, data);
+ nc_rpc_free (rpc);
+ return res;
+}
+
+static void
+node_metadata_children(struct lys_node *node, json_object *parent)
+{
+ json_object *array, *array_item;
+ struct lys_node *child;
+
+ array = json_object_new_array();
+
+ LY_TREE_FOR(node->child, child) {
+ array_item = json_object_new_string(child->name);
+ json_object_array_add(array, array_item);
+ }
+
+ json_object_object_add(parent, "children", array);
+}
+
+static void
+node_metadata_container(struct lys_node_container *cont, json_object *parent)
+{
+ json_object *obj;
+
+ /* element type */
+ obj = json_object_new_string("container");
+ json_object_object_add(parent, "eltype", obj);
+
+ /* config */
+ if (cont->flags & LYS_CONFIG_R) {
+ obj = json_object_new_boolean(0);
+ } else {
+ obj = json_object_new_boolean(1);
+ }
+ json_object_object_add(parent, "config", obj);
+
+ /* TODO */
+ /* description */
+
+ /* if-feature */
+
+ /* must */
+
+ /* presence */
+
+ /* reference */
+
+ /* status */
+
+ /* typedef */
+
+ /* when */
+
+ /* children */
+ node_metadata_children((struct lys_node *)cont, parent);
+}
+
+static int
+node_add_metadata(struct lys_node *node, struct lys_module *module, json_object *parent)
+{
+ struct lys_module *cur_module;
+ json_object *meta_obj;
+ char *obj_name;
+
+ cur_module = node->module;
+ if (cur_module->type) {
+ cur_module = ((struct lys_submodule *)cur_module)->belongsto;
+ }
+ if (cur_module == module) {
+ asprintf(&obj_name, "$@%s", node->name);
+ } else {
+ asprintf(&obj_name, "$@%s:%s", cur_module->name, node->name);
+ }
+
+ /* in (leaf-)lists the metadata could have already been added */
+ if (json_object_object_get_ex(parent, obj_name, NULL) == TRUE) {
+ free(obj_name);
+ return 1;
+ }
+
+ meta_obj = json_object_new_object();
+
+ switch (node->nodetype) {
+ case LYS_CONTAINER:
+ node_metadata_container((struct lys_node_container *)node, meta_obj);
+ break;
+ /* TODO LYS_AUGMENT
+ LYS_CHOICE
+ LYS_LEAF
+ LYS_LEAFLIST
+ LYS_LIST
+ LYS_ANYXML
+ LYS_GROUPING
+ LYS_CASE
+ LYS_INPUT
+ LYS_OUTPUT
+ LYS_NOTIF
+ LYS_RPC
+ LYS_USES*/
+ }
+
+ /* just a precaution */
+ if (json_object_get_type(parent) != json_type_object) {
+ ERROR("Internal: wrong JSON type (%s:%d)", __FILE__, __LINE__);
+ free(obj_name);
+ return 1;
+ }
+
+ json_object_object_add(parent, obj_name, meta_obj);
+ free(obj_name);
+ return 0;
+}
+
+static void
+node_add_metadata_recursive(struct lyd_node *data_tree, struct lys_module *module, json_object *data_json_parent)
+{
+ struct lys_module *cur_module;
+ struct lys_node *list_schema;
+ struct lyd_node *child, *list_item;
+ json_object *child_json, *list_child_json;
+ char *child_name;
+ int list_idx;
+
+ /* add data_tree metadata */
+ if (node_add_metadata(data_tree->schema, module, data_json_parent)) {
+ return;
+ }
+
+ /* get data_tree module */
+ cur_module = data_tree->schema->module;
+ if (cur_module->type) {
+ cur_module = ((struct lys_submodule *)cur_module)->belongsto;
+ }
+
+ if (!(data_tree->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
+ /* print correct data_tree JSON name */
+ if (cur_module == module) {
+ asprintf(&child_name, "%s", data_tree->schema->name);
+ } else {
+ asprintf(&child_name, "%s:%s", cur_module->name, data_tree->schema->name);
+ }
+
+ /* go down in JSON object */
+ if (json_object_object_get_ex(data_json_parent, child_name, &child_json) == FALSE) {
+ ERROR("Internal: failed to get JSON object \"%s\".", child_name);
+ free(child_name);
+ return;
+ }
+ free(child_name);
+
+ if (data_tree->schema->nodetype == LYS_LIST) {
+ if (json_object_get_type(child_json) != json_type_array) {
+ ERROR("Internal: type mismatch (%s:%d)", __FILE__, __LINE__);
+ return;
+ }
+ /* go down in data tree for every item, we process them all now, skip later
+ * (metadata duplicate will be detected at the beginning of this function) */
+ list_idx = 0;
+ list_schema = data_tree->schema;
+
+ LY_TREE_FOR(data_tree, list_item) {
+ /* another list member */
+ if (list_item->schema == list_schema) {
+ list_child_json = json_object_array_get_idx(child_json, list_idx);
+ if (!list_child_json) {
+ ERROR("Internal: list \"%s\" idx out-of-bounds", list_schema->name);
+ return;
+ }
+ LY_TREE_FOR(list_item->child, child) {
+ node_add_metadata_recursive(child, cur_module, list_child_json);
+ }
+
+ ++list_idx;
+ }
+ }
+ } else {
+ if (json_object_get_type(child_json) != json_type_object) {
+ ERROR("Internal: type mismatch (%s:%d)", __FILE__, __LINE__);
+ return;
+ }
+ /* go down in data tree */
+ LY_TREE_FOR(data_tree->child, child) {
+ node_add_metadata_recursive(child, cur_module, child_json);
+ }
+ }
+ }
+}
+
+static void
+node_add_children_with_metadata_recursive(struct lys_node *node, struct lys_module *module, json_object *parent)
+{
+ struct lys_module *cur_module;
+ struct lys_node *child;
+ json_object *node_json;
+ char *json_name;
+
+ /* add node metadata */
+ if (node_add_metadata(node, module, parent)) {
+ ERROR("Internal: metadata duplicate for \"%s\".", node->name);
+ return;
+ }
+
+ /* get node module */
+ cur_module = node->module;
+ if (cur_module->type) {
+ cur_module = ((struct lys_submodule *)cur_module)->belongsto;
+ }
+
+ /* create JSON object for child metadata */
+ node_json = json_object_new_object();
+ if (cur_module == module) {
+ json_object_object_add(parent, node->name, node_json);
+ } else {
+ asprintf(&json_name, "%s:%s", cur_module->name, node->name);
+ json_object_object_add(parent, json_name, node_json);
+ free(json_name);
+ }
+
+ LY_TREE_FOR(node->child, child) {
+ node_add_children_with_metadata_recursive(child, cur_module, node_json);
+ }
+}
+
+static json_object *
+libyang_query(unsigned int session_key, const char *filter, int load_children)
+{
+ struct lys_node *node;
+ struct session_with_mutex *locked_session;
+ json_object *ret = NULL, *data;
+
+ locked_session = session_get_locked(session_key, &ret);
+ if (!locked_session) {
+ ERROR("Locking failed or session not found.");
+ goto finish;
+ }
+
+ locked_session->last_activity = time(NULL);
+
+ /* collect schema metadata and create reply */
+ node = ly_ctx_get_node(locked_session->ctx, filter);
+
+ if (node) {
+ pthread_mutex_lock(&json_lock);
+ data = json_object_new_object();
+
+ if (load_children) {
+ node_add_children_with_metadata_recursive(node, NULL, data);
+ } else {
+ node_add_metadata(node, NULL, data);
+ }
+
+ pthread_mutex_unlock(&json_lock);
+ ret = create_data_reply(json_object_to_json_string(data));
+ json_object_put(data);
+ } else {
+ ret = create_error_reply("Failed to resolve XPath filter node.");
+ }
+
+ session_unlock(locked_session);
+
+finish:
+ return ret;
+}
+
+static json_object *
+libyang_merge(unsigned int session_key, const char *config)
+{
+ struct lyd_node *data_tree = NULL, *sibling;
+ struct session_with_mutex *locked_session;
+ json_object *ret = NULL, *data_json = NULL;
+ enum json_tokener_error err = 0;
+
+ locked_session = session_get_locked(session_key, &ret);
+ if (!locked_session) {
+ ERROR("Locking failed or session not found.");
+ goto finish;
+ }
+
+ locked_session->last_activity = time(NULL);
+
+ data_tree = lyd_parse(locked_session->ctx, config, LYD_JSON, LYD_OPT_STRICT);
+ if (!data_tree) {
+ ERROR("Creating data tree failed.");
+ ret = create_error_reply("Failed to create data tree from JSON config.");
+ session_unlock(locked_session);
+ goto finish;
+ }
+
+ session_unlock(locked_session);
+
+ pthread_mutex_lock(&json_lock);
+ data_json = json_tokener_parse_verbose(config, &err);
+ if (!data_json) {
+ ERROR("Parsing JSON config failed (%s).", json_tokener_error_desc(err));
+ pthread_mutex_unlock(&json_lock);
+ ret = create_error_reply(json_tokener_error_desc(err));
+ goto finish;
+ }
+
+ /* go simultaneously through both trees and add metadata */
+ LY_TREE_FOR(data_tree, sibling) {
+ node_add_metadata_recursive(sibling, NULL, data_json);
+ }
+ pthread_mutex_unlock(&json_lock);
+ ret = create_data_reply(json_object_to_json_string(data_json));
+
+finish:
+ LY_TREE_FOR(data_tree, sibling) {
+ lyd_free(sibling);
+ }
+ json_object_put(data_json);
+ return ret;
}
/**
* @}
*//* netconf_operations */
-void clb_print(NC_VERB_LEVEL level, const char* msg)
+void
+clb_print(NC_VERB_LEVEL level, const char *msg)
{
#define FOREACH(I) \
I(NC_VERB_ERROR) I(NC_VERB_WARNING)
#define CASE(VAL) case VAL: ERROR("%s: %s", #VAL, msg); \
- break;
+ break;
- switch (level) {
- FOREACH(CASE);
- case NC_VERB_VERBOSE:
- case NC_VERB_DEBUG:
- DEBUG("DEBUG: %s", msg);
- break;
- }
- if (level == NC_VERB_ERROR) {
- /* return global error */
- netconf_callback_error_process(NULL /* tag */, NULL /* type */,
- NULL /* severity */, NULL /* apptag */,
- NULL /* path */, msg, NULL /* attribute */,
- NULL /* element */, NULL /* ns */, NULL /* sid */);
- }
+ switch (level) {
+ FOREACH(CASE);
+ case NC_VERB_VERBOSE:
+ case NC_VERB_DEBUG:
+ DEBUG("DEBUG: %s", msg);
+ break;
+ }
+ if (level == NC_VERB_ERROR) {
+ /* return global error */
+ netconf_callback_error_process(NULL /* tag */, NULL /* type */,
+ NULL /* severity */, NULL /* apptag */,
+ NULL /* path */, msg, NULL /* attribute */,
+ NULL /* element */, NULL /* ns */, NULL /* sid */);
+ }
}
/**
* Receive message from client over UNIX socket and return pointer to it.
* Caller should free message memory.
- * \param[in] client socket descriptor of client
+ * \param[in] client socket descriptor of client
* \return pointer to message
*/
-char *get_framed_message(int client)
+char *
+get_framed_message(int client)
{
- /* read json in chunked framing */
- unsigned int buffer_size = 0;
- ssize_t buffer_len = 0;
- char *buffer = NULL;
- char c;
- ssize_t ret;
- int i, chunk_len;
- char chunk_len_str[12];
+ /* read json in chunked framing */
+ unsigned int buffer_size = 0;
+ ssize_t buffer_len = 0;
+ char *buffer = NULL;
+ char c;
+ ssize_t ret;
+ int i, chunk_len;
+ char chunk_len_str[12];
- while (1) {
- /* read chunk length */
- if ((ret = recv (client, &c, 1, 0)) != 1 || c != '\n') {
- if (buffer != NULL) {
- free (buffer);
- buffer = NULL;
- }
- break;
- }
- if ((ret = recv (client, &c, 1, 0)) != 1 || c != '#') {
- if (buffer != NULL) {
- free (buffer);
- buffer = NULL;
- }
- break;
- }
- i=0;
- memset (chunk_len_str, 0, 12);
- while ((ret = recv (client, &c, 1, 0) == 1 && (isdigit(c) || c == '#'))) {
- if (i==0 && c == '#') {
- if (recv (client, &c, 1, 0) != 1 || c != '\n') {
- /* end but invalid */
- if (buffer != NULL) {
- free (buffer);
- buffer = NULL;
- }
- }
- /* end of message, double-loop break */
- goto msg_complete;
- }
- chunk_len_str[i++] = c;
- if (i==11) {
- ERROR("Message is too long, buffer for length is not big enought!!!!");
- break;
- }
- }
- if (c != '\n') {
- if (buffer != NULL) {
- free (buffer);
- buffer = NULL;
- }
- break;
- }
- chunk_len_str[i] = 0;
- if ((chunk_len = atoi (chunk_len_str)) == 0) {
- if (buffer != NULL) {
- free (buffer);
- buffer = NULL;
- }
- break;
- }
- buffer_size += chunk_len+1;
- buffer = realloc (buffer, sizeof(char)*buffer_size);
- memset(buffer + (buffer_size-chunk_len-1), 0, chunk_len+1);
- if ((ret = recv (client, buffer+buffer_len, chunk_len, 0)) == -1 || ret != chunk_len) {
- if (buffer != NULL) {
- free (buffer);
- buffer = NULL;
- }
- break;
- }
- buffer_len += ret;
- }
+ while (1) {
+ /* read chunk length */
+ if ((ret = recv (client, &c, 1, 0)) != 1 || c != '\n') {
+ if (buffer != NULL) {
+ free (buffer);
+ buffer = NULL;
+ }
+ break;
+ }
+ if ((ret = recv (client, &c, 1, 0)) != 1 || c != '#') {
+ if (buffer != NULL) {
+ free (buffer);
+ buffer = NULL;
+ }
+ break;
+ }
+ i=0;
+ memset (chunk_len_str, 0, 12);
+ while ((ret = recv (client, &c, 1, 0) == 1 && (isdigit(c) || c == '#'))) {
+ if (i==0 && c == '#') {
+ if (recv (client, &c, 1, 0) != 1 || c != '\n') {
+ /* end but invalid */
+ if (buffer != NULL) {
+ free (buffer);
+ buffer = NULL;
+ }
+ }
+ /* end of message, double-loop break */
+ goto msg_complete;
+ }
+ chunk_len_str[i++] = c;
+ if (i==11) {
+ ERROR("Message is too long, buffer for length is not big enought!!!!");
+ break;
+ }
+ }
+ if (c != '\n') {
+ if (buffer != NULL) {
+ free (buffer);
+ buffer = NULL;
+ }
+ break;
+ }
+ chunk_len_str[i] = 0;
+ if ((chunk_len = atoi (chunk_len_str)) == 0) {
+ if (buffer != NULL) {
+ free (buffer);
+ buffer = NULL;
+ }
+ break;
+ }
+ buffer_size += chunk_len+1;
+ buffer = realloc (buffer, sizeof(char)*buffer_size);
+ memset(buffer + (buffer_size-chunk_len-1), 0, chunk_len+1);
+ if ((ret = recv (client, buffer+buffer_len, chunk_len, 0)) == -1 || ret != chunk_len) {
+ if (buffer != NULL) {
+ free (buffer);
+ buffer = NULL;
+ }
+ break;
+ }
+ buffer_len += ret;
+ }
msg_complete:
- return buffer;
+ return buffer;
}
-NC_DATASTORE parse_datastore(const char *ds)
+NC_DATASTORE
+parse_datastore(const char *ds)
{
- if (strcmp(ds, "running") == 0) {
- return NC_DATASTORE_RUNNING;
- } else if (strcmp(ds, "startup") == 0) {
- return NC_DATASTORE_STARTUP;
- } else if (strcmp(ds, "candidate") == 0) {
- return NC_DATASTORE_CANDIDATE;
- } else if (strcmp(ds, "url") == 0) {
- return NC_DATASTORE_URL;
- } else if (strcmp(ds, "config") == 0) {
- return NC_DATASTORE_CONFIG;
- }
- return -1;
+ if (strcmp(ds, "running") == 0) {
+ return NC_DATASTORE_RUNNING;
+ } else if (strcmp(ds, "startup") == 0) {
+ return NC_DATASTORE_STARTUP;
+ } else if (strcmp(ds, "candidate") == 0) {
+ return NC_DATASTORE_CANDIDATE;
+ } else if (strcmp(ds, "url") == 0) {
+ return NC_DATASTORE_URL;
+ } else if (strcmp(ds, "config") == 0) {
+ return NC_DATASTORE_CONFIG;
+ }
+ return -1;
}
-NC_EDIT_TESTOPT_TYPE parse_testopt(const char *t)
+NC_EDIT_TESTOPT_TYPE
+parse_testopt(const char *t)
{
- if (strcmp(t, "notset") == 0) {
- return NC_EDIT_TESTOPT_NOTSET;
- } else if (strcmp(t, "testset") == 0) {
- return NC_EDIT_TESTOPT_TESTSET;
- } else if (strcmp(t, "set") == 0) {
- return NC_EDIT_TESTOPT_SET;
- } else if (strcmp(t, "test") == 0) {
- return NC_EDIT_TESTOPT_TEST;
- }
- return NC_EDIT_TESTOPT_ERROR;
+ if (strcmp(t, "notset") == 0) {
+ return NC_EDIT_TESTOPT_NOTSET;
+ } else if (strcmp(t, "testset") == 0) {
+ return NC_EDIT_TESTOPT_TESTSET;
+ } else if (strcmp(t, "set") == 0) {
+ return NC_EDIT_TESTOPT_SET;
+ } else if (strcmp(t, "test") == 0) {
+ return NC_EDIT_TESTOPT_TEST;
+ }
+ return NC_EDIT_TESTOPT_ERROR;
}
-json_object *create_error(const char *errmess)
+json_object *
+create_error_reply(const char *errmess)
{
- pthread_mutex_lock(&json_lock);
- json_object *reply = json_object_new_object();
- json_object *array = json_object_new_array();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
- json_object_array_add(array, json_object_new_string(errmess));
- json_object_object_add(reply, "errors", array);
- pthread_mutex_unlock(&json_lock);
- return reply;
+ json_object *reply, *array;
+ pthread_mutex_lock(&json_lock);
+ reply = json_object_new_object();
+ array = json_object_new_array();
+ json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
+ json_object_array_add(array, json_object_new_string(errmess));
+ json_object_object_add(reply, "errors", array);
+ pthread_mutex_unlock(&json_lock);
+
+ return reply;
}
-json_object *create_data(const char *data)
+json_object *
+create_data_reply(const char *data)
{
- pthread_mutex_lock(&json_lock);
- json_object *reply = json_object_new_object();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
- json_object_object_add(reply, "data", json_object_new_string(data));
- pthread_mutex_unlock(&json_lock);
- return reply;
+ pthread_mutex_lock(&json_lock);
+ json_object *reply = json_object_new_object();
+ json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
+ json_object_object_add(reply, "data", json_object_new_string(data));
+ pthread_mutex_unlock(&json_lock);
+ return reply;
}
-json_object *create_ok()
+json_object *
+create_ok_reply(void)
{
- pthread_mutex_lock(&json_lock);
- json_object *reply = json_object_new_object();
- reply = json_object_new_object();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
- pthread_mutex_unlock(&json_lock);
- return reply;
+ pthread_mutex_lock(&json_lock);
+ json_object *reply = json_object_new_object();
+ reply = json_object_new_object();
+ json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+ pthread_mutex_unlock(&json_lock);
+ return reply;
}
-char *get_param_string(json_object *data, const char *name)
+json_object *
+create_replies(void)
{
- json_object *js_tmp = NULL;
- char *res = NULL;
- if (json_object_object_get_ex(data, name, &js_tmp) == TRUE) {
- res = strdup(json_object_get_string(js_tmp));
- json_object_put(js_tmp);
- }
- return res;
+ json_object *replies;
+
+ pthread_mutex_lock(&json_lock);
+ replies = json_object_new_object();
+ pthread_mutex_unlock(&json_lock);
+
+ return replies;
}
-json_object *handle_op_connect(json_object *request)
+void
+add_reply(json_object *replies, json_object *reply, unsigned int session_key)
{
- char *host = NULL;
- char *port = NULL;
- char *user = NULL;
- char *pass = NULL;
- json_object *capabilities = NULL;
- json_object *reply = NULL;
- const char *session_id = NULL;
- struct nc_cpblts* cpblts = NULL;
- unsigned int len, i;
+ char *str;
- DEBUG("Request: Connect");
- pthread_mutex_lock(&json_lock);
+ asprintf(&str, "%u", session_key);
- host = get_param_string(request, "host");
- port = get_param_string(request, "port");
- user = get_param_string(request, "user");
- pass = get_param_string(request, "pass");
+ pthread_mutex_lock(&json_lock);
+ json_object_object_add(replies, str, reply);
+ pthread_mutex_unlock(&json_lock);
- if (json_object_object_get_ex(request, "capabilities", &capabilities) == TRUE) {
- if ((capabilities != NULL) && ((len = json_object_array_length(capabilities)) > 0)) {
- cpblts = nc_cpblts_new(NULL);
- for (i=0; i<len; i++) {
- nc_cpblts_add(cpblts, json_object_get_string(json_object_array_get_idx(capabilities, i)));
- }
- } else {
- ERROR("no capabilities specified");
- }
- json_object_put(capabilities);
- }
-
- pthread_mutex_unlock(&json_lock);
-
- DEBUG("host: %s, port: %s, user: %s", host, port, user);
- if ((host == NULL) || (user == NULL)) {
- ERROR("Cannot connect - insufficient input.");
- session_id = NULL;
- } else {
- session_id = netconf_connect(host, port, user, pass, cpblts);
- DEBUG("SID: %s", session_id);
- }
- if (cpblts != NULL) {
- nc_cpblts_free(cpblts);
- }
-
- GETSPEC_ERR_REPLY
-
- pthread_mutex_lock(&json_lock);
- if (session_id == NULL) {
- /* negative reply */
- if (err_reply == NULL) {
- reply = json_object_new_object();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
- json_object_object_add(reply, "error-message", json_object_new_string("Connecting NETCONF server failed."));
- ERROR("Connection failed.");
- } else {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- ERROR("Connect - error from libnetconf's callback.");
- }
- } else {
- /* positive reply */
- reply = json_object_new_object();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
- json_object_object_add(reply, "session", json_object_new_string(session_id));
- }
- memset(pass, 0, strlen(pass));
- pthread_mutex_unlock(&json_lock);
- CHECK_AND_FREE(host);
- CHECK_AND_FREE(user);
- CHECK_AND_FREE(port);
- CHECK_AND_FREE(pass);
- return reply;
+ free(str);
}
-json_object *handle_op_get(json_object *request, const char *session_id)
+char *
+get_param_string(json_object *data, const char *name)
{
- char *filter = NULL;
- char *data = NULL;
- json_object *reply = NULL;
-
- DEBUG("Request: get (session %s)", session_id);
-
- pthread_mutex_lock(&json_lock);
- filter = get_param_string(request, "filter");
- pthread_mutex_unlock(&json_lock);
-
- if ((data = netconf_get(session_id, filter, &reply)) == NULL) {
- CHECK_ERR_SET_REPLY_ERR("Get information failed.")
- } else {
- reply = create_data(data);
- free(data);
- }
- return reply;
+ json_object *js_tmp = NULL;
+ char *res = NULL;
+ if (json_object_object_get_ex(data, name, &js_tmp) == TRUE) {
+ res = strdup(json_object_get_string(js_tmp));
+ }
+ return res;
}
-json_object *handle_op_getconfig(json_object *request, const char *session_id)
+json_object *
+handle_op_connect(json_object *request)
{
- NC_DATASTORE ds_type_s = -1;
- char *filter = NULL;
- char *data = NULL;
- char *source = NULL;
- json_object *reply = NULL;
+ char *host = NULL;
+ char *port = NULL;
+ char *user = NULL;
+ char *pass = NULL;
+ json_object *reply = NULL;
+ unsigned int session_key = 0;
+ struct nc_cpblts* cpblts = NULL;
- DEBUG("Request: get-config (session %s)", session_id);
+ DEBUG("Request: connect");
+ pthread_mutex_lock(&json_lock);
- pthread_mutex_lock(&json_lock);
- filter = get_param_string(request, "filter");
+ host = get_param_string(request, "host");
+ port = get_param_string(request, "port");
+ user = get_param_string(request, "user");
+ pass = get_param_string(request, "pass");
- source = get_param_string(request, "source");
- if (source != NULL) {
- ds_type_s = parse_datastore(source);
- }
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_unlock(&json_lock);
- if ((int)ds_type_s == -1) {
- reply = create_error("Invalid source repository type requested.");
- goto finalize;
- }
+ DEBUG("host: %s, port: %s, user: %s", host, port, user);
+ if ((host == NULL) || (user == NULL)) {
+ ERROR("Cannot connect - insufficient input.");
+ session_key = 0;
+ } else {
+ session_key = netconf_connect(host, port, user, pass, cpblts);
+ DEBUG("Session key: %u", session_key);
+ }
+ if (cpblts != NULL) {
+ nc_cpblts_free(cpblts);
+ }
- if ((data = netconf_getconfig(session_id, ds_type_s, filter, &reply)) == NULL) {
- CHECK_ERR_SET_REPLY_ERR("Get configuration operation failed.")
- } else {
- reply = create_data(data);
- free(data);
- }
-finalize:
- CHECK_AND_FREE(filter);
- CHECK_AND_FREE(source);
- return reply;
+ GETSPEC_ERR_REPLY
+
+ pthread_mutex_lock(&json_lock);
+ if (session_key == 0) {
+ /* negative reply */
+ if (err_reply == NULL) {
+ reply = json_object_new_object();
+ json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
+ json_object_object_add(reply, "error-message", json_object_new_string("Connecting NETCONF server failed."));
+ ERROR("Connection failed.");
+ } else {
+ /* use filled err_reply from libnetconf's callback */
+ reply = err_reply;
+ ERROR("Connect - error from libnetconf's callback.");
+ }
+ } else {
+ /* positive reply */
+ reply = json_object_new_object();
+ json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+ json_object_object_add(reply, "session", json_object_new_int(session_key));
+ }
+ memset(pass, 0, strlen(pass));
+ pthread_mutex_unlock(&json_lock);
+ CHECK_AND_FREE(host);
+ CHECK_AND_FREE(user);
+ CHECK_AND_FREE(port);
+ CHECK_AND_FREE(pass);
+ return reply;
}
-json_object *handle_op_getschema(json_object *request, const char *session_id)
+json_object *
+handle_op_disconnect(json_object *UNUSED(request), unsigned int session_key)
{
- char *data = NULL;
- char *identifier = NULL;
- char *version = NULL;
- char *format = NULL;
- json_object *reply = NULL;
+ json_object *reply;
- DEBUG("Request: get-schema (session %s)", session_id);
- pthread_mutex_lock(&json_lock);
- identifier = get_param_string(request, "identifier");
- version = get_param_string(request, "version");
- format = get_param_string(request, "format");
- pthread_mutex_unlock(&json_lock);
+ DEBUG("Request: disconnect (session %u)", session_key);
- if (identifier == NULL) {
- reply = create_error("No identifier for get-schema supplied.");
- goto finalize;
- }
+ if (netconf_close(session_key, &reply) != EXIT_SUCCESS) {
+ CHECK_ERR_SET_REPLY_ERR("Get configuration information from device failed.")
+ } else {
+ reply = create_ok_reply();
+ }
- DEBUG("get-schema(version: %s, format: %s)", version, format);
- if ((data = netconf_getschema(session_id, identifier, version, format, &reply)) == NULL) {
- CHECK_ERR_SET_REPLY_ERR("Get models operation failed.")
- } else {
- reply = create_data(data);
- free(data);
- }
-finalize:
- CHECK_AND_FREE(identifier);
- CHECK_AND_FREE(version);
- CHECK_AND_FREE(format);
- return reply;
+ return reply;
}
-json_object *handle_op_editconfig(json_object *request, const char *session_id)
+json_object *
+handle_op_get(json_object *request, unsigned int session_key)
{
- NC_DATASTORE ds_type_s = -1;
- NC_DATASTORE ds_type_t = -1;
- NC_EDIT_DEFOP_TYPE defop_type = NC_EDIT_DEFOP_NOTSET;
- NC_EDIT_ERROPT_TYPE erropt_type = 0;
- NC_EDIT_TESTOPT_TYPE testopt_type = NC_EDIT_TESTOPT_TESTSET;
- char *defop = NULL;
- char *erropt = NULL;
- char *config = NULL;
- char *source = NULL;
- char *target = NULL;
- char *testopt = NULL;
- json_object *reply = NULL;
+ char *filter = NULL;
+ char *data = NULL;
+ json_object *reply = NULL, *obj;
+ int strict;
- DEBUG("Request: edit-config (session %s)", session_id);
+ DEBUG("Request: get (session %u)", session_key);
- pthread_mutex_lock(&json_lock);
- /* get parameters */
- defop = get_param_string(request, "default-operation");
- erropt = get_param_string(request, "error-option");
- target = get_param_string(request, "target");
- source = get_param_string(request, "source");
- config = get_param_string(request, "config");
- testopt = get_param_string(request, "test-option");
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_lock(&json_lock);
+ filter = get_param_string(request, "filter");
+ if (json_object_object_get_ex(request, "strict", &obj) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing strict parameter.");
+ return reply;
+ }
+ strict = json_object_get_boolean(obj);
+ pthread_mutex_unlock(&json_lock);
- if (target != NULL) {
- ds_type_t = parse_datastore(target);
- }
- if (source != NULL) {
- ds_type_s = parse_datastore(source);
- } else {
- /* source is optional, default value is config */
- ds_type_s = NC_DATASTORE_CONFIG;
- }
+ if ((data = netconf_get(session_key, filter, strict, &reply)) == NULL) {
+ CHECK_ERR_SET_REPLY_ERR("Get information failed.")
+ } else {
+ reply = create_data_reply(data);
+ free(data);
+ }
- if (defop != NULL) {
- if (strcmp(defop, "merge") == 0) {
- defop_type = NC_EDIT_DEFOP_MERGE;
- } else if (strcmp(defop, "replace") == 0) {
- defop_type = NC_EDIT_DEFOP_REPLACE;
- } else if (strcmp(defop, "none") == 0) {
- defop_type = NC_EDIT_DEFOP_NONE;
- } else {
- reply = create_error("Invalid default-operation parameter.");
- goto finalize;
- }
- } else {
- defop_type = NC_EDIT_DEFOP_NOTSET;
- }
-
- if (erropt != NULL) {
- if (strcmp(erropt, "continue-on-error") == 0) {
- erropt_type = NC_EDIT_ERROPT_CONT;
- } else if (strcmp(erropt, "stop-on-error") == 0) {
- erropt_type = NC_EDIT_ERROPT_STOP;
- } else if (strcmp(erropt, "rollback-on-error") == 0) {
- erropt_type = NC_EDIT_ERROPT_ROLLBACK;
- } else {
- reply = create_error("Invalid error-option parameter.");
- goto finalize;
- }
- } else {
- erropt_type = 0;
- }
-
- if ((int)ds_type_t == -1) {
- reply = create_error("Invalid target repository type requested.");
- goto finalize;
- }
- if (ds_type_s == NC_DATASTORE_CONFIG) {
- if (config == NULL) {
- reply = create_error("Invalid config data parameter.");
- goto finalize;
- }
- } else if (ds_type_s == NC_DATASTORE_URL){
- if (config == NULL) {
- config = "";
- }
- }
-
- if (testopt != NULL) {
- testopt_type = parse_testopt(testopt);
- } else {
- testopt_type = NC_EDIT_TESTOPT_TESTSET;
- }
-
- reply = netconf_editconfig(session_id, ds_type_s, ds_type_t, defop_type, erropt_type, testopt_type, config);
-
- CHECK_ERR_SET_REPLY
-finalize:
- CHECK_AND_FREE(defop);
- CHECK_AND_FREE(erropt);
- CHECK_AND_FREE(config);
- CHECK_AND_FREE(source);
- CHECK_AND_FREE(target);
- CHECK_AND_FREE(testopt);
- return reply;
+ return reply;
}
-json_object *handle_op_copyconfig(json_object *request, const char *session_id)
+json_object *
+handle_op_getconfig(json_object *request, unsigned int session_key)
{
- NC_DATASTORE ds_type_s = -1;
- NC_DATASTORE ds_type_t = -1;
- char *config = NULL;
- char *target = NULL;
- char *source = NULL;
- char *uri_src = NULL;
- char *uri_trg = NULL;
+ NC_DATASTORE ds_type_s = -1;
+ char *filter = NULL;
+ char *data = NULL;
+ char *source = NULL;
+ json_object *reply = NULL, *obj;
+ int strict;
- json_object *reply = NULL;
+ DEBUG("Request: get-config (session %u)", session_key);
- DEBUG("Request: copy-config (session %s)", session_id);
+ pthread_mutex_lock(&json_lock);
+ filter = get_param_string(request, "filter");
+ source = get_param_string(request, "source");
+ if (source != NULL) {
+ ds_type_s = parse_datastore(source);
+ }
+ if (json_object_object_get_ex(request, "strict", &obj) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing strict parameter.");
+ return reply;
+ }
+ strict = json_object_get_boolean(obj);
+ pthread_mutex_unlock(&json_lock);
- /* get parameters */
- pthread_mutex_lock(&json_lock);
- target = get_param_string(request, "target");
- source = get_param_string(request, "source");
- config = get_param_string(request, "config");
- uri_src = get_param_string(request, "uri-source");
- uri_trg = get_param_string(request, "uri-target");
- pthread_mutex_unlock(&json_lock);
+ if ((int)ds_type_s == -1) {
+ reply = create_error_reply("Invalid source repository type requested.");
+ goto finalize;
+ }
- if (target != NULL) {
- ds_type_t = parse_datastore(target);
- }
- if (source != NULL) {
- ds_type_s = parse_datastore(source);
- } else {
- /* source == NULL *//* no explicit source specified -> use config data */
- ds_type_s = NC_DATASTORE_CONFIG;
- }
- if ((int)ds_type_s == -1) {
- /* source datastore specified, but it is invalid */
- reply = create_error("Invalid source repository type requested.");
- goto finalize;
- }
-
- if ((int)ds_type_t == -1) {
- /* invalid target datastore specified */
- reply = create_error("Invalid target repository type requested.");
- goto finalize;
- }
-
- /* source can be missing when config is given */
- if (source == NULL && config == NULL) {
- reply = create_error("invalid input parameters - source and config is required.");
- goto finalize;
- }
-
- if (ds_type_s == NC_DATASTORE_URL) {
- if (uri_src == NULL) {
- uri_src = "";
- }
- }
- if (ds_type_t == NC_DATASTORE_URL) {
- if (uri_trg == NULL) {
- uri_trg = "";
- }
- }
- reply = netconf_copyconfig(session_id, ds_type_s, ds_type_t, config, uri_src, uri_trg);
-
- CHECK_ERR_SET_REPLY
+ if ((data = netconf_getconfig(session_key, ds_type_s, filter, strict, &reply)) == NULL) {
+ CHECK_ERR_SET_REPLY_ERR("Get configuration operation failed.")
+ } else {
+ reply = create_data_reply(data);
+ free(data);
+ }
finalize:
- CHECK_AND_FREE(config);
- CHECK_AND_FREE(target);
- CHECK_AND_FREE(source);
- CHECK_AND_FREE(uri_src);
- CHECK_AND_FREE(uri_trg);
-
- return reply;
+ CHECK_AND_FREE(filter);
+ CHECK_AND_FREE(source);
+ return reply;
}
-json_object *handle_op_generic(json_object *request, const char *session_id)
+json_object *
+handle_op_editconfig(json_object *request, unsigned int session_key, int idx)
{
- json_object *reply = NULL;
- char *config = NULL;
- char *data = NULL;
+ NC_DATASTORE ds_type_s = -1;
+ NC_DATASTORE ds_type_t = -1;
+ NC_EDIT_DEFOP_TYPE defop_type = NC_EDIT_DEFOP_NOTSET;
+ NC_EDIT_ERROPT_TYPE erropt_type = 0;
+ NC_EDIT_TESTOPT_TYPE testopt_type = NC_EDIT_TESTOPT_TESTSET;
+ char *defop = NULL;
+ char *erropt = NULL;
+ char *config = NULL;
+ char *source = NULL;
+ char *target = NULL;
+ char *testopt = NULL;
+ char *urisource = NULL;
+ json_object *reply = NULL, *configs, *obj;
- DEBUG("Request: generic request for session %s", session_id);
+ DEBUG("Request: edit-config (session %u)", session_key);
- pthread_mutex_lock(&json_lock);
- config = get_param_string(request, "content");
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_lock(&json_lock);
+ /* get parameters */
+ target = get_param_string(request, "target");
+ if (json_object_object_get_ex(request, "configs", &configs) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing configs parameter.");
+ goto finalize;
+ }
+ obj = json_object_array_get_idx(configs, idx);
+ config = strdup(json_object_get_string(obj));
- reply = netconf_generic(session_id, config, &data);
- if (reply == NULL) {
- GETSPEC_ERR_REPLY
- if (err_reply != NULL) {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- } else {
- if (data == NULL) {
- pthread_mutex_lock(&json_lock);
- reply = json_object_new_object();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
- pthread_mutex_unlock(&json_lock);
- } else {
- reply = create_data(data);
- free(data);
- }
- }
- CHECK_AND_FREE(config);
- return reply;
-}
+ source = get_param_string(request, "source");
+ defop = get_param_string(request, "default-operation");
+ erropt = get_param_string(request, "error-option");
+ urisource = get_param_string(request, "uri-source");
+ testopt = get_param_string(request, "test-option");
+ pthread_mutex_unlock(&json_lock);
-json_object *handle_op_disconnect(json_object *UNUSED(request), const char *session_id)
-{
- json_object *reply = NULL;
- DEBUG("Request: Disconnect session %s", session_id);
+ if (target != NULL) {
+ ds_type_t = parse_datastore(target);
+ }
+ if (source != NULL) {
+ ds_type_s = parse_datastore(source);
+ } else {
+ /* source is optional, default value is config */
+ ds_type_s = NC_DATASTORE_CONFIG;
+ }
- if (netconf_close(session_id, &reply) != EXIT_SUCCESS) {
- CHECK_ERR_SET_REPLY_ERR("Get configuration information from device failed.")
- } else {
- reply = create_ok();
- }
- return reply;
-}
+ if (defop != NULL) {
+ if (strcmp(defop, "merge") == 0) {
+ defop_type = NC_EDIT_DEFOP_MERGE;
+ } else if (strcmp(defop, "replace") == 0) {
+ defop_type = NC_EDIT_DEFOP_REPLACE;
+ } else if (strcmp(defop, "none") == 0) {
+ defop_type = NC_EDIT_DEFOP_NONE;
+ } else {
+ reply = create_error_reply("Invalid default-operation parameter.");
+ goto finalize;
+ }
+ } else {
+ defop_type = NC_EDIT_DEFOP_NOTSET;
+ }
-json_object *handle_op_kill(json_object *request, const char *session_id)
-{
- json_object *reply = NULL;
- char *sid = NULL;
+ if (erropt != NULL) {
+ if (strcmp(erropt, "continue-on-error") == 0) {
+ erropt_type = NC_EDIT_ERROPT_CONT;
+ } else if (strcmp(erropt, "stop-on-error") == 0) {
+ erropt_type = NC_EDIT_ERROPT_STOP;
+ } else if (strcmp(erropt, "rollback-on-error") == 0) {
+ erropt_type = NC_EDIT_ERROPT_ROLLBACK;
+ } else {
+ reply = create_error_reply("Invalid error-option parameter.");
+ goto finalize;
+ }
+ } else {
+ erropt_type = 0;
+ }
- DEBUG("Request: kill-session, session %s", session_id);
+ if ((int)ds_type_t == -1) {
+ reply = create_error_reply("Invalid target repository type requested.");
+ goto finalize;
+ }
+ if (ds_type_s == NC_DATASTORE_CONFIG) {
+ if (config == NULL) {
+ reply = create_error_reply("Invalid config data parameter.");
+ goto finalize;
+ }
+ } else if (ds_type_s == NC_DATASTORE_URL){
+ if (urisource == NULL) {
+ reply = create_error_reply("Invalid uri-source parameter.");
+ goto finalize;
+ }
+ config = urisource;
+ }
- pthread_mutex_lock(&json_lock);
- sid = get_param_string(request, "session-id");
- pthread_mutex_unlock(&json_lock);
+ if (testopt != NULL) {
+ testopt_type = parse_testopt(testopt);
+ } else {
+ testopt_type = NC_EDIT_TESTOPT_TESTSET;
+ }
- if (sid == NULL) {
- reply = create_error("Missing session-id parameter.");
- goto finalize;
- }
+ reply = netconf_editconfig(session_key, ds_type_s, ds_type_t, defop_type, erropt_type, testopt_type, config);
- reply = netconf_killsession(session_id, sid);
-
- CHECK_ERR_SET_REPLY
+ CHECK_ERR_SET_REPLY
finalize:
- CHECK_AND_FREE(sid);
- return reply;
+ CHECK_AND_FREE(defop);
+ CHECK_AND_FREE(erropt);
+ CHECK_AND_FREE(config);
+ CHECK_AND_FREE(source);
+ CHECK_AND_FREE(urisource);
+ CHECK_AND_FREE(target);
+ CHECK_AND_FREE(testopt);
+
+ return reply;
}
-json_object *handle_op_reloadhello(json_object *UNUSED(request), const char *session_id)
+json_object *
+handle_op_copyconfig(json_object *request, unsigned int session_key, int idx)
{
- struct nc_session *temp_session = NULL;
- struct session_with_mutex * locked_session = NULL;
- json_object *reply = NULL;
- DEBUG("Request: get info about session %s", session_id);
+ NC_DATASTORE ds_type_s = -1;
+ NC_DATASTORE ds_type_t = -1;
+ char *config = NULL;
+ char *target = NULL;
+ char *source = NULL;
+ char *uri_src = NULL;
+ char *uri_trg = NULL;
+ json_object *reply = NULL, *configs, *obj;
- DEBUG("LOCK wrlock %s", __func__);
- if (pthread_rwlock_wrlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- return NULL;
- }
+ DEBUG("Request: copy-config (session %u)", session_key);
- for (locked_session = netconf_sessions_list;
- locked_session && strcmp(nc_session_get_id(locked_session->session), session_id);
+ /* get parameters */
+ pthread_mutex_lock(&json_lock);
+ target = get_param_string(request, "target");
+ source = get_param_string(request, "source");
+ uri_src = get_param_string(request, "uri-source");
+ uri_trg = get_param_string(request, "uri-target");
+ if (!strcmp(source, "config")) {
+ if (json_object_object_get_ex(request, "configs", &configs) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing configs parameter.");
+ goto finalize;
+ }
+ obj = json_object_array_get_idx(configs, idx);
+ if (!obj) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Configs array parameter shorter than sessions.");
+ goto finalize;
+ }
+ config = strdup(json_object_get_string(obj));
+ }
+ pthread_mutex_unlock(&json_lock);
+
+ if (target != NULL) {
+ ds_type_t = parse_datastore(target);
+ }
+ if (source != NULL) {
+ ds_type_s = parse_datastore(source);
+ }
+
+ if ((int)ds_type_s == -1) {
+ /* invalid source datastore specified */
+ reply = create_error_reply("Invalid source repository type requested.");
+ goto finalize;
+ }
+
+ if ((int)ds_type_t == -1) {
+ /* invalid target datastore specified */
+ reply = create_error_reply("Invalid target repository type requested.");
+ goto finalize;
+ }
+
+ if (ds_type_s == NC_DATASTORE_URL) {
+ if (uri_src == NULL) {
+ uri_src = "";
+ }
+ }
+ if (ds_type_t == NC_DATASTORE_URL) {
+ if (uri_trg == NULL) {
+ uri_trg = "";
+ }
+ }
+ reply = netconf_copyconfig(session_key, ds_type_s, ds_type_t, config, uri_src, uri_trg);
+
+ CHECK_ERR_SET_REPLY
+
+finalize:
+ CHECK_AND_FREE(config);
+ CHECK_AND_FREE(target);
+ CHECK_AND_FREE(source);
+ CHECK_AND_FREE(uri_src);
+ CHECK_AND_FREE(uri_trg);
+
+ return reply;
+}
+
+json_object *
+handle_op_deleteconfig(json_object *request, unsigned int session_key)
+{
+ json_object *reply;
+ NC_DATASTORE ds_type = -1;
+ char *target, *url;
+
+ DEBUG("Request: delete-config (session %u)", session_key);
+
+ pthread_mutex_lock(&json_lock);
+ target = get_param_string(request, "target");
+ url = get_param_string(request, "url");
+ pthread_mutex_unlock(&json_lock);
+
+ if (target != NULL) {
+ ds_type = parse_datastore(target);
+ }
+ if ((int)ds_type == -1) {
+ reply = create_error_reply("Invalid target repository type requested.");
+ goto finalize;
+ }
+ if (ds_type == NC_DATASTORE_URL) {
+ if (!url) {
+ url = "";
+ }
+ }
+
+ reply = netconf_deleteconfig(session_key, ds_type, url);
+
+ CHECK_ERR_SET_REPLY
+ if (reply == NULL) {
+ reply = create_ok_reply();
+ }
+
+finalize:
+ CHECK_AND_FREE(target);
+ CHECK_AND_FREE(url);
+ return reply;
+}
+
+json_object *
+handle_op_lock(json_object *request, unsigned int session_key)
+{
+ json_object *reply;
+ NC_DATASTORE ds_type = -1;
+ char *target;
+
+ DEBUG("Request: lock (session %u)", session_key);
+
+ pthread_mutex_lock(&json_lock);
+ target = get_param_string(request, "target");
+ pthread_mutex_unlock(&json_lock);
+
+ if (target != NULL) {
+ ds_type = parse_datastore(target);
+ }
+ if ((int)ds_type == -1) {
+ reply = create_error_reply("Invalid target repository type requested.");
+ goto finalize;
+ }
+
+ reply = netconf_lock(session_key, ds_type);
+
+ CHECK_ERR_SET_REPLY
+ if (reply == NULL) {
+ reply = create_ok_reply();
+ }
+
+finalize:
+ CHECK_AND_FREE(target);
+ return reply;
+}
+
+json_object *
+handle_op_unlock(json_object *request, unsigned int session_key)
+{
+ json_object *reply;
+ NC_DATASTORE ds_type = -1;
+ char *target;
+
+ DEBUG("Request: unlock (session %u)", session_key);
+
+ pthread_mutex_lock(&json_lock);
+ target = get_param_string(request, "target");
+ pthread_mutex_unlock(&json_lock);
+
+ if (target != NULL) {
+ ds_type = parse_datastore(target);
+ }
+ if ((int)ds_type == -1) {
+ reply = create_error_reply("Invalid target repository type requested.");
+ goto finalize;
+ }
+
+ reply = netconf_unlock(session_key, ds_type);
+
+ CHECK_ERR_SET_REPLY
+ if (reply == NULL) {
+ reply = create_ok_reply();
+ }
+
+finalize:
+ CHECK_AND_FREE(target);
+ return reply;
+}
+
+json_object *
+handle_op_kill(json_object *request, unsigned int session_key)
+{
+ json_object *reply = NULL;
+ char *sid = NULL;
+
+ DEBUG("Request: kill-session (session %u)", session_key);
+
+ pthread_mutex_lock(&json_lock);
+ sid = get_param_string(request, "session-id");
+ pthread_mutex_unlock(&json_lock);
+
+ if (sid == NULL) {
+ reply = create_error_reply("Missing session-id parameter.");
+ goto finalize;
+ }
+
+ reply = netconf_killsession(session_key, sid);
+
+ CHECK_ERR_SET_REPLY
+
+finalize:
+ CHECK_AND_FREE(sid);
+ return reply;
+}
+
+json_object *
+handle_op_info(json_object *UNUSED(request), unsigned int session_key)
+{
+ json_object *reply = NULL;
+ struct session_with_mutex *locked_session = NULL;
+ DEBUG("Request: get info about session %u", session_key);
+
+ DEBUG("LOCK wrlock %s", __func__);
+ if (pthread_rwlock_rdlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
locked_session = locked_session->next);
- if ((locked_session != NULL) && (locked_session->hello_message != NULL)) {
- DEBUG("LOCK mutex %s", __func__);
- pthread_mutex_lock(&locked_session->lock);
- DEBUG("creating temporal NC session.");
- temp_session = nc_session_connect_channel(locked_session->session, NULL);
- if (temp_session != NULL) {
- prepare_status_message(locked_session, temp_session);
- DEBUG("closing temporal NC session.");
- nc_session_free(temp_session);
- temp_session = NULL;
- } else {
- DEBUG("Reload hello failed due to channel establishment");
- reply = create_error("Reload was unsuccessful, connection failed.");
- }
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- } else {
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- reply = create_error("Invalid session identifier.");
- }
+ if (locked_session != NULL) {
+ DEBUG("LOCK mutex %s", __func__);
+ pthread_mutex_lock(&locked_session->lock);
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ if (locked_session->hello_message != NULL) {
+ reply = locked_session->hello_message;
+ } else {
+ reply = create_error_reply("Invalid session identifier.");
+ }
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ } else {
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ reply = create_error_reply("Invalid session identifier.");
+ }
- if ((reply == NULL) && (locked_session->hello_message != NULL)) {
- reply = locked_session->hello_message;
- }
- return reply;
+ return reply;
}
-json_object *handle_op_info(json_object *UNUSED(request), const char *session_id)
+json_object *
+handle_op_generic(json_object *request, unsigned int session_key, int idx)
{
- json_object *reply = NULL;
- struct session_with_mutex * locked_session = NULL;
- DEBUG("Request: get info about session %s", session_id);
+ json_object *reply = NULL, *contents, *obj;
+ char *config = NULL;
+ char *data = NULL;
- DEBUG("LOCK wrlock %s", __func__);
- if (pthread_rwlock_rdlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
+ DEBUG("Request: generic request (session %u)", session_key);
- for (locked_session = netconf_sessions_list;
- locked_session && strcmp(nc_session_get_id(locked_session->session), session_id);
+ pthread_mutex_lock(&json_lock);
+ if (json_object_object_get_ex(request, "contents", &contents) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing contents parameter.");
+ goto finalize;
+ }
+ obj = json_object_array_get_idx(contents, idx);
+ if (!obj) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Contents array parameter shorter than sessions.");
+ goto finalize;
+ }
+ config = strdup(json_object_get_string(obj));
+ pthread_mutex_unlock(&json_lock);
+
+ reply = netconf_generic(session_key, config, &data);
+ if (reply == NULL) {
+ GETSPEC_ERR_REPLY
+ if (err_reply != NULL) {
+ /* use filled err_reply from libnetconf's callback */
+ reply = err_reply;
+ }
+ } else {
+ if (data == NULL) {
+ pthread_mutex_lock(&json_lock);
+ reply = json_object_new_object();
+ json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+ pthread_mutex_unlock(&json_lock);
+ } else {
+ reply = create_data_reply(data);
+ free(data);
+ }
+ }
+
+finalize:
+ CHECK_AND_FREE(config);
+ return reply;
+}
+
+json_object *
+handle_op_getschema(json_object *request, unsigned int session_key)
+{
+ char *data = NULL;
+ char *identifier = NULL;
+ char *version = NULL;
+ char *format = NULL;
+ json_object *reply = NULL;
+
+ DEBUG("Request: get-schema (session %u)", session_key);
+
+ pthread_mutex_lock(&json_lock);
+ identifier = get_param_string(request, "identifier");
+ version = get_param_string(request, "version");
+ format = get_param_string(request, "format");
+ pthread_mutex_unlock(&json_lock);
+
+ if (identifier == NULL) {
+ reply = create_error_reply("No identifier for get-schema supplied.");
+ goto finalize;
+ }
+
+ DEBUG("get-schema(version: %s, format: %s)", version, format);
+ if ((data = netconf_getschema(session_key, identifier, version, format, &reply)) == NULL) {
+ CHECK_ERR_SET_REPLY_ERR("Get models operation failed.")
+ } else {
+ reply = create_data_reply(data);
+ free(data);
+ }
+
+finalize:
+ CHECK_AND_FREE(identifier);
+ CHECK_AND_FREE(version);
+ CHECK_AND_FREE(format);
+ return reply;
+}
+
+json_object *
+handle_op_reloadhello(json_object *UNUSED(request), unsigned int session_key)
+{
+ struct nc_session *temp_session = NULL;
+ struct session_with_mutex * locked_session = NULL;
+ json_object *reply = NULL;
+
+ DEBUG("Request: reload hello (session %u)", session_key);
+
+ DEBUG("LOCK wrlock %s", __func__);
+ if (pthread_rwlock_wrlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ return NULL;
+ }
+
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
locked_session = locked_session->next);
- if (locked_session != NULL) {
- DEBUG("LOCK mutex %s", __func__);
- pthread_mutex_lock(&locked_session->lock);
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- if (locked_session->hello_message != NULL) {
- reply = locked_session->hello_message;
- } else {
- reply = create_error("Invalid session identifier.");
- }
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- } else {
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- reply = create_error("Invalid session identifier.");
- }
+ if ((locked_session != NULL) && (locked_session->hello_message != NULL)) {
+ DEBUG("LOCK mutex %s", __func__);
+ pthread_mutex_lock(&locked_session->lock);
+ DEBUG("creating temporary NC session.");
+ temp_session = nc_session_connect_channel(locked_session->session, NULL);
+ if (temp_session != NULL) {
+ prepare_status_message(locked_session, temp_session);
+ DEBUG("closing temporal NC session.");
+ nc_session_free(temp_session);
+ temp_session = NULL;
+ } else {
+ DEBUG("Reload hello failed due to channel establishment");
+ reply = create_error_reply("Reload was unsuccessful, connection failed.");
+ }
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ } else {
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ reply = create_error_reply("Invalid session identifier.");
+ }
+ if ((reply == NULL) && (locked_session->hello_message != NULL)) {
+ reply = locked_session->hello_message;
+ }
- return reply;
+ return reply;
}
-void notification_history(time_t eventtime, const char *content)
+void
+notification_history(time_t eventtime, const char *content)
{
- json_object *notif_history_array = (json_object *) pthread_getspecific(notif_history_key);
- if (notif_history_array == NULL) {
- ERROR("No list of notification history found.");
- return;
- }
- DEBUG("Got notification from history %lu.", (long unsigned) eventtime);
- pthread_mutex_lock(&json_lock);
- json_object *notif = json_object_new_object();
- if (notif == NULL) {
- ERROR("Could not allocate memory for notification (json).");
- goto failed;
- }
- json_object_object_add(notif, "eventtime", json_object_new_int64(eventtime));
- json_object_object_add(notif, "content", json_object_new_string(content));
- json_object_array_add(notif_history_array, notif);
+ json_object *notif_history_array = (json_object *)pthread_getspecific(notif_history_key);
+ if (notif_history_array == NULL) {
+ ERROR("No list of notification history found.");
+ return;
+ }
+ DEBUG("Got notification from history %lu.", (long unsigned)eventtime);
+ pthread_mutex_lock(&json_lock);
+ json_object *notif = json_object_new_object();
+ if (notif == NULL) {
+ ERROR("Could not allocate memory for notification (json).");
+ goto failed;
+ }
+ json_object_object_add(notif, "eventtime", json_object_new_int64(eventtime));
+ json_object_object_add(notif, "content", json_object_new_string(content));
+ json_object_array_add(notif_history_array, notif);
failed:
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_unlock(&json_lock);
}
-json_object *handle_op_ntfgethistory(json_object *request, const char *session_id)
+json_object *
+handle_op_ntfgethistory(json_object *request, unsigned int session_key)
{
- json_object *reply = NULL;
- json_object *js_tmp = NULL;
- char *sid = NULL;
- struct session_with_mutex *locked_session = NULL;
- struct nc_session *temp_session = NULL;
- nc_rpc *rpc = NULL;
- time_t start = 0;
- time_t stop = 0;
- int64_t from = 0, to = 0;
+ json_object *reply = NULL;
+ json_object *js_tmp = NULL;
+ struct session_with_mutex *locked_session = NULL;
+ struct nc_session *temp_session = NULL;
+ nc_rpc *rpc = NULL;
+ time_t start = 0;
+ time_t stop = 0;
+ int64_t from = 0, to = 0;
- DEBUG("Request: get notification history, session %s", session_id);
+ DEBUG("Request: get notification history (session %u)", session_key);
- pthread_mutex_lock(&json_lock);
- sid = get_param_string(request, "session");
+ pthread_mutex_lock(&json_lock);
+ if (json_object_object_get_ex(request, "from", &js_tmp) == TRUE) {
+ from = json_object_get_int64(js_tmp);
+ }
+ if (json_object_object_get_ex(request, "to", &js_tmp) == TRUE) {
+ to = json_object_get_int64(js_tmp);
+ }
+ pthread_mutex_unlock(&json_lock);
- if (json_object_object_get_ex(request, "from", &js_tmp) == TRUE) {
- from = json_object_get_int64(js_tmp);
- json_object_put(js_tmp);
- }
- if (json_object_object_get_ex(request, "to", &js_tmp) == TRUE) {
- to = json_object_get_int64(js_tmp);
- json_object_put(js_tmp);
- }
- pthread_mutex_unlock(&json_lock);
+ start = time(NULL) + from;
+ stop = time(NULL) + to;
- start = time(NULL) + from;
- stop = time(NULL) + to;
+ DEBUG("notification history interval %li %li", (long int)from, (long int)to);
- DEBUG("notification history interval %li %li", (long int) from, (long int) to);
+ DEBUG("LOCK wrlock %s", __func__);
+ if (pthread_rwlock_rdlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ reply = create_error_reply("Internal lock failed.");
+ goto finalize;
+ }
- if (sid == NULL) {
- reply = create_error("Missing session parameter.");
- goto finalize;
- }
-
- DEBUG("LOCK wrlock %s", __func__);
- if (pthread_rwlock_rdlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- reply = create_error("Internal lock failed.");
- goto finalize;
- }
-
- for (locked_session = netconf_sessions_list;
- locked_session && strcmp(nc_session_get_id(locked_session->session), session_id);
+ for (locked_session = netconf_sessions_list;
+ locked_session && (locked_session->session_key != session_key);
locked_session = locked_session->next);
- if (locked_session != NULL) {
- DEBUG("LOCK mutex %s", __func__);
- pthread_mutex_lock(&locked_session->lock);
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- DEBUG("creating temporal NC session.");
- temp_session = nc_session_connect_channel(locked_session->session, NULL);
- if (temp_session != NULL) {
- rpc = nc_rpc_subscribe(NULL /* stream */, NULL /* filter */, &start, &stop);
- if (rpc == NULL) {
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- DEBUG("notifications: creating an rpc request failed.");
- reply = create_error("notifications: creating an rpc request failed.");
- goto finalize;
- }
+ if (locked_session != NULL) {
+ DEBUG("LOCK mutex %s", __func__);
+ pthread_mutex_lock(&locked_session->lock);
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ DEBUG("creating temporal NC session.");
+ temp_session = nc_session_connect_channel(locked_session->session, NULL);
+ if (temp_session != NULL) {
+ rpc = nc_rpc_subscribe(NULL /* stream */, NULL /* filter */, &start, &stop);
+ if (rpc == NULL) {
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("notifications: creating an rpc request failed.");
+ reply = create_error_reply("notifications: creating an rpc request failed.");
+ goto finalize;
+ }
- DEBUG("Send NC subscribe.");
- /** \todo replace with sth like netconf_op(http_server, session_hash, rpc) */
- json_object *res = netconf_unlocked_op(temp_session, rpc);
- if (res != NULL) {
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- DEBUG("Subscription RPC failed.");
- reply = res;
- goto finalize;
- }
- rpc = NULL; /* just note that rpc is already freed by send_recv_process() */
+ DEBUG("Send NC subscribe.");
+ /** \todo replace with sth like netconf_op(http_server, session_hash, rpc) */
+ json_object *res = netconf_unlocked_op(temp_session, rpc);
+ if (res != NULL) {
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("Subscription RPC failed.");
+ reply = res;
+ goto finalize;
+ }
+ rpc = NULL; /* just note that rpc is already freed by send_recv_process() */
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- DEBUG("LOCK mutex %s", __func__);
- pthread_mutex_lock(&ntf_history_lock);
- pthread_mutex_lock(&json_lock);
- json_object *notif_history_array = json_object_new_array();
- pthread_mutex_unlock(&json_lock);
- if (pthread_setspecific(notif_history_key, notif_history_array) != 0) {
- ERROR("notif_history: cannot set thread-specific hash value.");
- }
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("LOCK mutex %s", __func__);
+ pthread_mutex_lock(&ntf_history_lock);
+ pthread_mutex_lock(&json_lock);
+ json_object *notif_history_array = json_object_new_array();
+ pthread_mutex_unlock(&json_lock);
+ if (pthread_setspecific(notif_history_key, notif_history_array) != 0) {
+ ERROR("notif_history: cannot set thread-specific hash value.");
+ }
- ncntf_dispatch_receive(temp_session, notification_history);
+ ncntf_dispatch_receive(temp_session, notification_history);
- pthread_mutex_lock(&json_lock);
- reply = json_object_new_object();
- json_object_object_add(reply, "notifications", notif_history_array);
- //json_object_put(notif_history_array);
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_lock(&json_lock);
+ reply = json_object_new_object();
+ json_object_object_add(reply, "notifications", notif_history_array);
+ //json_object_put(notif_history_array);
+ pthread_mutex_unlock(&json_lock);
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&ntf_history_lock);
- DEBUG("closing temporal NC session.");
- nc_session_free(temp_session);
- temp_session = NULL;
- } else {
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&locked_session->lock);
- DEBUG("Get history of notification failed due to channel establishment");
- reply = create_error("Get history of notification was unsuccessful, connection failed.");
- }
- } else {
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
- reply = create_error("Invalid session identifier.");
- }
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&ntf_history_lock);
+ DEBUG("closing temporal NC session.");
+ nc_session_free(temp_session);
+ temp_session = NULL;
+ } else {
+ DEBUG("UNLOCK mutex %s", __func__);
+ pthread_mutex_unlock(&locked_session->lock);
+ DEBUG("Get history of notification failed due to channel establishment");
+ reply = create_error_reply("Get history of notification was unsuccessful, connection failed.");
+ }
+ } else {
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
+ reply = create_error_reply("Invalid session identifier.");
+ }
finalize:
- CHECK_AND_FREE(sid);
- return reply;
+ return reply;
}
-json_object *handle_op_validate(json_object *request, const char *session_id)
+json_object *
+handle_op_validate(json_object *request, unsigned int session_key)
{
- json_object *reply = NULL;
- char *sid = NULL;
- char *target = NULL;
- char *url = NULL;
- nc_rpc *rpc = NULL;
- NC_DATASTORE target_ds;
+ json_object *reply = NULL;
+ char *target = NULL;
+ char *url = NULL;
+ nc_rpc *rpc = NULL;
+ NC_DATASTORE target_ds;
- DEBUG("Request: validate datastore, session %s", session_id);
+ DEBUG("Request: validate datastore (session %u)", session_key);
- pthread_mutex_lock(&json_lock);
- sid = get_param_string(request, "session");
- target = get_param_string(request, "target");
- url = get_param_string(request, "url");
- pthread_mutex_unlock(&json_lock);
+ pthread_mutex_lock(&json_lock);
+ target = get_param_string(request, "target");
+ url = get_param_string(request, "url");
+ pthread_mutex_unlock(&json_lock);
- if ((sid == NULL) || (target == NULL)) {
- reply = create_error("Missing session parameter.");
- goto finalize;
- }
+ if (target == NULL) {
+ reply = create_error_reply("Missing target parameter.");
+ goto finalize;
+ }
- /* validation */
- target_ds = parse_datastore(target);
- if (target_ds == NC_DATASTORE_URL) {
- if (url != NULL) {
- rpc = nc_rpc_validate(target_ds, url);
- }
- } else if ((target_ds == NC_DATASTORE_RUNNING) || (target_ds == NC_DATASTORE_STARTUP)
- || (target_ds == NC_DATASTORE_CANDIDATE)) {
- rpc = nc_rpc_validate(target_ds);
- }
- if (rpc == NULL) {
- DEBUG("mod_netconf: creating rpc request failed");
- reply = create_error("Creation of RPC request failed.");
- goto finalize;
- }
+ /* validation */
+ target_ds = parse_datastore(target);
+ if (target_ds == NC_DATASTORE_URL) {
+ if (url != NULL) {
+ rpc = nc_rpc_validate(target_ds, url);
+ }
+ } else if ((target_ds == NC_DATASTORE_RUNNING) || (target_ds == NC_DATASTORE_STARTUP)
+ || (target_ds == NC_DATASTORE_CANDIDATE)) {
+ rpc = nc_rpc_validate(target_ds);
+ }
+ if (rpc == NULL) {
+ DEBUG("mod_netconf: creating rpc request failed");
+ reply = create_error_reply("Creation of RPC request failed.");
+ goto finalize;
+ }
- DEBUG("Request: validate datastore");
- if ((reply = netconf_op(session_id, rpc, NULL)) == NULL) {
+ if ((reply = netconf_op(session_key, rpc, NULL)) == NULL) {
+ CHECK_ERR_SET_REPLY
- CHECK_ERR_SET_REPLY
+ if (reply == NULL) {
+ DEBUG("Request: validation ok.");
+ reply = create_ok_reply();
+ }
+ }
+ nc_rpc_free (rpc);
- if (reply == NULL) {
- DEBUG("Request: validation ok.");
- reply = create_ok();
- }
- }
- nc_rpc_free (rpc);
finalize:
- CHECK_AND_FREE(sid);
- CHECK_AND_FREE(target);
- CHECK_AND_FREE(url);
- return reply;
+ CHECK_AND_FREE(target);
+ CHECK_AND_FREE(url);
+ return reply;
}
-void * thread_routine (void * arg)
+json_object *
+handle_op_query(json_object *request, unsigned int session_key, int idx)
{
- void * retval = NULL;
- struct pollfd fds;
- json_object *request = NULL;
- json_object *reply = NULL;
- json_object *js_tmp = NULL;
- int operation = (-1);
- NC_DATASTORE ds_type_t = -1;
- int status = 0;
- const char *msgtext;
- char *session_id = NULL;
- char *target = NULL;
- char *url = NULL;
- char *chunked_out_msg = NULL;
- //server_rec * server = ((struct pass_to_thread*)arg)->server;
- int client = ((struct pass_to_thread*)arg)->client;
+ json_object *reply = NULL, *filters, *obj;
+ char *filter = NULL;
+ int load_children = 0;
- char *buffer = NULL;
+ DEBUG("Request: query (session %u)", session_key);
- /* init thread specific err_reply memory */
- create_err_reply_p();
+ pthread_mutex_lock(&json_lock);
+ if (json_object_object_get_ex(request, "filters", &filters) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing filters parameter.");
+ goto finalize;
+ }
+ obj = json_object_array_get_idx(filters, idx);
+ if (!obj) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Filters array parameter shorter than sessions.");
+ goto finalize;
+ }
+ filter = strdup(json_object_get_string(obj));
+ if (json_object_object_get_ex(request, "load_children", &obj) == TRUE) {
+ load_children = json_object_get_boolean(obj);
+ }
+ pthread_mutex_unlock(&json_lock);
- while (!isterminated) {
- fds.fd = client;
- fds.events = POLLIN;
- fds.revents = 0;
+ reply = libyang_query(session_key, filter, load_children);
- status = poll(&fds, 1, 1000);
+ CHECK_ERR_SET_REPLY
+ if (!reply) {
+ reply = create_error_reply("Query failed.");
+ }
- if (status == 0 || (status == -1 && (errno == EAGAIN || (errno == EINTR && isterminated == 0)))) {
- /* poll was interrupted - check if the isterminated is set and if not, try poll again */
- continue;
- } else if (status < 0) {
- /* 0: poll time outed
- * close socket and ignore this request from the client, it can try it again
- * -1: poll failed
- * something wrong happend, close this socket and wait for another request
- */
- close(client);
- break;
- }
- /* status > 0 */
+finalize:
+ CHECK_AND_FREE(filter);
+ return reply;
+}
- /* check the status of the socket */
+json_object *
+handle_op_merge(json_object *request, unsigned int session_key, int idx)
+{
+ json_object *reply = NULL, *configs, *obj;
+ char *config = NULL;
- /* if nothing to read and POLLHUP (EOF) or POLLERR set */
- if ((fds.revents & POLLHUP) || (fds.revents & POLLERR)) {
- /* close client's socket (it's probably already closed by client */
- close(client);
- break;
- }
+ DEBUG("Request: merge (session %u)", session_key);
- DEBUG("Get framed message...");
- buffer = get_framed_message(client);
+ pthread_mutex_lock(&json_lock);
+ if (json_object_object_get_ex(request, "configurations", &configs) == FALSE) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Missing configurations parameter.");
+ goto finalize;
+ }
+ obj = json_object_array_get_idx(configs, idx);
+ if (!obj) {
+ pthread_mutex_unlock(&json_lock);
+ reply = create_error_reply("Filters array parameter shorter than sessions.");
+ goto finalize;
+ }
+ config = strdup(json_object_get_string(obj));
+ pthread_mutex_unlock(&json_lock);
- DEBUG("Check read buffer.");
- if (buffer != NULL) {
- enum json_tokener_error jerr;
- pthread_mutex_lock(&json_lock);
- request = json_tokener_parse_verbose(buffer, &jerr);
- if (jerr != json_tokener_success) {
- ERROR("JSON parsing error");
- pthread_mutex_unlock(&json_lock);
- continue;
- }
+ reply = libyang_merge(session_key, config);
- session_id = get_param_string(request, "session");
- if (json_object_object_get_ex(request, "type", &js_tmp) == TRUE) {
- operation = json_object_get_int(js_tmp);
- json_object_put(js_tmp);
- js_tmp = NULL;
- }
- pthread_mutex_unlock(&json_lock);
- if (operation == -1) {
- reply = create_error("Missing operation type form frontend.");
- goto send_reply;
- }
+ CHECK_ERR_SET_REPLY
+ if (!reply) {
+ reply = create_error_reply("Merge failed.");
+ }
- DEBUG("operation %d session_id %s.", operation, session_id);
- /* DO NOT FREE session_key HERE, IT IS PART OF REQUEST */
- if (operation != MSG_CONNECT && session_id == NULL) {
- reply = create_error("Missing session specification.");
- pthread_mutex_lock(&json_lock);
- msgtext = json_object_to_json_string(reply);
- pthread_mutex_unlock(&json_lock);
+finalize:
+ CHECK_AND_FREE(config);
+ return reply;
+}
- send(client, msgtext, strlen(msgtext) + 1, 0);
+void *
+thread_routine(void *arg)
+{
+ void *retval = NULL;
+ struct pollfd fds;
+ json_object *request = NULL, *replies = NULL, *reply, *sessions = NULL;
+ json_object *js_tmp = NULL;
+ int operation = (-1), count, i;
+ int status = 0;
+ const char *msgtext;
+ unsigned int session_key = 0;
+ char *chunked_out_msg = NULL;
+ int client = ((struct pass_to_thread *)arg)->client;
- pthread_mutex_lock(&json_lock);
- json_object_put(reply);
- pthread_mutex_unlock(&json_lock);
- /* there is some stupid client, so close the connection to give a chance to some other client */
- close(client);
- break;
- }
+ char *buffer = NULL;
- /* null global JSON error-reply */
- clean_err_reply();
+ /* init thread specific err_reply memory */
+ create_err_reply_p();
- /* prepare reply envelope */
- if (reply != NULL) {
- pthread_mutex_lock(&json_lock);
- json_object_put(reply);
- pthread_mutex_unlock(&json_lock);
- }
- reply = NULL;
+ while (!isterminated) {
+ fds.fd = client;
+ fds.events = POLLIN;
+ fds.revents = 0;
- /* process required operation */
- switch (operation) {
- case MSG_CONNECT:
- reply = handle_op_connect(request);
- break;
- case MSG_GET:
- reply = handle_op_get(request, session_id);
- break;
- case MSG_GETCONFIG:
- reply = handle_op_getconfig(request, session_id);
- break;
- case MSG_GETSCHEMA:
- reply = handle_op_getschema(request, session_id);
- break;
- case MSG_EDITCONFIG:
- reply = handle_op_editconfig(request, session_id);
- break;
- case MSG_COPYCONFIG:
- reply = handle_op_copyconfig(request, session_id);
- break;
+ status = poll(&fds, 1, 1000);
- case MSG_DELETECONFIG:
- case MSG_LOCK:
- case MSG_UNLOCK:
- /* get parameters */
- pthread_mutex_lock(&json_lock);
- target = get_param_string(request, "target");
- pthread_mutex_unlock(&json_lock);
- if (target != NULL) {
- ds_type_t = parse_datastore(target);
- }
+ if (status == 0 || (status == -1 && (errno == EAGAIN || (errno == EINTR && isterminated == 0)))) {
+ /* poll was interrupted - check if the isterminated is set and if not, try poll again */
+ continue;
+ } else if (status < 0) {
+ /* 0: poll time outed
+ * close socket and ignore this request from the client, it can try it again
+ * -1: poll failed
+ * something wrong happend, close this socket and wait for another request
+ */
+ close(client);
+ break;
+ }
+ /* status > 0 */
- if ((int)ds_type_t == -1) {
- reply = create_error("Invalid target repository type requested.");
- break;
- }
- switch(operation) {
- case MSG_DELETECONFIG:
- DEBUG("Request: delete-config (session %s)", session_id);
- pthread_mutex_lock(&json_lock);
- url = get_param_string(request, "url");
- pthread_mutex_unlock(&json_lock);
- reply = netconf_deleteconfig(session_id, ds_type_t, url);
- break;
- case MSG_LOCK:
- DEBUG("Request: lock (session %s)", session_id);
- reply = netconf_lock(session_id, ds_type_t);
- break;
- case MSG_UNLOCK:
- DEBUG("Request: unlock (session %s)", session_id);
- reply = netconf_unlock(session_id, ds_type_t);
- break;
- default:
- reply = create_error("Internal: Unknown request type.");
- break;
- }
+ /* check the status of the socket */
- CHECK_ERR_SET_REPLY
- if (reply == NULL) {
- reply = create_ok();
- }
- break;
- case MSG_KILL:
- reply = handle_op_kill(request, session_id);
- break;
- case MSG_DISCONNECT:
- reply = handle_op_disconnect(request, session_id);
- break;
- case MSG_RELOADHELLO:
- reply = handle_op_reloadhello(request, session_id);
- break;
- case MSG_INFO:
- reply = handle_op_info(request, session_id);
- break;
- case MSG_GENERIC:
- reply = handle_op_generic(request, session_id);
- break;
- case MSG_NTF_GETHISTORY:
- reply = handle_op_ntfgethistory(request, session_id);
- break;
- case MSG_VALIDATE:
- reply = handle_op_validate(request, session_id);
- break;
- default:
- DEBUG("Unknown mod_netconf operation requested (%d)", operation);
- reply = create_error("Operation not supported.");
- break;
- }
- /* free parameters */
- CHECK_AND_FREE(url);
- CHECK_AND_FREE(target);
- request = NULL;
- operation = (-1);
- ds_type_t = (-1);
+ /* if nothing to read and POLLHUP (EOF) or POLLERR set */
+ if ((fds.revents & POLLHUP) || (fds.revents & POLLERR)) {
+ /* close client's socket (it's probably already closed by client */
+ close(client);
+ break;
+ }
- DEBUG("Clean request json object.");
- if (request != NULL) {
- pthread_mutex_lock(&json_lock);
- json_object_put(request);
- pthread_mutex_unlock(&json_lock);
- }
- DEBUG("Send reply json object.");
+ DEBUG("Get framed message...");
+ buffer = get_framed_message(client);
+ DEBUG("Check read buffer.");
+ if (buffer != NULL) {
+ enum json_tokener_error jerr;
+ pthread_mutex_lock(&json_lock);
+ request = json_tokener_parse_verbose(buffer, &jerr);
+ if (jerr != json_tokener_success) {
+ ERROR("JSON parsing error");
+ pthread_mutex_unlock(&json_lock);
+ continue;
+ }
+
+ if (json_object_object_get_ex(request, "type", &js_tmp) == TRUE) {
+ operation = json_object_get_int(js_tmp);
+ }
+ pthread_mutex_unlock(&json_lock);
+ if (operation == -1) {
+ replies = create_replies();
+ add_reply(replies, create_error_reply("Missing operation type from frontend."), 0);
+ goto send_reply;
+ }
+
+ if ((operation < 4) || ((operation > 19) && (operation < 100)) || (operation > 101)) {
+ DEBUG("Unknown mod_netconf operation requested (%d)", operation);
+ replies = create_replies();
+ add_reply(replies, create_error_reply("Operation not supported."), 0);
+ goto send_reply;
+ }
+
+ DEBUG("operation %d", operation);
+
+ /* null global JSON error-reply */
+ clean_err_reply();
+
+ /* clean replies envelope */
+ if (replies != NULL) {
+ pthread_mutex_lock(&json_lock);
+ json_object_put(replies);
+ pthread_mutex_unlock(&json_lock);
+ }
+ replies = create_replies();
+
+ if (operation == MSG_CONNECT) {
+ count = 1;
+ } else {
+ pthread_mutex_lock(&json_lock);
+ if (json_object_object_get_ex(request, "sessions", &sessions) == FALSE) {
+ add_reply(replies, create_error_reply("Operation missing \"sessions\" arg"), 0);
+ goto send_reply;
+ }
+ count = json_object_array_length(sessions);
+ pthread_mutex_unlock(&json_lock);
+ }
+
+ for (i = 0; i < count; ++i) {
+ if (operation != MSG_CONNECT) {
+ js_tmp = json_object_array_get_idx(sessions, i);
+ session_key = json_object_get_int(js_tmp);
+ }
+
+ /* process required operation */
+ switch (operation) {
+ case MSG_CONNECT:
+ reply = handle_op_connect(request);
+ break;
+ case MSG_DISCONNECT:
+ reply = handle_op_disconnect(request, session_key);
+ break;
+ case MSG_GET:
+ reply = handle_op_get(request, session_key);
+ break;
+ case MSG_GETCONFIG:
+ reply = handle_op_getconfig(request, session_key);
+ break;
+ case MSG_EDITCONFIG:
+ reply = handle_op_editconfig(request, session_key, i);
+ break;
+ case MSG_COPYCONFIG:
+ reply = handle_op_copyconfig(request, session_key, i);
+ break;
+ case MSG_DELETECONFIG:
+ reply = handle_op_deleteconfig(request, session_key);
+ break;
+ case MSG_LOCK:
+ reply = handle_op_lock(request, session_key);
+ break;
+ case MSG_UNLOCK:
+ reply = handle_op_unlock(request, session_key);
+ break;
+ case MSG_KILL:
+ reply = handle_op_kill(request, session_key);
+ break;
+ case MSG_INFO:
+ reply = handle_op_info(request, session_key);
+ break;
+ case MSG_GENERIC:
+ reply = handle_op_generic(request, session_key, i);
+ break;
+ case MSG_GETSCHEMA:
+ reply = handle_op_getschema(request, session_key);
+ break;
+ case MSG_RELOADHELLO:
+ reply = handle_op_reloadhello(request, session_key);
+ break;
+ case MSG_NTF_GETHISTORY:
+ reply = handle_op_ntfgethistory(request, session_key);
+ break;
+ case MSG_VALIDATE:
+ reply = handle_op_validate(request, session_key);
+ break;
+ case SCH_QUERY:
+ reply = handle_op_query(request, session_key, i);
+ break;
+ case SCH_MERGE:
+ reply = handle_op_merge(request, session_key, i);
+ break;
+ }
+
+ add_reply(replies, reply, session_key);
+ }
+
+ /* free parameters */
+ operation = (-1);
+
+ DEBUG("Clean request json object.");
+ if (request != NULL) {
+ pthread_mutex_lock(&json_lock);
+ json_object_put(request);
+ pthread_mutex_unlock(&json_lock);
+ }
+ DEBUG("Send reply json object.");
send_reply:
- /* send reply to caller */
- if (reply != NULL) {
- pthread_mutex_lock(&json_lock);
- msgtext = json_object_to_json_string(reply);
- if (asprintf(&chunked_out_msg, "\n#%d\n%s\n##\n", (int) strlen(msgtext), msgtext) == -1) {
- if (buffer != NULL) {
- free(buffer);
- buffer = NULL;
- }
- pthread_mutex_unlock(&json_lock);
- break;
- }
- pthread_mutex_unlock(&json_lock);
+ /* send reply to caller */
+ if (replies) {
+ pthread_mutex_lock(&json_lock);
+ msgtext = json_object_to_json_string(replies);
+ if (asprintf(&chunked_out_msg, "\n#%d\n%s\n##\n", (int)strlen(msgtext), msgtext) == -1) {
+ if (buffer != NULL) {
+ free(buffer);
+ buffer = NULL;
+ }
+ pthread_mutex_unlock(&json_lock);
+ break;
+ }
+ pthread_mutex_unlock(&json_lock);
- DEBUG("Send framed reply json object.");
- send(client, chunked_out_msg, strlen(chunked_out_msg) + 1, 0);
- DEBUG("Clean reply json object.");
- pthread_mutex_lock(&json_lock);
- json_object_put(reply);
- reply = NULL;
- DEBUG("Clean message buffer.");
- CHECK_AND_FREE(chunked_out_msg);
- chunked_out_msg = NULL;
- if (buffer != NULL) {
- free(buffer);
- buffer = NULL;
- }
- pthread_mutex_unlock(&json_lock);
- clean_err_reply();
- } else {
- ERROR("Reply is NULL, shouldn't be...");
- continue;
- }
- }
- }
- free (arg);
+ DEBUG("Send framed reply json object.");
+ send(client, chunked_out_msg, strlen(chunked_out_msg) + 1, 0);
+ DEBUG("Clean reply json object.");
+ pthread_mutex_lock(&json_lock);
+ json_object_put(replies);
+ replies = NULL;
+ DEBUG("Clean message buffer.");
+ CHECK_AND_FREE(chunked_out_msg);
+ chunked_out_msg = NULL;
+ if (buffer) {
+ free(buffer);
+ buffer = NULL;
+ }
+ pthread_mutex_unlock(&json_lock);
+ clean_err_reply();
+ } else {
+ ERROR("Reply is NULL, shouldn't be...");
+ continue;
+ }
+ }
+ }
+ free(arg);
+ free_err_reply();
- free_err_reply();
-
- return retval;
+ return retval;
}
/**
@@ -2108,61 +3032,67 @@
* sessions. This function iterates over the list of sessions and close them
* all.
*/
-static void close_all_nc_sessions(void)
+static void
+close_all_nc_sessions(void)
{
- struct session_with_mutex *swm = NULL;
- int ret;
+ struct session_with_mutex *locked_session, *next_session;
+ int ret;
- /* get exclusive access to sessions_list (conns) */
- DEBUG("LOCK wrlock %s", __func__);
- if ((ret = pthread_rwlock_wrlock (&session_lock)) != 0) {
- ERROR("Error while locking rwlock: %d (%s)", ret, strerror(ret));
- return;
- }
- for (swm = netconf_sessions_list; swm; swm = swm->next) {
- DEBUG("Closing NETCONF session (%s).", nc_session_get_id(swm->session));
+ /* get exclusive access to sessions_list (conns) */
+ DEBUG("LOCK wrlock %s", __func__);
+ if ((ret = pthread_rwlock_wrlock (&session_lock)) != 0) {
+ ERROR("Error while locking rwlock: %d (%s)", ret, strerror(ret));
+ return;
+ }
+ for (next_session = netconf_sessions_list; next_session;) {
+ locked_session = next_session;
+ next_session = locked_session->next;
/* close_and_free_session handles locking on its own */
- close_and_free_session(swm);
- }
- /* get exclusive access to sessions_list (conns) */
- DEBUG("UNLOCK wrlock %s", __func__);
- if (pthread_rwlock_unlock (&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
+ DEBUG("Closing NETCONF session %u (SID %s).", locked_session->session_key, nc_session_get_id(locked_session->session));
+ close_and_free_session(locked_session);
+ }
+ netconf_sessions_list = NULL;
+
+ /* get exclusive access to sessions_list (conns) */
+ DEBUG("UNLOCK wrlock %s", __func__);
+ if (pthread_rwlock_unlock (&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
}
-static void check_timeout_and_close(void)
+static void
+check_timeout_and_close(void)
{
- struct nc_session *ns = NULL;
- struct session_with_mutex *swm = NULL;
- time_t current_time = time(NULL);
- int ret;
+ struct nc_session *ns = NULL;
+ struct session_with_mutex *locked_session = NULL;
+ time_t current_time = time(NULL);
+ int ret;
- /* get exclusive access to sessions_list (conns) */
- if ((ret = pthread_rwlock_wrlock(&session_lock)) != 0) {
- DEBUG("Error while locking rwlock: %d (%s)", ret, strerror(ret));
- return;
- }
- for (swm = netconf_sessions_list; swm; swm = swm->next) {
- ns = swm->session;
- if (ns == NULL) {
- continue;
- }
- pthread_mutex_lock(&swm->lock);
- if ((current_time - swm->last_activity) > ACTIVITY_TIMEOUT) {
- DEBUG("Closing NETCONF session (%s).", nc_session_get_id(swm->session));
+ /* get exclusive access to sessions_list (conns) */
+ if ((ret = pthread_rwlock_wrlock(&session_lock)) != 0) {
+ DEBUG("Error while locking rwlock: %d (%s)", ret, strerror(ret));
+ return;
+ }
+ for (locked_session = netconf_sessions_list; locked_session; locked_session = locked_session->next) {
+ ns = locked_session->session;
+ if (ns == NULL) {
+ continue;
+ }
+ pthread_mutex_lock(&locked_session->lock);
+ if ((current_time - locked_session->last_activity) > ACTIVITY_TIMEOUT) {
+ DEBUG("Closing NETCONF session %u (SID %s).", locked_session->session_key, nc_session_get_id(locked_session->session));
- /* close_and_free_session handles locking on its own */
- close_and_free_session(swm);
- } else {
- pthread_mutex_unlock(&swm->lock);
- }
- }
- /* get exclusive access to sessions_list (conns) */
- if (pthread_rwlock_unlock(&session_lock) != 0) {
- ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
- }
+ /* close_and_free_session handles locking on its own */
+ close_and_free_session(locked_session);
+ } else {
+ pthread_mutex_unlock(&locked_session->lock);
+ }
+ }
+ /* get exclusive access to sessions_list (conns) */
+ if (pthread_rwlock_unlock(&session_lock) != 0) {
+ ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+ }
}
@@ -2173,237 +3103,239 @@
* - the daemon run as a separate process
*
*/
-static void forked_proc(void)
+static void
+forked_proc(void)
{
- struct timeval tv;
- struct sockaddr_un local, remote;
- int lsock, client, ret, i, pthread_count = 0;
- unsigned int olds = 0, timediff = 0;
- socklen_t len;
- struct pass_to_thread * arg;
- pthread_t * ptids = calloc(1, sizeof(pthread_t));
- struct timespec maxtime;
- pthread_rwlockattr_t lock_attrs;
- #ifdef WITH_NOTIFICATIONS
- char use_notifications = 0;
- #endif
+ struct timeval tv;
+ struct sockaddr_un local, remote;
+ int lsock, client, ret, i, pthread_count = 0;
+ unsigned int olds = 0, timediff = 0;
+ socklen_t len;
+ struct pass_to_thread *arg;
+ pthread_t *ptids = calloc(1, sizeof(pthread_t));
+ struct timespec maxtime;
+ pthread_rwlockattr_t lock_attrs;
+ #ifdef WITH_NOTIFICATIONS
+ char use_notifications = 0;
+ #endif
- /* wait at most 5 seconds for every thread to terminate */
- maxtime.tv_sec = 5;
- maxtime.tv_nsec = 0;
+ /* wait at most 5 seconds for every thread to terminate */
+ maxtime.tv_sec = 5;
+ maxtime.tv_nsec = 0;
#ifdef HAVE_UNIXD_SETUP_CHILD
- /* change uid and gid of process for security reasons */
- unixd_setup_child();
+ /* change uid and gid of process for security reasons */
+ unixd_setup_child();
#else
# ifdef SU_GROUP
- if (strlen(SU_GROUP) > 0) {
- struct group *g = getgrnam(SU_GROUP);
- if (g == NULL) {
- ERROR("GID (%s) was not found.", SU_GROUP);
- return;
- }
- if (setgid(g->gr_gid) != 0) {
-
- ERROR("Switching to %s GID failed. (%s)", SU_GROUP, strerror(errno));
- return;
- }
- }
+ if (strlen(SU_GROUP) > 0) {
+ struct group *g = getgrnam(SU_GROUP);
+ if (g == NULL) {
+ ERROR("GID (%s) was not found.", SU_GROUP);
+ return;
+ }
+ if (setgid(g->gr_gid) != 0) {
+ ERROR("Switching to %s GID failed. (%s)", SU_GROUP, strerror(errno));
+ return;
+ }
+ }
# else
- DEBUG("no SU_GROUP");
+ DEBUG("no SU_GROUP");
# endif
# ifdef SU_USER
- if (strlen(SU_USER) > 0) {
- struct passwd *p = getpwnam(SU_USER);
- if (p == NULL) {
- ERROR("UID (%s) was not found.", SU_USER);
- return;
- }
- if (setuid(p->pw_uid) != 0) {
- ERROR("Switching to UID %s failed. (%s)", SU_USER, strerror(errno));
- return;
- }
- }
+ if (strlen(SU_USER) > 0) {
+ struct passwd *p = getpwnam(SU_USER);
+ if (p == NULL) {
+ ERROR("UID (%s) was not found.", SU_USER);
+ return;
+ }
+ if (setuid(p->pw_uid) != 0) {
+ ERROR("Switching to UID %s failed. (%s)", SU_USER, strerror(errno));
+ return;
+ }
+ }
# else
- DEBUG("no SU_USER");
+ DEBUG("no SU_USER");
# endif
#endif
- /* try to remove if exists */
- unlink(sockname);
+ /* try to remove if exists */
+ unlink(sockname);
- /* create listening UNIX socket to accept incoming connections */
- if ((lsock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
- ERROR("Creating socket failed (%s)", strerror(errno));
- goto error_exit;
- }
+ /* create listening UNIX socket to accept incoming connections */
+ if ((lsock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
+ ERROR("Creating socket failed (%s)", strerror(errno));
+ goto error_exit;
+ }
- local.sun_family = AF_UNIX;
- strncpy(local.sun_path, sockname, sizeof(local.sun_path));
- len = offsetof(struct sockaddr_un, sun_path) + strlen(local.sun_path);
+ local.sun_family = AF_UNIX;
+ strncpy(local.sun_path, sockname, sizeof(local.sun_path));
+ len = offsetof(struct sockaddr_un, sun_path) + strlen(local.sun_path);
- if (bind(lsock, (struct sockaddr *) &local, len) == -1) {
- if (errno == EADDRINUSE) {
- ERROR("mod_netconf socket address already in use");
- goto error_exit;
- }
- ERROR("Binding socket failed (%s)", strerror(errno));
- goto error_exit;
- }
+ if (bind(lsock, (struct sockaddr *)&local, len) == -1) {
+ if (errno == EADDRINUSE) {
+ ERROR("mod_netconf socket address already in use");
+ goto error_exit;
+ }
+ ERROR("Binding socket failed (%s)", strerror(errno));
+ goto error_exit;
+ }
- if (listen(lsock, MAX_SOCKET_CL) == -1) {
- ERROR("Setting up listen socket failed (%s)", strerror(errno));
- goto error_exit;
- }
- chmod(sockname, S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH);
+ if (listen(lsock, MAX_SOCKET_CL) == -1) {
+ ERROR("Setting up listen socket failed (%s)", strerror(errno));
+ goto error_exit;
+ }
+ chmod(sockname, S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH);
- uid_t user = -1;
- if (strlen(CHOWN_USER) > 0) {
- struct passwd *p = getpwnam(CHOWN_USER);
- if (p != NULL) {
- user = p->pw_uid;
- }
- }
- gid_t group = -1;
- if (strlen(CHOWN_GROUP) > 0) {
- struct group *g = getgrnam(CHOWN_GROUP);
- if (g != NULL) {
- group = g->gr_gid;
- }
- }
- if (chown(sockname, user, group) == -1) {
- ERROR("Chown on socket file failed (%s).", strerror(errno));
- }
+ uid_t user = -1;
+ if (strlen(CHOWN_USER) > 0) {
+ struct passwd *p = getpwnam(CHOWN_USER);
+ if (p != NULL) {
+ user = p->pw_uid;
+ }
+ }
+ gid_t group = -1;
+ if (strlen(CHOWN_GROUP) > 0) {
+ struct group *g = getgrnam(CHOWN_GROUP);
+ if (g != NULL) {
+ group = g->gr_gid;
+ }
+ }
+ if (chown(sockname, user, group) == -1) {
+ ERROR("Chown on socket file failed (%s).", strerror(errno));
+ }
- /* prepare internal lists */
+ /* prepare internal lists */
- #ifdef WITH_NOTIFICATIONS
- if (notification_init() == -1) {
- ERROR("libwebsockets initialization failed");
- use_notifications = 0;
- } else {
- use_notifications = 1;
- }
- #endif
+ #ifdef WITH_NOTIFICATIONS
+ if (notification_init() == -1) {
+ ERROR("libwebsockets initialization failed");
+ use_notifications = 0;
+ } else {
+ use_notifications = 1;
+ }
+ #endif
- /* setup libnetconf's callbacks */
- nc_verbosity(NC_VERB_DEBUG);
- nc_callback_print(clb_print);
- nc_callback_ssh_host_authenticity_check(netconf_callback_ssh_hostkey_check);
- nc_callback_sshauth_interactive(netconf_callback_sshauth_interactive);
- nc_callback_sshauth_password(netconf_callback_sshauth_password);
- nc_callback_sshauth_passphrase(netconf_callback_sshauth_passphrase);
- nc_callback_error_reply(netconf_callback_error_process);
+ /* setup libnetconf's callbacks */
+ nc_verbosity(NC_VERB_DEBUG);
+ nc_callback_print(clb_print);
+ nc_callback_ssh_host_authenticity_check(netconf_callback_ssh_hostkey_check);
+ nc_callback_sshauth_interactive(netconf_callback_sshauth_interactive);
+ nc_callback_sshauth_password(netconf_callback_sshauth_password);
+ nc_callback_sshauth_passphrase(netconf_callback_sshauth_passphrase);
+ nc_callback_error_reply(netconf_callback_error_process);
- /* disable publickey authentication */
- nc_ssh_pref(NC_SSH_AUTH_PUBLIC_KEYS, -1);
+ /* disable publickey authentication */
+ nc_ssh_pref(NC_SSH_AUTH_PUBLIC_KEYS, -1);
- /* create mutex protecting session list */
- pthread_rwlockattr_init(&lock_attrs);
- /* rwlock is shared only with threads in this process */
- pthread_rwlockattr_setpshared(&lock_attrs, PTHREAD_PROCESS_PRIVATE);
- /* create rw lock */
- if (pthread_rwlock_init(&session_lock, &lock_attrs) != 0) {
- ERROR("Initialization of mutex failed: %d (%s)", errno, strerror(errno));
- goto error_exit;
- }
- pthread_mutex_init(&ntf_history_lock, NULL);
- pthread_mutex_init(&json_lock, NULL);
- DEBUG("Initialization of notification history.");
- if (pthread_key_create(¬if_history_key, NULL) != 0) {
- ERROR("Initialization of notification history failed.");
- }
- if (pthread_key_create(&err_reply_key, NULL) != 0) {
- ERROR("Initialization of reply key failed.");
- }
+ /* create mutex protecting session list */
+ pthread_rwlockattr_init(&lock_attrs);
+ /* rwlock is shared only with threads in this process */
+ pthread_rwlockattr_setpshared(&lock_attrs, PTHREAD_PROCESS_PRIVATE);
+ /* create rw lock */
+ if (pthread_rwlock_init(&session_lock, &lock_attrs) != 0) {
+ ERROR("Initialization of mutex failed: %d (%s)", errno, strerror(errno));
+ goto error_exit;
+ }
+ pthread_mutex_init(&ntf_history_lock, NULL);
+ pthread_mutex_init(&json_lock, NULL);
+ DEBUG("Initialization of notification history.");
+ if (pthread_key_create(¬if_history_key, NULL) != 0) {
+ ERROR("Initialization of notification history failed.");
+ }
+ if (pthread_key_create(&err_reply_key, NULL) != 0) {
+ ERROR("Initialization of reply key failed.");
+ }
- fcntl(lsock, F_SETFL, fcntl(lsock, F_GETFL, 0) | O_NONBLOCK);
- while (isterminated == 0) {
- gettimeofday(&tv, NULL);
- timediff = (unsigned int)tv.tv_sec - olds;
- #ifdef WITH_NOTIFICATIONS
- if (use_notifications == 1) {
- notification_handle();
- }
- #endif
- if (timediff > ACTIVITY_CHECK_INTERVAL) {
- check_timeout_and_close();
- }
+ fcntl(lsock, F_SETFL, fcntl(lsock, F_GETFL, 0) | O_NONBLOCK);
+ while (isterminated == 0) {
+ gettimeofday(&tv, NULL);
+ timediff = (unsigned int)tv.tv_sec - olds;
+ #ifdef WITH_NOTIFICATIONS
+ if (use_notifications == 1) {
+ notification_handle();
+ }
+ #endif
+ if (timediff > ACTIVITY_CHECK_INTERVAL) {
+ check_timeout_and_close();
+ }
- /* open incoming connection if any */
- len = sizeof(remote);
- client = accept(lsock, (struct sockaddr *) &remote, &len);
- if (client == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
- usleep(SLEEP_TIME * 1000);
- continue;
- } else if (client == -1 && (errno == EINTR)) {
- continue;
- } else if (client == -1) {
- ERROR("Accepting mod_netconf client connection failed (%s)", strerror(errno));
- continue;
- }
+ /* open incoming connection if any */
+ len = sizeof(remote);
+ client = accept(lsock, (struct sockaddr *) &remote, &len);
+ if (client == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ usleep(SLEEP_TIME * 1000);
+ continue;
+ } else if (client == -1 && (errno == EINTR)) {
+ continue;
+ } else if (client == -1) {
+ ERROR("Accepting mod_netconf client connection failed (%s)", strerror(errno));
+ continue;
+ }
- /* set client's socket as non-blocking */
- //fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) | O_NONBLOCK);
+ /* set client's socket as non-blocking */
+ //fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) | O_NONBLOCK);
- arg = malloc(sizeof(struct pass_to_thread));
- arg->client = client;
- arg->netconf_sessions_list = netconf_sessions_list;
+ arg = malloc(sizeof(struct pass_to_thread));
+ arg->client = client;
+ arg->netconf_sessions_list = netconf_sessions_list;
- /* start new thread. It will serve this particular request and then terminate */
- if ((ret = pthread_create (&ptids[pthread_count], NULL, thread_routine, (void*)arg)) != 0) {
- ERROR("Creating POSIX thread failed: %d\n", ret);
- } else {
- DEBUG("Thread %lu created", ptids[pthread_count]);
- pthread_count++;
- ptids = realloc (ptids, sizeof(pthread_t)*(pthread_count+1));
- ptids[pthread_count] = 0;
- }
+ /* start new thread. It will serve this particular request and then terminate */
+ if ((ret = pthread_create (&ptids[pthread_count], NULL, thread_routine, (void *)arg)) != 0) {
+ ERROR("Creating POSIX thread failed: %d\n", ret);
+ } else {
+ DEBUG("Thread %lu created", ptids[pthread_count]);
+ pthread_count++;
+ ptids = realloc (ptids, sizeof(pthread_t) * (pthread_count+1));
+ ptids[pthread_count] = 0;
+ }
- /* check if some thread already terminated, free some resources by joining it */
- for (i=0; i<pthread_count; i++) {
- if (pthread_tryjoin_np (ptids[i], (void**)&arg) == 0) {
- DEBUG("Thread %lu joined with retval %p", ptids[i], arg);
- pthread_count--;
- if (pthread_count > 0) {
- /* place last Thread ID on the place of joined one */
- ptids[i] = ptids[pthread_count];
- }
- }
- }
- DEBUG("Running %d threads", pthread_count);
- }
+ /* check if some thread already terminated, free some resources by joining it */
+ for (i = 0; i < pthread_count; i++) {
+ if (pthread_tryjoin_np(ptids[i], (void **)&arg) == 0) {
+ DEBUG("Thread %lu joined with retval %p", ptids[i], arg);
+ pthread_count--;
+ if (pthread_count > 0) {
+ /* place last Thread ID on the place of joined one */
+ ptids[i] = ptids[pthread_count];
+ }
+ }
+ }
+ DEBUG("Running %d threads", pthread_count);
+ }
- DEBUG("mod_netconf terminating...");
- /* join all threads */
- for (i=0; i<pthread_count; i++) {
- pthread_timedjoin_np (ptids[i], (void**)&arg, &maxtime);
- }
+ DEBUG("mod_netconf terminating...");
+ /* join all threads */
+ for (i = 0; i < pthread_count; i++) {
+ pthread_timedjoin_np(ptids[i], (void **)&arg, &maxtime);
+ }
- #ifdef WITH_NOTIFICATIONS
- notification_close();
- #endif
+ #ifdef WITH_NOTIFICATIONS
+ notification_close();
+ #endif
- /* close all NETCONF sessions */
- close_all_nc_sessions();
+ /* close all NETCONF sessions */
+ close_all_nc_sessions();
- /* destroy rwlock */
- pthread_rwlock_destroy(&session_lock);
- pthread_rwlockattr_destroy(&lock_attrs);
+ /* destroy rwlock */
+ pthread_rwlock_destroy(&session_lock);
+ pthread_rwlockattr_destroy(&lock_attrs);
- DEBUG("Exiting from the mod_netconf daemon");
+ DEBUG("Exiting from the mod_netconf daemon");
- free(ptids);
- close(lsock);
- exit(0);
- return;
+ free(ptids);
+ close(lsock);
+ exit(0);
+ return;
+
error_exit:
- close(lsock);
- free(ptids);
- return;
+ close(lsock);
+ free(ptids);
+ return;
}
-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
{
struct sigaction action;
sigset_t block_mask;
@@ -2414,14 +3346,14 @@
sockname = SOCKET_FILENAME;
}
- sigfillset (&block_mask);
+ sigfillset(&block_mask);
action.sa_handler = signal_handler;
action.sa_mask = block_mask;
action.sa_flags = 0;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
- forked_proc();
- DEBUG("Terminated");
- return 0;
+ forked_proc();
+ DEBUG("Terminated");
+ return 0;
}