messages CHANGE split to 3 groups of functions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f0b504d..1077da4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,8 @@
src/io.c
src/log.c
src/messages.c
+ src/messages_client.c
+ src/messages_server.c
src/session.c
src/session_client.c
src/session_server.c
@@ -61,7 +63,9 @@
src/session.h
src/session_client.h
src/session_server.h
- src/messages.h)
+ src/messages.h
+ src/messages_client.h
+ src/messages_server.h)
# libnetconf2 target
add_library(netconf2 SHARED ${libsrc})
diff --git a/nc_client.h.in b/nc_client.h.in
index 5d95439..531798c 100644
--- a/nc_client.h.in
+++ b/nc_client.h.in
@@ -29,6 +29,7 @@
#include <libnetconf2/netconf.h>
#include <libnetconf2/log.h>
#include <libnetconf2/messages.h>
+#include <libnetconf2/messages_client.h>
#include <libnetconf2/session_client.h>
#endif /* NC_CLIENT_H_ */
diff --git a/nc_server.h.in b/nc_server.h.in
index bc18da1..224e3f6 100644
--- a/nc_server.h.in
+++ b/nc_server.h.in
@@ -28,6 +28,8 @@
#include <libnetconf2/netconf.h>
#include <libnetconf2/log.h>
+#include <libnetconf2/messages.h>
+#include <libnetconf2/messages_server.h>
#include <libnetconf2/session_server.h>
#endif /* NC_SERVER_H_ */
diff --git a/src/messages.c b/src/messages.c
index 5cd4c0a..7e84e02 100644
--- a/src/messages.c
+++ b/src/messages.c
@@ -27,1070 +27,10 @@
#include <libyang/libyang.h>
-#include "libnetconf.h"
+#include "config.h"
+#include "messages.h"
#include "messages_p.h"
-const char *rpcedit_dfltop2str[] = {NULL, "merge", "replace", "none"};
-const char *rpcedit_testopt2str[] = {NULL, "test-then-set", "set", "test-only"};
-const char *rpcedit_erropt2str[] = {NULL, "stop-on-error", "continue-on-error", "rollback-on-error"};
-
-API NC_RPC_TYPE
-nc_rpc_get_type(const struct nc_rpc *rpc)
-{
- return rpc->type;
-}
-
-API struct nc_rpc *
-nc_rpc_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_generic *rpc;
-
- if (data->next || (data->prev != data)) {
- ERR("Generic RPC must have a single root node.");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_GENERIC;
- rpc->has_data = 1;
- if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
- rpc->content.data = lyd_dup(data, 1);
- } else {
- rpc->content.data = (struct lyd_node *)data;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_generic *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_GENERIC;
- rpc->has_data = 0;
- if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
- rpc->content.xml_str = strdup(xml_str);
- } else {
- rpc->content.xml_str = (char *)xml_str;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_getconfig *rpc;
-
- if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
- ERR("Filter must either be an XML subtree or an XPath expression.");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_GETCONFIG;
- rpc->source = source;
- if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->filter = strdup(filter);
- } else {
- rpc->filter = (char *)filter;
- }
- rpc->wd_mode = wd_mode;
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
- NC_RPC_EDIT_ERROPT error_opt, const char *edit_content, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_edit *rpc;
-
- if ((edit_content[0] != '<') && !isalpha(edit_content[0])) {
- ERR("<edit-config> content must either be a URL or a config (XML).");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_EDIT;
- rpc->target = target;
- rpc->default_op = default_op;
- rpc->test_opt = test_opt;
- rpc->error_opt = error_opt;
- if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
- rpc->edit_cont = strdup(edit_content);
- } else {
- rpc->edit_cont = (char *)edit_content;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const char *url_or_config_src,
- NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_copy *rpc;
-
- if (url_or_config_src && (url_or_config_src[0] != '<') && !isalpha(url_or_config_src[0])) {
- ERR("<copy-config> source is neither a URL nor a config (XML).");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_COPY;
- rpc->target = target;
- if (url_trg && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->url_trg = strdup(url_trg);
- } else {
- rpc->url_trg = (char *)url_trg;
- }
- rpc->source = source;
- if (url_or_config_src && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->url_config_src = strdup(url_or_config_src);
- } else {
- rpc->url_config_src = (char *)url_or_config_src;
- }
- rpc->wd_mode = wd_mode;
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_delete *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_DELETE;
- rpc->target = target;
- if (url && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->url = strdup(url);
- } else {
- rpc->url = (char *)url;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_lock(NC_DATASTORE target)
-{
- struct nc_rpc_lock *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_LOCK;
- rpc->target = target;
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_unlock(NC_DATASTORE target)
-{
- struct nc_rpc_lock *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_UNLOCK;
- rpc->target = target;
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_get *rpc;
-
- if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
- ERR("Filter must either be an XML subtree or an XPath expression.");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_GET;
- if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->filter = strdup(filter);
- } else {
- rpc->filter = (char *)filter;
- }
- rpc->wd_mode = wd_mode;
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_kill(uint32_t session_id)
-{
- struct nc_rpc_kill *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_KILL;
- rpc->sid = session_id;
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id,
- NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_commit *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_COMMIT;
- rpc->confirmed = confirmed;
- rpc->confirm_timeout = confirm_timeout;
- if (persist && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->persist = strdup(persist);
- } else {
- rpc->persist = (char *)persist;
- }
- if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->persist_id = strdup(persist_id);
- } else {
- rpc->persist_id = (char *)persist_id;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_discard(void)
-{
- struct nc_rpc *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_DISCARD;
-
- return rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_cancel *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_CANCEL;
- if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->persist_id = strdup(persist_id);
- } else {
- rpc->persist_id = (char *)persist_id;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_validate *rpc;
-
- if (url_or_config && (url_or_config[0] != '<') && !isalpha(url_or_config[0])) {
- ERR("<validate> source is neither a URL nor a config (XML).");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_VALIDATE;
- rpc->source = source;
- if (url_or_config && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->url_config_src = strdup(url_or_config);
- } else {
- rpc->url_config_src = (char *)url_or_config;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_getschema(const char *identifier, const char *version, const char *format, NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_getschema *rpc;
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_GETSCHEMA;
- if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
- rpc->identifier = strdup(identifier);
- } else {
- rpc->identifier = (char *)identifier;
- }
- if (version && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->version = strdup(version);
- } else {
- rpc->version = (char *)version;
- }
- if (format && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->format = strdup(format);
- } else {
- rpc->format = (char *)format;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_rpc *
-nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_time, const char *stop_time,
- NC_PARAMTYPE paramtype)
-{
- struct nc_rpc_subscribe *rpc;
-
- if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
- ERR("Filter must either be an XML subtree or an XPath expression.");
- return NULL;
- }
-
- rpc = malloc(sizeof *rpc);
- if (!rpc) {
- ERRMEM;
- return NULL;
- }
-
- rpc->type = NC_RPC_SUBSCRIBE;
- if (stream_name && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->stream = strdup(stream_name);
- } else {
- rpc->stream = (char *)stream_name;
- }
- if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->filter = strdup(filter);
- } else {
- rpc->filter = (char *)filter;
- }
- if (start_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->start = strdup(start_time);
- } else {
- rpc->start = (char *)start_time;
- }
- if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
- rpc->stop = strdup(stop_time);
- } else {
- rpc->stop = (char *)stop_time;
- }
- rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
-
- return (struct nc_rpc *)rpc;
-}
-
-API struct nc_server_reply *
-nc_server_reply_ok(void)
-{
- struct nc_server_reply *ret;
-
- ret = malloc(sizeof *ret);
- if (!ret) {
- ERRMEM;
- return NULL;
- }
-
- ret->type = NC_RPL_OK;
- return ret;
-}
-
-API struct nc_server_reply *
-nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype)
-{
- struct nc_server_reply_data *ret;
-
- if (!data) {
- ERRARG;
- return NULL;
- }
-
- ret = malloc(sizeof *ret);
- if (!ret) {
- ERRMEM;
- return NULL;
- }
-
- ret->type = NC_RPL_DATA;
- if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
- ret->data = lyd_dup(data, 1);
- } else {
- ret->data = data;
- }
- if (paramtype != NC_PARAMTYPE_CONST) {
- ret->free = 1;
- } else {
- ret->free = 0;
- }
- return (struct nc_server_reply *)ret;
-}
-
-API struct nc_server_reply *
-nc_server_reply_err(struct ly_ctx *ctx, struct nc_server_error *err)
-{
- struct nc_server_reply_error *ret;
-
- if (!ctx || !err) {
- ERRARG;
- return NULL;
- }
-
- ret = malloc(sizeof *ret);
- if (!ret) {
- ERRMEM;
- return NULL;
- }
-
- ret->type = NC_RPL_ERROR;
- ret->ctx = ctx;
- ret->err = malloc(sizeof *ret->err);
- ret->err[0] = err;
- ret->count = 1;
- return (struct nc_server_reply *)ret;
-}
-
-API int
-nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err)
-{
- struct nc_server_reply_error *err_rpl;
-
- if (!reply || (reply->type != NC_RPL_ERROR) || !err) {
- ERRARG;
- return -1;
- }
-
- err_rpl = (struct nc_server_reply_error *)reply;
- ++err_rpl->count;
- err_rpl->err = realloc(err_rpl->err, err_rpl->count * sizeof *err_rpl->err);
- err_rpl->err[err_rpl->count - 1] = err;
- return 0;
-}
-
-API struct nc_server_error *
-nc_err(struct ly_ctx *ctx, NC_ERR tag, ...)
-{
- va_list ap;
- struct nc_server_error *ret;
- NC_ERR_TYPE type;
- const char *arg1, *arg2;
- uint32_t sid;
-
- if (!ctx || !tag) {
- ERRARG;
- return NULL;
- }
-
- ret = calloc(1, sizeof *ret);
- if (!ret) {
- ERRMEM;
- return NULL;
- }
-
- va_start(ap, tag);
-
- switch (tag) {
- case NC_ERR_IN_USE:
- case NC_ERR_INVALID_VALUE:
- case NC_ERR_ACCESS_DENIED:
- case NC_ERR_ROLLBACK_FAILED:
- case NC_ERR_OP_NOT_SUPPORTED:
- type = va_arg(ap, NC_ERR_TYPE);
- if ((type != NC_ERR_TYPE_PROT) && (type == NC_ERR_TYPE_APP)) {
- goto fail;
- }
- break;
-
- case NC_ERR_TOO_BIG:
- case NC_ERR_RES_DENIED:
- type = va_arg(ap, NC_ERR_TYPE);
- /* nothing to check */
- break;
-
- case NC_ERR_MISSING_ATTR:
- case NC_ERR_BAD_ATTR:
- case NC_ERR_UNKNOWN_ATTR:
- type = va_arg(ap, NC_ERR_TYPE);
- arg1 = va_arg(ap, const char *);
- arg2 = va_arg(ap, const char *);
-
- if (type == NC_ERR_TYPE_TRAN) {
- goto fail;
- }
- nc_err_add_bad_attr(ctx, ret, arg1);
- nc_err_add_bad_elem(ctx, ret, arg2);
- break;
-
- case NC_ERR_MISSING_ELEM:
- case NC_ERR_BAD_ELEM:
- case NC_ERR_UNKNOWN_ELEM:
- type = va_arg(ap, NC_ERR_TYPE);
- arg1 = va_arg(ap, const char *);
-
- if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
- goto fail;
- }
- nc_err_add_bad_elem(ctx, ret, arg1);
- break;
-
- case NC_ERR_UNKNOWN_NS:
- type = va_arg(ap, NC_ERR_TYPE);
- arg1 = va_arg(ap, const char *);
- arg2 = va_arg(ap, const char *);
-
- if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
- goto fail;
- }
- nc_err_add_bad_elem(ctx, ret, arg1);
- nc_err_add_bad_ns(ctx, ret, arg2);
- break;
-
- case NC_ERR_LOCK_DENIED:
- sid = va_arg(ap, uint32_t);
-
- type = NC_ERR_TYPE_PROT;
- nc_err_set_sid(ret, sid);
- break;
-
- case NC_ERR_DATA_EXISTS:
- case NC_ERR_DATA_MISSING:
- type = NC_ERR_TYPE_APP;
- break;
-
- case NC_ERR_OP_FAILED:
- type = va_arg(ap, NC_ERR_TYPE);
-
- if (type == NC_ERR_TYPE_TRAN) {
- goto fail;
- }
- break;
-
- case NC_ERR_MALFORMED_MSG:
- type = NC_ERR_TYPE_RPC;
- break;
-
- default:
- goto fail;
- }
-
- switch (tag) {
- case NC_ERR_IN_USE:
- nc_err_set_msg(ctx, ret, "The request requires a resource that already is in use.", "en");
- break;
- case NC_ERR_INVALID_VALUE:
- nc_err_set_msg(ctx, ret, "The request specifies an unacceptable value for one or more parameters.", "en");
- break;
- case NC_ERR_TOO_BIG:
- nc_err_set_msg(ctx, ret, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
- break;
- case NC_ERR_MISSING_ATTR:
- nc_err_set_msg(ctx, ret, "An expected attribute is missing.", "en");
- break;
- case NC_ERR_BAD_ATTR:
- nc_err_set_msg(ctx, ret, "An attribute value is not correct.", "en");
- break;
- case NC_ERR_UNKNOWN_ATTR:
- nc_err_set_msg(ctx, ret, "An unexpected attribute is present.", "en");
- break;
- case NC_ERR_MISSING_ELEM:
- nc_err_set_msg(ctx, ret, "An expected element is missing.", "en");
- break;
- case NC_ERR_BAD_ELEM:
- nc_err_set_msg(ctx, ret, "An element value is not correct.", "en");
- break;
- case NC_ERR_UNKNOWN_ELEM:
- nc_err_set_msg(ctx, ret, "An unexpected element is present.", "en");
- break;
- case NC_ERR_UNKNOWN_NS:
- nc_err_set_msg(ctx, ret, "An unexpected namespace is present.", "en");
- break;
- case NC_ERR_ACCESS_DENIED:
- nc_err_set_msg(ctx, ret, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
- break;
- case NC_ERR_LOCK_DENIED:
- nc_err_set_msg(ctx, ret, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
- break;
- case NC_ERR_RES_DENIED:
- nc_err_set_msg(ctx, ret, "Request could not be completed because of insufficient resources.", "en");
- break;
- case NC_ERR_ROLLBACK_FAILED:
- nc_err_set_msg(ctx, ret, "Request to roll back some configuration change was not completed for some reason.", "en");
- break;
- case NC_ERR_DATA_EXISTS:
- nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content already exists.", "en");
- break;
- case NC_ERR_DATA_MISSING:
- nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content does not exist.", "en");
- break;
- case NC_ERR_OP_NOT_SUPPORTED:
- nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
- break;
- case NC_ERR_OP_FAILED:
- nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
- break;
- case NC_ERR_MALFORMED_MSG:
- nc_err_set_msg(ctx, ret, "A message could not be handled because it failed to be parsed correctly.", "en");
- break;
- default:
- goto fail;
- }
-
- va_end(ap);
-
- ret->type = type;
- ret->tag = tag;
- return ret;
-
-fail:
- ERRARG;
- free(ret);
- return NULL;
-}
-
-API int
-nc_err_set_app_tag(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_app_tag)
-{
- if (!ctx || !err || !error_app_tag) {
- ERRARG;
- return -1;
- }
-
- if (err->apptag) {
- lydict_remove(ctx, err->apptag);
- }
- err->apptag = lydict_insert(ctx, error_app_tag, 0);
- return 0;
-}
-
-API int
-nc_err_set_path(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_path)
-{
- if (!ctx || !err || !error_path) {
- ERRARG;
- return -1;
- }
-
- if (err->path) {
- lydict_remove(ctx, err->path);
- }
- err->path = lydict_insert(ctx, error_path, 0);
- return 0;
-}
-
-API int
-nc_err_set_msg(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_message, const char *lang)
-{
- if (!ctx || !err || !error_message) {
- ERRARG;
- return -1;
- }
-
- if (err->message) {
- lydict_remove(ctx, err->apptag);
- }
- err->message = lydict_insert(ctx, error_message, 0);
-
- if (err->message_lang) {
- lydict_remove(ctx, err->message_lang);
- }
- if (lang) {
- err->message_lang = lydict_insert(ctx, lang, 0);
- } else {
- lang = NULL;
- }
- return 0;
-}
-
-API int
-nc_err_set_sid(struct nc_server_error *err, uint32_t session_id)
-{
- if (!err) {
- ERRARG;
- return -1;
- }
-
- err->sid = session_id;
- return 0;
-}
-
-API int
-nc_err_add_bad_attr(struct ly_ctx *ctx, struct nc_server_error *err, const char *attr_name)
-{
- if (!ctx || !err || !attr_name) {
- ERRARG;
- return -1;
- }
-
- ++err->attr_count;
- err->attr = realloc(err->attr, err->attr_count * sizeof *err->attr);
- err->attr[err->attr_count - 1] = lydict_insert(ctx, attr_name, 0);
- return 0;
-}
-
-API int
-nc_err_add_bad_elem(struct ly_ctx *ctx, struct nc_server_error *err, const char *elem_name)
-{
- if (!ctx || !err || !elem_name) {
- ERRARG;
- return -1;
- }
-
- ++err->elem_count;
- err->elem = realloc(err->elem, err->elem_count * sizeof *err->elem);
- err->elem[err->elem_count - 1] = lydict_insert(ctx, elem_name, 0);
- return 0;
-}
-
-API int
-nc_err_add_bad_ns(struct ly_ctx *ctx, struct nc_server_error *err, const char *ns_name)
-{
- if (!ctx || !err || !ns_name) {
- ERRARG;
- return -1;
- }
-
- ++err->ns_count;
- err->ns = realloc(err->ns, err->ns_count * sizeof *err->ns);
- err->ns[err->ns_count - 1] = lydict_insert(ctx, ns_name, 0);
- return 0;
-}
-
-API int
-nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other)
-{
- if (!err || !other) {
- ERRARG;
- return -1;
- }
-
- ++err->other_count;
- err->other = realloc(err->other, err->other_count * sizeof *err->other);
- err->other[err->other_count - 1] = other;
- return 0;
-}
-
-void
-nc_server_rpc_free(struct nc_server_rpc *rpc)
-{
- lyxml_free(rpc->tree->schema->module->ctx, rpc->root);
- lyd_free(rpc->tree);
- free(rpc);
-}
-
-API void
-nc_server_reply_free(struct nc_server_reply *reply)
-{
- uint32_t i;
- struct nc_server_reply_data *data_rpl;
- struct nc_server_reply_error *error_rpl;
-
- if (!reply) {
- return;
- }
-
- switch (reply->type) {
- case NC_RPL_DATA:
- data_rpl = (struct nc_server_reply_data *)reply;
- if (data_rpl->free) {
- lyd_free_withsiblings(data_rpl->data);
- }
- break;
- case NC_RPL_OK:
- /* nothing to free */
- break;
- case NC_RPL_ERROR:
- error_rpl = (struct nc_server_reply_error *)reply;
- for (i = 0; i < error_rpl->count; ++i) {
- nc_err_free(error_rpl->ctx, error_rpl->err[i]);
- }
- free(error_rpl->err);
- break;
- default:
- break;
- }
- free(reply);
-}
-
-API void
-nc_err_free(struct ly_ctx *ctx, struct nc_server_error *err)
-{
- uint32_t i;
-
- if (!err) {
- ERRARG;
- return;
- }
-
- lydict_remove(ctx, err->apptag);
- lydict_remove(ctx, err->path);
- lydict_remove(ctx, err->message);
- lydict_remove(ctx, err->message_lang);
- for (i = 0; i < err->attr_count; ++i) {
- lydict_remove(ctx, err->attr[i]);
- }
- free(err->attr);
- for (i = 0; i < err->elem_count; ++i) {
- lydict_remove(ctx, err->elem[i]);
- }
- free(err->elem);
- for (i = 0; i < err->ns_count; ++i) {
- lydict_remove(ctx, err->ns[i]);
- }
- free(err->ns);
- for (i = 0; i < err->other_count; ++i) {
- lyxml_free(ctx, err->other[i]);
- }
- free(err->other);
- free(err);
-}
-
-API void
-nc_rpc_free(struct nc_rpc *rpc)
-{
- struct nc_rpc_generic *rpc_generic;
- struct nc_rpc_getconfig *rpc_getconfig;
- struct nc_rpc_edit *rpc_edit;
- struct nc_rpc_copy *rpc_copy;
- struct nc_rpc_delete *rpc_delete;
- struct nc_rpc_get *rpc_get;
- struct nc_rpc_commit *rpc_commit;
- struct nc_rpc_cancel *rpc_cancel;
- struct nc_rpc_validate *rpc_validate;
- struct nc_rpc_getschema *rpc_getschema;
- struct nc_rpc_subscribe *rpc_subscribe;
-
- if (!rpc) {
- return;
- }
-
- switch (rpc->type) {
- case NC_RPC_GENERIC:
- rpc_generic = (struct nc_rpc_generic *)rpc;
- if (rpc_generic->free) {
- if (rpc_generic->has_data) {
- lyd_free(rpc_generic->content.data);
- } else {
- free(rpc_generic->content.xml_str);
- }
- }
- break;
- case NC_RPC_GETCONFIG:
- rpc_getconfig = (struct nc_rpc_getconfig *)rpc;
- if (rpc_getconfig->free) {
- free(rpc_getconfig->filter);
- }
- break;
- case NC_RPC_EDIT:
- rpc_edit = (struct nc_rpc_edit *)rpc;
- if (rpc_edit->free) {
- free(rpc_edit->edit_cont);
- }
- break;
- case NC_RPC_COPY:
- rpc_copy = (struct nc_rpc_copy *)rpc;
- if (rpc_copy->free) {
- free(rpc_copy->url_config_src);
- }
- break;
- case NC_RPC_DELETE:
- rpc_delete = (struct nc_rpc_delete *)rpc;
- if (rpc_delete->free) {
- free(rpc_delete->url);
- }
- break;
- case NC_RPC_GET:
- rpc_get = (struct nc_rpc_get *)rpc;
- if (rpc_get->free) {
- free(rpc_get->filter);
- }
- break;
- case NC_RPC_COMMIT:
- rpc_commit = (struct nc_rpc_commit *)rpc;
- if (rpc_commit->free) {
- free(rpc_commit->persist);
- free(rpc_commit->persist_id);
- }
- break;
- case NC_RPC_CANCEL:
- rpc_cancel = (struct nc_rpc_cancel *)rpc;
- if (rpc_cancel->free) {
- free(rpc_cancel->persist_id);
- }
- break;
- case NC_RPC_VALIDATE:
- rpc_validate = (struct nc_rpc_validate *)rpc;
- if (rpc_validate->free) {
- free(rpc_validate->url_config_src);
- }
- break;
- case NC_RPC_GETSCHEMA:
- rpc_getschema = (struct nc_rpc_getschema *)rpc;
- if (rpc_getschema->free) {
- free(rpc_getschema->identifier);
- free(rpc_getschema->version);
- free(rpc_getschema->format);
- }
- break;
- case NC_RPC_SUBSCRIBE:
- rpc_subscribe = (struct nc_rpc_subscribe *)rpc;
- if (rpc_subscribe->free) {
- free(rpc_subscribe->stream);
- free(rpc_subscribe->filter);
- free(rpc_subscribe->start);
- free(rpc_subscribe->stop);
- }
- break;
- case NC_RPC_KILL:
- case NC_RPC_DISCARD:
- case NC_RPC_LOCK:
- case NC_RPC_UNLOCK:
- /* nothing special needed */
- break;
- }
-
- free(rpc);
-}
-
-API void
-nc_reply_free(struct nc_reply *reply)
-{
- struct nc_reply_error *error;
- struct nc_reply_data *data;
- uint32_t i, j;
-
- if (!reply) {
- return;
- }
-
- switch (reply->type) {
- case NC_RPL_DATA:
- data = (struct nc_reply_data *)reply;
- lyd_free_withsiblings(data->data);
- break;
-
- case NC_RPL_OK:
- /* nothing to free */
- break;
-
- case NC_RPL_ERROR:
- error = (struct nc_reply_error *)reply;
- for (i = 0; i < error->count; ++i) {
- lydict_remove(error->ctx, error->err[i].type);
- lydict_remove(error->ctx, error->err[i].tag);
- lydict_remove(error->ctx, error->err[i].severity);
- lydict_remove(error->ctx, error->err[i].apptag);
- lydict_remove(error->ctx, error->err[i].path);
- lydict_remove(error->ctx, error->err[i].message);
- lydict_remove(error->ctx, error->err[i].message_lang);
- lydict_remove(error->ctx, error->err[i].sid);
- for (j = 0; j < error->err[i].attr_count; ++j) {
- lydict_remove(error->ctx, error->err[i].attr[j]);
- }
- free(error->err[i].attr);
- for (j = 0; j < error->err[i].elem_count; ++j) {
- lydict_remove(error->ctx, error->err[i].elem[j]);
- }
- free(error->err[i].elem);
- for (j = 0; j < error->err[i].ns_count; ++j) {
- lydict_remove(error->ctx, error->err[i].ns[j]);
- }
- free(error->err[i].ns);
- for (j = 0; j < error->err[i].other_count; ++j) {
- lyxml_free(error->ctx, error->err[i].other[j]);
- }
- free(error->err[i].other);
- }
- free(error->err);
- break;
-
- case NC_RPL_NOTIF:
- nc_notif_free((struct nc_notif *)reply);
- break;
- }
-
- free(reply);
-}
-
API void
nc_notif_free(struct nc_notif *notif)
{
diff --git a/src/messages.h b/src/messages.h
index 9372944..027461f 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -1,6 +1,6 @@
/**
* \file messages.h
- * \author Radek Krejci <rkrejci@cesnet.cz>
+ * \author Michal Vasko <mvasko@cesnet.cz>
* \brief libnetconf2's public functions and structures of NETCONF messages.
*
* Copyright (c) 2015 CESNET, z.s.p.o.
@@ -23,64 +23,6 @@
#ifndef NC_MESSAGES_H_
#define NC_MESSAGES_H_
-#include <stdint.h>
-
-#include "netconf.h"
-
-typedef enum {
- NC_RPC_GENERIC, /**< user-defined generic RPC. */
-
- /* ietf-netconf */
- NC_RPC_GETCONFIG, /**< \<get-config\> RPC. */
- NC_RPC_EDIT, /**< \<edit-config\> RPC. */
- NC_RPC_COPY, /**< \<copy-config\> RPC. */
- NC_RPC_DELETE, /**< \<delete-config\> RPC. */
- NC_RPC_LOCK, /**< \<lock\> RPC. */
- NC_RPC_UNLOCK, /**< \<unlock\> RPC. */
- NC_RPC_GET, /**< \<get\> RPC. */
- /* NC_RPC_CLOSE is not defined since sending \<close-session\> is done by nc_session_free() */
- NC_RPC_KILL, /**< \<kill-session\> RPC. */
- NC_RPC_COMMIT, /**< \<commit\> RPC. */
- NC_RPC_DISCARD, /**< \<discard-changes\> RPC. */
- NC_RPC_CANCEL, /**< \<cancel-commit\> RPC. */
- NC_RPC_VALIDATE, /**< \<validate\> RPC. */
-
- /* ietf-netconf-monitoring */
- NC_RPC_GETSCHEMA, /**< \<get-schema\> RPC. */
-
- /* notifications */
- NC_RPC_SUBSCRIBE /**< \<create-subscription\> RPC. */
-} NC_RPC_TYPE;
-
-typedef enum {
- NC_RPC_EDIT_DFLTOP_UNKNOWN = 0,
- NC_RPC_EDIT_DFLTOP_MERGE,
- NC_RPC_EDIT_DFLTOP_REPLACE,
- NC_RPC_EDIT_DFLTOP_NONE
-} NC_RPC_EDIT_DFLTOP;
-
-typedef enum {
- NC_RPC_EDIT_TESTOPT_UNKNOWN = 0,
- NC_RPC_EDIT_TESTOPT_TESTSET,
- NC_RPC_EDIT_TESTOPT_SET,
- NC_RPC_EDIT_TESTOPT_TEST
-} NC_RPC_EDIT_TESTOPT;
-
-typedef enum {
- NC_RPC_EDIT_ERROPT_UNKNOWN = 0,
- NC_RPC_EDIT_ERROPT_STOP,
- NC_RPC_EDIT_ERROPT_CONTINUE,
- NC_RPC_EDIT_ERROPT_ROLLBACK
-} NC_RPC_EDIT_ERROPT;
-
-typedef enum {
- NC_WD_UNKNOWN = 0,
- NC_WD_ALL = 0x01,
- NC_WD_ALL_TAG = 0x02,
- NC_WD_TRIM = 0x04,
- NC_WD_EXPLICIT = 0x08
-} NC_WD_MODE;
-
typedef enum {
NC_PARAMTYPE_CONST,
NC_PARAMTYPE_FREE,
@@ -88,37 +30,6 @@
} NC_PARAMTYPE;
typedef enum {
- NC_ERR_UNKNOWN = 0,
- NC_ERR_IN_USE,
- NC_ERR_INVALID_VALUE,
- NC_ERR_TOO_BIG,
- NC_ERR_MISSING_ATTR,
- NC_ERR_BAD_ATTR,
- NC_ERR_UNKNOWN_ATTR,
- NC_ERR_MISSING_ELEM,
- NC_ERR_BAD_ELEM,
- NC_ERR_UNKNOWN_ELEM,
- NC_ERR_UNKNOWN_NS,
- NC_ERR_ACCESS_DENIED,
- NC_ERR_LOCK_DENIED,
- NC_ERR_RES_DENIED,
- NC_ERR_ROLLBACK_FAILED,
- NC_ERR_DATA_EXISTS,
- NC_ERR_DATA_MISSING,
- NC_ERR_OP_NOT_SUPPORTED,
- NC_ERR_OP_FAILED,
- NC_ERR_MALFORMED_MSG
-} NC_ERR;
-
-typedef enum {
- NC_ERR_TYPE_UNKNOWN = 0,
- NC_ERR_TYPE_TRAN,
- NC_ERR_TYPE_RPC,
- NC_ERR_TYPE_PROT,
- NC_ERR_TYPE_APP
-} NC_ERR_TYPE;
-
-typedef enum {
NC_RPL_OK,
NC_RPL_DATA,
NC_RPL_ERROR,
@@ -126,411 +37,11 @@
} NC_RPL;
/**
- * @brief NETCONF error structure representation
- */
-struct nc_err {
- /**
- * @brief \<error-type\>, error layer where the error occurred.
- */
- const char *type;
- /**
- * @brief \<error-tag\>.
- */
- const char *tag;
- /**
- * @brief \<error-severity\>.
- */
- const char *severity;
- /**
- * @brief \<error-app-tag\>, the data-model-specific or implementation-specific error condition, if one exists.
- */
- const char *apptag;
- /**
- * @brief \<error-path\>, XPATH expression identifying the element with the error.
- */
- const char *path;
- /**
- * @brief \<error-message\>, Human-readable description of the error.
- */
- const char *message;
- const char *message_lang;
-
- /* <error-info> */
-
- /**
- * @brief \<session-id\>, session ID of the session holding the requested lock.
- */
- const char *sid;
- /**
- * @brief \<bad-attr\>, the name of the data-model-specific XML attribute that caused the error.
- */
- const char **attr;
- uint16_t attr_count;
- /**
- * @brief \<bad-element\>, the name of the data-model-specific XML element that caused the error.
- */
- const char **elem;
- uint16_t elem_count;
- /**
- * @brief \<bad-namespace\>, the name of the unexpected XML namespace that caused the error.
- */
- const char **ns;
- uint16_t ns_count;
- /**
- * @brief Remaining non-standard elements.
- */
- struct lyxml_elem **other;
- uint16_t other_count;
-};
-
-/**
- * @brief NETCONF client RPC object
- */
-struct nc_rpc;
-
-struct nc_reply {
- NC_RPL type;
-};
-
-struct nc_reply_data {
- NC_RPL type; /**< NC_RPL_DATA */
- struct lyd_node *data; /**< libyang data tree */
-};
-
-struct nc_reply_error {
- NC_RPL type; /**< NC_RPL_ERROR */
- struct ly_ctx *ctx;
- struct nc_err *err; /**< errors, any of the values inside can be NULL */
- uint32_t count;
-};
-
-struct nc_notif {
- NC_RPL type; /**< NC_RPL_NOTIF */
- const char *datetime; /**< eventTime of the notification */
- struct lyd_node *tree; /**< libyang data tree of the message */
-};
-
-/**
- * @brief NETCONF server RPC reply object
- */
-struct nc_server_reply;
-
-struct nc_server_error;
-
-/**
* @brief NETCONF notification object
*/
struct nc_notif;
/**
- * @brief Get the type of the RPC
- *
- * @param[in] rpc RPC to check the type of.
- * @return Type of \p rpc.
- */
-NC_RPC_TYPE nc_rpc_get_type(const struct nc_rpc *rpc);
-
-/**
- * @brief Create a generic NETCONF RPC
- *
- * Note that created object can be sent via any NETCONF session that shares the context
- * of the \p data.
- *
- * @param[in] data NETCONF RPC data as a data tree.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create a generic NETCONF RPC from an XML string
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] xml_str NETCONF RPC data as an XML string.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<get-config\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] source Source datastore being queried.
- * @param[in] filter Optional filter data, an XML subtree or XPath expression.
- * @param[in] wd_mode Optional with-defaults capability mode.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode,
- NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<edit-config\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] target Target datastore being edited.
- * @param[in] default_op Optional default operation.
- * @param[in] test_opt Optional test option.
- * @param[in] error_opt Optional error option.
- * @param[in] edit_content Config or URL where the config to perform is to be found.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
- NC_RPC_EDIT_ERROPT error_opt, const char *edit_content, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<copy-config\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] target Target datastore.
- * @param[in] url_trg Used instead \p target if the target is an URL.
- * @param[in] source Source datastore.
- * @param[in] url_or_config_src Used instead \p source if the source is an URL or a config.
- * @param[in] wd_mode Optional with-defaults capability mode.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source,
- const char *url_or_config_src, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<delete-config\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] target Target datastore to delete.
- * @param[in] url Used instead \p target if the target is an URL.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<lock\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] target Target datastore of the operation.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_lock(NC_DATASTORE target);
-
-/**
- * @brief Create NETCONF RPC \<unlock\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] target Target datastore of the operation.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_unlock(NC_DATASTORE target);
-
-/**
- * @brief Create NETCONF RPC \<get\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] filter Optional filter data, an XML subtree or XPath expression.
- * @param[in] wd_mode Optional with-defaults capability mode.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<kill-session\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] session_id Session ID of the session to kill.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_kill(uint32_t session_id);
-
-/**
- * @brief Create NETCONF RPC \<commit\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] confirmed Whether the commit is to be confirmed.
- * @param[in] confirm_timeout Optional confirm timeout.
- * @param[in] persist Optional identification string of a new persistent confirmed commit.
- * @param[in] persist_id Optional identification string of a persistent confirmed commit to be commited.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id,
- NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<discard-changes\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_discard(void);
-
-/**
- * @brief Create NETCONF RPC \<cancel-commit\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] persist_id Optional identification string of a persistent confirmed commit.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<validate\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] source Source datastore being validated.
- * @param[in] url_or_config Usedn instead \p source if the source is an URL or a config.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<get-schema\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] identifier Requested model identifier.
- * @param[in] version Optional model version, either YANG version (1.0/1.1) or revision date.
- * @param[in] format Optional format of the model (default is YANG).
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_getschema(const char *identifier, const char *version, const char *format, NC_PARAMTYPE paramtype);
-
-/**
- * @brief Create NETCONF RPC \<create-subscription\>
- *
- * Note that functions to create any RPC object do not check validity of the provided
- * parameters. It is checked later while sending the RPC via a specific NETCONF session
- * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
- * check. Created object can be sent via any NETCONF session which supports all the
- * needed NETCONF capabilities for the RPC.
- *
- * @param[in] stream_name Optional name of a NETCONF stream to subscribe to.
- * @param[in] filter Optional filter data, an XML subtree or XPath expression.
- * @param[in] start_time Optional YANG datetime identifying the start of the subscription.
- * @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
- * @param[in] paramtype How to further manage data parameters.
- * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
- */
-struct nc_rpc *nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_time,
- const char *stop_time, NC_PARAMTYPE paramtype);
-
-struct nc_server_reply *nc_server_reply_ok(void);
-
-struct nc_server_reply *nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype);
-
-struct nc_server_reply *nc_server_reply_err(struct ly_ctx *ctx, struct nc_server_error *err);
-
-int nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err);
-
-struct nc_server_error *nc_err(struct ly_ctx *ctx, NC_ERR tag, ...);
-
-int nc_err_set_app_tag(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_app_tag);
-
-int nc_err_set_path(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_path);
-
-int nc_err_set_msg(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_message, const char *lang);
-
-int nc_err_set_sid(struct nc_server_error *err, uint32_t session_id);
-
-int nc_err_add_bad_attr(struct ly_ctx *ctx, struct nc_server_error *err, const char *attr_name);
-
-int nc_err_add_bad_elem(struct ly_ctx *ctx, struct nc_server_error *err, const char *elem_name);
-
-int nc_err_add_bad_ns(struct ly_ctx *ctx, struct nc_server_error *err, const char *ns_name);
-
-int nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other);
-
-/**
- * @brief Free the NETCONF RPC object.
- * @param[in] rpc Object to free.
- */
-void nc_rpc_free(struct nc_rpc *rpc);
-
-/**
- * @brief Free the NETCONF RPC reply object.
- * @param[in] rpc Object to free.
- */
-void nc_reply_free(struct nc_reply *reply);
-
-void nc_server_reply_free(struct nc_server_reply *reply);
-
-void nc_err_free(struct ly_ctx *ctx, struct nc_server_error *err);
-
-/**
* @brief Free the NETCONF Notification object.
* @param[in] rpc Object to free.
*/
diff --git a/src/messages_client.c b/src/messages_client.c
new file mode 100644
index 0000000..dfc7485
--- /dev/null
+++ b/src/messages_client.c
@@ -0,0 +1,629 @@
+/**
+ * \file messages.c
+ * \author Radek Krejci <rkrejci@cesnet.cz>
+ * \brief libnetconf2 - NETCONF messages functions
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <libyang/libyang.h>
+
+#include "libnetconf.h"
+#include "messages_p.h"
+
+const char *rpcedit_dfltop2str[] = {NULL, "merge", "replace", "none"};
+const char *rpcedit_testopt2str[] = {NULL, "test-then-set", "set", "test-only"};
+const char *rpcedit_erropt2str[] = {NULL, "stop-on-error", "continue-on-error", "rollback-on-error"};
+
+API NC_RPC_TYPE
+nc_rpc_get_type(const struct nc_rpc *rpc)
+{
+ return rpc->type;
+}
+
+API struct nc_rpc *
+nc_rpc_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_generic *rpc;
+
+ if (data->next || (data->prev != data)) {
+ ERR("Generic RPC must have a single root node.");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_GENERIC;
+ rpc->has_data = 1;
+ if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+ rpc->content.data = lyd_dup(data, 1);
+ } else {
+ rpc->content.data = (struct lyd_node *)data;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_generic *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_GENERIC;
+ rpc->has_data = 0;
+ if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+ rpc->content.xml_str = strdup(xml_str);
+ } else {
+ rpc->content.xml_str = (char *)xml_str;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_getconfig *rpc;
+
+ if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+ ERR("Filter must either be an XML subtree or an XPath expression.");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_GETCONFIG;
+ rpc->source = source;
+ if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->filter = strdup(filter);
+ } else {
+ rpc->filter = (char *)filter;
+ }
+ rpc->wd_mode = wd_mode;
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
+ NC_RPC_EDIT_ERROPT error_opt, const char *edit_content, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_edit *rpc;
+
+ if ((edit_content[0] != '<') && !isalpha(edit_content[0])) {
+ ERR("<edit-config> content must either be a URL or a config (XML).");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_EDIT;
+ rpc->target = target;
+ rpc->default_op = default_op;
+ rpc->test_opt = test_opt;
+ rpc->error_opt = error_opt;
+ if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+ rpc->edit_cont = strdup(edit_content);
+ } else {
+ rpc->edit_cont = (char *)edit_content;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const char *url_or_config_src,
+ NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_copy *rpc;
+
+ if (url_or_config_src && (url_or_config_src[0] != '<') && !isalpha(url_or_config_src[0])) {
+ ERR("<copy-config> source is neither a URL nor a config (XML).");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_COPY;
+ rpc->target = target;
+ if (url_trg && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->url_trg = strdup(url_trg);
+ } else {
+ rpc->url_trg = (char *)url_trg;
+ }
+ rpc->source = source;
+ if (url_or_config_src && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->url_config_src = strdup(url_or_config_src);
+ } else {
+ rpc->url_config_src = (char *)url_or_config_src;
+ }
+ rpc->wd_mode = wd_mode;
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_delete *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_DELETE;
+ rpc->target = target;
+ if (url && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->url = strdup(url);
+ } else {
+ rpc->url = (char *)url;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_lock(NC_DATASTORE target)
+{
+ struct nc_rpc_lock *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_LOCK;
+ rpc->target = target;
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_unlock(NC_DATASTORE target)
+{
+ struct nc_rpc_lock *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_UNLOCK;
+ rpc->target = target;
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_get *rpc;
+
+ if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+ ERR("Filter must either be an XML subtree or an XPath expression.");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_GET;
+ if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->filter = strdup(filter);
+ } else {
+ rpc->filter = (char *)filter;
+ }
+ rpc->wd_mode = wd_mode;
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_kill(uint32_t session_id)
+{
+ struct nc_rpc_kill *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_KILL;
+ rpc->sid = session_id;
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id,
+ NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_commit *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_COMMIT;
+ rpc->confirmed = confirmed;
+ rpc->confirm_timeout = confirm_timeout;
+ if (persist && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->persist = strdup(persist);
+ } else {
+ rpc->persist = (char *)persist;
+ }
+ if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->persist_id = strdup(persist_id);
+ } else {
+ rpc->persist_id = (char *)persist_id;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_discard(void)
+{
+ struct nc_rpc *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_DISCARD;
+
+ return rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_cancel *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_CANCEL;
+ if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->persist_id = strdup(persist_id);
+ } else {
+ rpc->persist_id = (char *)persist_id;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_validate *rpc;
+
+ if (url_or_config && (url_or_config[0] != '<') && !isalpha(url_or_config[0])) {
+ ERR("<validate> source is neither a URL nor a config (XML).");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_VALIDATE;
+ rpc->source = source;
+ if (url_or_config && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->url_config_src = strdup(url_or_config);
+ } else {
+ rpc->url_config_src = (char *)url_or_config;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_getschema(const char *identifier, const char *version, const char *format, NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_getschema *rpc;
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_GETSCHEMA;
+ if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+ rpc->identifier = strdup(identifier);
+ } else {
+ rpc->identifier = (char *)identifier;
+ }
+ if (version && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->version = strdup(version);
+ } else {
+ rpc->version = (char *)version;
+ }
+ if (format && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->format = strdup(format);
+ } else {
+ rpc->format = (char *)format;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_time, const char *stop_time,
+ NC_PARAMTYPE paramtype)
+{
+ struct nc_rpc_subscribe *rpc;
+
+ if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+ ERR("Filter must either be an XML subtree or an XPath expression.");
+ return NULL;
+ }
+
+ rpc = malloc(sizeof *rpc);
+ if (!rpc) {
+ ERRMEM;
+ return NULL;
+ }
+
+ rpc->type = NC_RPC_SUBSCRIBE;
+ if (stream_name && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->stream = strdup(stream_name);
+ } else {
+ rpc->stream = (char *)stream_name;
+ }
+ if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->filter = strdup(filter);
+ } else {
+ rpc->filter = (char *)filter;
+ }
+ if (start_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->start = strdup(start_time);
+ } else {
+ rpc->start = (char *)start_time;
+ }
+ if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+ rpc->stop = strdup(stop_time);
+ } else {
+ rpc->stop = (char *)stop_time;
+ }
+ rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+ return (struct nc_rpc *)rpc;
+}
+
+API void
+nc_rpc_free(struct nc_rpc *rpc)
+{
+ struct nc_rpc_generic *rpc_generic;
+ struct nc_rpc_getconfig *rpc_getconfig;
+ struct nc_rpc_edit *rpc_edit;
+ struct nc_rpc_copy *rpc_copy;
+ struct nc_rpc_delete *rpc_delete;
+ struct nc_rpc_get *rpc_get;
+ struct nc_rpc_commit *rpc_commit;
+ struct nc_rpc_cancel *rpc_cancel;
+ struct nc_rpc_validate *rpc_validate;
+ struct nc_rpc_getschema *rpc_getschema;
+ struct nc_rpc_subscribe *rpc_subscribe;
+
+ if (!rpc) {
+ return;
+ }
+
+ switch (rpc->type) {
+ case NC_RPC_GENERIC:
+ rpc_generic = (struct nc_rpc_generic *)rpc;
+ if (rpc_generic->free) {
+ if (rpc_generic->has_data) {
+ lyd_free(rpc_generic->content.data);
+ } else {
+ free(rpc_generic->content.xml_str);
+ }
+ }
+ break;
+ case NC_RPC_GETCONFIG:
+ rpc_getconfig = (struct nc_rpc_getconfig *)rpc;
+ if (rpc_getconfig->free) {
+ free(rpc_getconfig->filter);
+ }
+ break;
+ case NC_RPC_EDIT:
+ rpc_edit = (struct nc_rpc_edit *)rpc;
+ if (rpc_edit->free) {
+ free(rpc_edit->edit_cont);
+ }
+ break;
+ case NC_RPC_COPY:
+ rpc_copy = (struct nc_rpc_copy *)rpc;
+ if (rpc_copy->free) {
+ free(rpc_copy->url_config_src);
+ }
+ break;
+ case NC_RPC_DELETE:
+ rpc_delete = (struct nc_rpc_delete *)rpc;
+ if (rpc_delete->free) {
+ free(rpc_delete->url);
+ }
+ break;
+ case NC_RPC_GET:
+ rpc_get = (struct nc_rpc_get *)rpc;
+ if (rpc_get->free) {
+ free(rpc_get->filter);
+ }
+ break;
+ case NC_RPC_COMMIT:
+ rpc_commit = (struct nc_rpc_commit *)rpc;
+ if (rpc_commit->free) {
+ free(rpc_commit->persist);
+ free(rpc_commit->persist_id);
+ }
+ break;
+ case NC_RPC_CANCEL:
+ rpc_cancel = (struct nc_rpc_cancel *)rpc;
+ if (rpc_cancel->free) {
+ free(rpc_cancel->persist_id);
+ }
+ break;
+ case NC_RPC_VALIDATE:
+ rpc_validate = (struct nc_rpc_validate *)rpc;
+ if (rpc_validate->free) {
+ free(rpc_validate->url_config_src);
+ }
+ break;
+ case NC_RPC_GETSCHEMA:
+ rpc_getschema = (struct nc_rpc_getschema *)rpc;
+ if (rpc_getschema->free) {
+ free(rpc_getschema->identifier);
+ free(rpc_getschema->version);
+ free(rpc_getschema->format);
+ }
+ break;
+ case NC_RPC_SUBSCRIBE:
+ rpc_subscribe = (struct nc_rpc_subscribe *)rpc;
+ if (rpc_subscribe->free) {
+ free(rpc_subscribe->stream);
+ free(rpc_subscribe->filter);
+ free(rpc_subscribe->start);
+ free(rpc_subscribe->stop);
+ }
+ break;
+ case NC_RPC_KILL:
+ case NC_RPC_DISCARD:
+ case NC_RPC_LOCK:
+ case NC_RPC_UNLOCK:
+ /* nothing special needed */
+ break;
+ }
+
+ free(rpc);
+}
+
+API void
+nc_reply_free(struct nc_reply *reply)
+{
+ struct nc_reply_error *error;
+ struct nc_reply_data *data;
+ uint32_t i, j;
+
+ if (!reply) {
+ return;
+ }
+
+ switch (reply->type) {
+ case NC_RPL_DATA:
+ data = (struct nc_reply_data *)reply;
+ lyd_free_withsiblings(data->data);
+ break;
+
+ case NC_RPL_OK:
+ /* nothing to free */
+ break;
+
+ case NC_RPL_ERROR:
+ error = (struct nc_reply_error *)reply;
+ for (i = 0; i < error->count; ++i) {
+ lydict_remove(error->ctx, error->err[i].type);
+ lydict_remove(error->ctx, error->err[i].tag);
+ lydict_remove(error->ctx, error->err[i].severity);
+ lydict_remove(error->ctx, error->err[i].apptag);
+ lydict_remove(error->ctx, error->err[i].path);
+ lydict_remove(error->ctx, error->err[i].message);
+ lydict_remove(error->ctx, error->err[i].message_lang);
+ lydict_remove(error->ctx, error->err[i].sid);
+ for (j = 0; j < error->err[i].attr_count; ++j) {
+ lydict_remove(error->ctx, error->err[i].attr[j]);
+ }
+ free(error->err[i].attr);
+ for (j = 0; j < error->err[i].elem_count; ++j) {
+ lydict_remove(error->ctx, error->err[i].elem[j]);
+ }
+ free(error->err[i].elem);
+ for (j = 0; j < error->err[i].ns_count; ++j) {
+ lydict_remove(error->ctx, error->err[i].ns[j]);
+ }
+ free(error->err[i].ns);
+ for (j = 0; j < error->err[i].other_count; ++j) {
+ lyxml_free(error->ctx, error->err[i].other[j]);
+ }
+ free(error->err[i].other);
+ }
+ free(error->err);
+ break;
+
+ case NC_RPL_NOTIF:
+ nc_notif_free((struct nc_notif *)reply);
+ break;
+ }
+
+ free(reply);
+}
diff --git a/src/messages_client.h b/src/messages_client.h
new file mode 100644
index 0000000..517eb3d
--- /dev/null
+++ b/src/messages_client.h
@@ -0,0 +1,440 @@
+/**
+ * \file messages_client.h
+ * \author Radek Krejci <rkrejci@cesnet.cz>
+ * \author Michal Vasko <mvasko@cesnet.cz>
+ * \brief libnetconf2's public functions and structures of NETCONF client messages.
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ */
+
+#ifndef NC_MESSAGES_CLIENT_H_
+#define NC_MESSAGES_CLIENT_H_
+
+#include <stdint.h>
+
+#include "netconf.h"
+
+typedef enum {
+ NC_RPC_GENERIC, /**< user-defined generic RPC. */
+
+ /* ietf-netconf */
+ NC_RPC_GETCONFIG, /**< \<get-config\> RPC. */
+ NC_RPC_EDIT, /**< \<edit-config\> RPC. */
+ NC_RPC_COPY, /**< \<copy-config\> RPC. */
+ NC_RPC_DELETE, /**< \<delete-config\> RPC. */
+ NC_RPC_LOCK, /**< \<lock\> RPC. */
+ NC_RPC_UNLOCK, /**< \<unlock\> RPC. */
+ NC_RPC_GET, /**< \<get\> RPC. */
+ /* NC_RPC_CLOSE is not defined since sending \<close-session\> is done by nc_session_free() */
+ NC_RPC_KILL, /**< \<kill-session\> RPC. */
+ NC_RPC_COMMIT, /**< \<commit\> RPC. */
+ NC_RPC_DISCARD, /**< \<discard-changes\> RPC. */
+ NC_RPC_CANCEL, /**< \<cancel-commit\> RPC. */
+ NC_RPC_VALIDATE, /**< \<validate\> RPC. */
+
+ /* ietf-netconf-monitoring */
+ NC_RPC_GETSCHEMA, /**< \<get-schema\> RPC. */
+
+ /* notifications */
+ NC_RPC_SUBSCRIBE /**< \<create-subscription\> RPC. */
+} NC_RPC_TYPE;
+
+typedef enum {
+ NC_RPC_EDIT_DFLTOP_UNKNOWN = 0,
+ NC_RPC_EDIT_DFLTOP_MERGE,
+ NC_RPC_EDIT_DFLTOP_REPLACE,
+ NC_RPC_EDIT_DFLTOP_NONE
+} NC_RPC_EDIT_DFLTOP;
+
+typedef enum {
+ NC_RPC_EDIT_TESTOPT_UNKNOWN = 0,
+ NC_RPC_EDIT_TESTOPT_TESTSET,
+ NC_RPC_EDIT_TESTOPT_SET,
+ NC_RPC_EDIT_TESTOPT_TEST
+} NC_RPC_EDIT_TESTOPT;
+
+typedef enum {
+ NC_RPC_EDIT_ERROPT_UNKNOWN = 0,
+ NC_RPC_EDIT_ERROPT_STOP,
+ NC_RPC_EDIT_ERROPT_CONTINUE,
+ NC_RPC_EDIT_ERROPT_ROLLBACK
+} NC_RPC_EDIT_ERROPT;
+
+/**
+ * @brief NETCONF error structure representation
+ */
+struct nc_err {
+ /**
+ * @brief \<error-type\>, error layer where the error occurred.
+ */
+ const char *type;
+ /**
+ * @brief \<error-tag\>.
+ */
+ const char *tag;
+ /**
+ * @brief \<error-severity\>.
+ */
+ const char *severity;
+ /**
+ * @brief \<error-app-tag\>, the data-model-specific or implementation-specific error condition, if one exists.
+ */
+ const char *apptag;
+ /**
+ * @brief \<error-path\>, XPATH expression identifying the element with the error.
+ */
+ const char *path;
+ /**
+ * @brief \<error-message\>, Human-readable description of the error.
+ */
+ const char *message;
+ const char *message_lang;
+
+ /* <error-info> */
+
+ /**
+ * @brief \<session-id\>, session ID of the session holding the requested lock.
+ */
+ const char *sid;
+ /**
+ * @brief \<bad-attr\>, the name of the data-model-specific XML attribute that caused the error.
+ */
+ const char **attr;
+ uint16_t attr_count;
+ /**
+ * @brief \<bad-element\>, the name of the data-model-specific XML element that caused the error.
+ */
+ const char **elem;
+ uint16_t elem_count;
+ /**
+ * @brief \<bad-namespace\>, the name of the unexpected XML namespace that caused the error.
+ */
+ const char **ns;
+ uint16_t ns_count;
+ /**
+ * @brief Remaining non-standard elements.
+ */
+ struct lyxml_elem **other;
+ uint16_t other_count;
+};
+
+/**
+ * @brief NETCONF client RPC object
+ */
+struct nc_rpc;
+
+struct nc_reply {
+ NC_RPL type;
+};
+
+struct nc_reply_data {
+ NC_RPL type; /**< NC_RPL_DATA */
+ struct lyd_node *data; /**< libyang data tree */
+};
+
+struct nc_reply_error {
+ NC_RPL type; /**< NC_RPL_ERROR */
+ struct ly_ctx *ctx;
+ struct nc_err *err; /**< errors, any of the values inside can be NULL */
+ uint32_t count;
+};
+
+struct nc_notif {
+ NC_RPL type; /**< NC_RPL_NOTIF */
+ const char *datetime; /**< eventTime of the notification */
+ struct lyd_node *tree; /**< libyang data tree of the message */
+};
+
+/**
+ * @brief Get the type of the RPC
+ *
+ * @param[in] rpc RPC to check the type of.
+ * @return Type of \p rpc.
+ */
+NC_RPC_TYPE nc_rpc_get_type(const struct nc_rpc *rpc);
+
+/**
+ * @brief Create a generic NETCONF RPC
+ *
+ * Note that created object can be sent via any NETCONF session that shares the context
+ * of the \p data.
+ *
+ * @param[in] data NETCONF RPC data as a data tree.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create a generic NETCONF RPC from an XML string
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] xml_str NETCONF RPC data as an XML string.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<get-config\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] source Source datastore being queried.
+ * @param[in] filter Optional filter data, an XML subtree or XPath expression.
+ * @param[in] wd_mode Optional with-defaults capability mode.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode,
+ NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<edit-config\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] target Target datastore being edited.
+ * @param[in] default_op Optional default operation.
+ * @param[in] test_opt Optional test option.
+ * @param[in] error_opt Optional error option.
+ * @param[in] edit_content Config or URL where the config to perform is to be found.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
+ NC_RPC_EDIT_ERROPT error_opt, const char *edit_content, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<copy-config\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] target Target datastore.
+ * @param[in] url_trg Used instead \p target if the target is an URL.
+ * @param[in] source Source datastore.
+ * @param[in] url_or_config_src Used instead \p source if the source is an URL or a config.
+ * @param[in] wd_mode Optional with-defaults capability mode.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source,
+ const char *url_or_config_src, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<delete-config\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] target Target datastore to delete.
+ * @param[in] url Used instead \p target if the target is an URL.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<lock\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] target Target datastore of the operation.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_lock(NC_DATASTORE target);
+
+/**
+ * @brief Create NETCONF RPC \<unlock\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] target Target datastore of the operation.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_unlock(NC_DATASTORE target);
+
+/**
+ * @brief Create NETCONF RPC \<get\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] filter Optional filter data, an XML subtree or XPath expression.
+ * @param[in] wd_mode Optional with-defaults capability mode.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<kill-session\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] session_id Session ID of the session to kill.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_kill(uint32_t session_id);
+
+/**
+ * @brief Create NETCONF RPC \<commit\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] confirmed Whether the commit is to be confirmed.
+ * @param[in] confirm_timeout Optional confirm timeout.
+ * @param[in] persist Optional identification string of a new persistent confirmed commit.
+ * @param[in] persist_id Optional identification string of a persistent confirmed commit to be commited.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id,
+ NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<discard-changes\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_discard(void);
+
+/**
+ * @brief Create NETCONF RPC \<cancel-commit\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] persist_id Optional identification string of a persistent confirmed commit.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<validate\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] source Source datastore being validated.
+ * @param[in] url_or_config Usedn instead \p source if the source is an URL or a config.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<get-schema\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] identifier Requested model identifier.
+ * @param[in] version Optional model version, either YANG version (1.0/1.1) or revision date.
+ * @param[in] format Optional format of the model (default is YANG).
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_getschema(const char *identifier, const char *version, const char *format, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<create-subscription\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] stream_name Optional name of a NETCONF stream to subscribe to.
+ * @param[in] filter Optional filter data, an XML subtree or XPath expression.
+ * @param[in] start_time Optional YANG datetime identifying the start of the subscription.
+ * @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_time,
+ const char *stop_time, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Free the NETCONF RPC object.
+ * @param[in] rpc Object to free.
+ */
+void nc_rpc_free(struct nc_rpc *rpc);
+
+/**
+ * @brief Free the NETCONF RPC reply object.
+ * @param[in] rpc Object to free.
+ */
+void nc_reply_free(struct nc_reply *reply);
+
+#endif /* NC_MESSAGES_CLIENT_H_ */
diff --git a/src/messages_p.h b/src/messages_p.h
index 7aef57b..a5c690e 100644
--- a/src/messages_p.h
+++ b/src/messages_p.h
@@ -26,6 +26,8 @@
#include <libyang/libyang.h>
#include "messages.h"
+#include "messages_server.h"
+#include "messages_client.h"
extern const char *rpcedit_dfltop2str[];
extern const char *rpcedit_testopt2str[];
diff --git a/src/messages_server.c b/src/messages_server.c
new file mode 100644
index 0000000..0467483
--- /dev/null
+++ b/src/messages_server.c
@@ -0,0 +1,494 @@
+/**
+ * \file messages_server.c
+ * \author Michal Vasko <mvasko@cesnet.cz>
+ * \brief libnetconf2 - server NETCONF messages functions
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <libyang/libyang.h>
+
+#include "libnetconf.h"
+#include "messages_p.h"
+
+API struct nc_server_reply *
+nc_server_reply_ok(void)
+{
+ struct nc_server_reply *ret;
+
+ ret = malloc(sizeof *ret);
+ if (!ret) {
+ ERRMEM;
+ return NULL;
+ }
+
+ ret->type = NC_RPL_OK;
+ return ret;
+}
+
+API struct nc_server_reply *
+nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype)
+{
+ struct nc_server_reply_data *ret;
+
+ if (!data) {
+ ERRARG;
+ return NULL;
+ }
+
+ ret = malloc(sizeof *ret);
+ if (!ret) {
+ ERRMEM;
+ return NULL;
+ }
+
+ ret->type = NC_RPL_DATA;
+ if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+ ret->data = lyd_dup(data, 1);
+ } else {
+ ret->data = data;
+ }
+ if (paramtype != NC_PARAMTYPE_CONST) {
+ ret->free = 1;
+ } else {
+ ret->free = 0;
+ }
+ return (struct nc_server_reply *)ret;
+}
+
+API struct nc_server_reply *
+nc_server_reply_err(struct ly_ctx *ctx, struct nc_server_error *err)
+{
+ struct nc_server_reply_error *ret;
+
+ if (!ctx || !err) {
+ ERRARG;
+ return NULL;
+ }
+
+ ret = malloc(sizeof *ret);
+ if (!ret) {
+ ERRMEM;
+ return NULL;
+ }
+
+ ret->type = NC_RPL_ERROR;
+ ret->ctx = ctx;
+ ret->err = malloc(sizeof *ret->err);
+ ret->err[0] = err;
+ ret->count = 1;
+ return (struct nc_server_reply *)ret;
+}
+
+API int
+nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err)
+{
+ struct nc_server_reply_error *err_rpl;
+
+ if (!reply || (reply->type != NC_RPL_ERROR) || !err) {
+ ERRARG;
+ return -1;
+ }
+
+ err_rpl = (struct nc_server_reply_error *)reply;
+ ++err_rpl->count;
+ err_rpl->err = realloc(err_rpl->err, err_rpl->count * sizeof *err_rpl->err);
+ err_rpl->err[err_rpl->count - 1] = err;
+ return 0;
+}
+
+API struct nc_server_error *
+nc_err(struct ly_ctx *ctx, NC_ERR tag, ...)
+{
+ va_list ap;
+ struct nc_server_error *ret;
+ NC_ERR_TYPE type;
+ const char *arg1, *arg2;
+ uint32_t sid;
+
+ if (!ctx || !tag) {
+ ERRARG;
+ return NULL;
+ }
+
+ ret = calloc(1, sizeof *ret);
+ if (!ret) {
+ ERRMEM;
+ return NULL;
+ }
+
+ va_start(ap, tag);
+
+ switch (tag) {
+ case NC_ERR_IN_USE:
+ case NC_ERR_INVALID_VALUE:
+ case NC_ERR_ACCESS_DENIED:
+ case NC_ERR_ROLLBACK_FAILED:
+ case NC_ERR_OP_NOT_SUPPORTED:
+ type = va_arg(ap, NC_ERR_TYPE);
+ if ((type != NC_ERR_TYPE_PROT) && (type == NC_ERR_TYPE_APP)) {
+ goto fail;
+ }
+ break;
+
+ case NC_ERR_TOO_BIG:
+ case NC_ERR_RES_DENIED:
+ type = va_arg(ap, NC_ERR_TYPE);
+ /* nothing to check */
+ break;
+
+ case NC_ERR_MISSING_ATTR:
+ case NC_ERR_BAD_ATTR:
+ case NC_ERR_UNKNOWN_ATTR:
+ type = va_arg(ap, NC_ERR_TYPE);
+ arg1 = va_arg(ap, const char *);
+ arg2 = va_arg(ap, const char *);
+
+ if (type == NC_ERR_TYPE_TRAN) {
+ goto fail;
+ }
+ nc_err_add_bad_attr(ctx, ret, arg1);
+ nc_err_add_bad_elem(ctx, ret, arg2);
+ break;
+
+ case NC_ERR_MISSING_ELEM:
+ case NC_ERR_BAD_ELEM:
+ case NC_ERR_UNKNOWN_ELEM:
+ type = va_arg(ap, NC_ERR_TYPE);
+ arg1 = va_arg(ap, const char *);
+
+ if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
+ goto fail;
+ }
+ nc_err_add_bad_elem(ctx, ret, arg1);
+ break;
+
+ case NC_ERR_UNKNOWN_NS:
+ type = va_arg(ap, NC_ERR_TYPE);
+ arg1 = va_arg(ap, const char *);
+ arg2 = va_arg(ap, const char *);
+
+ if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
+ goto fail;
+ }
+ nc_err_add_bad_elem(ctx, ret, arg1);
+ nc_err_add_bad_ns(ctx, ret, arg2);
+ break;
+
+ case NC_ERR_LOCK_DENIED:
+ sid = va_arg(ap, uint32_t);
+
+ type = NC_ERR_TYPE_PROT;
+ nc_err_set_sid(ret, sid);
+ break;
+
+ case NC_ERR_DATA_EXISTS:
+ case NC_ERR_DATA_MISSING:
+ type = NC_ERR_TYPE_APP;
+ break;
+
+ case NC_ERR_OP_FAILED:
+ type = va_arg(ap, NC_ERR_TYPE);
+
+ if (type == NC_ERR_TYPE_TRAN) {
+ goto fail;
+ }
+ break;
+
+ case NC_ERR_MALFORMED_MSG:
+ type = NC_ERR_TYPE_RPC;
+ break;
+
+ default:
+ goto fail;
+ }
+
+ switch (tag) {
+ case NC_ERR_IN_USE:
+ nc_err_set_msg(ctx, ret, "The request requires a resource that already is in use.", "en");
+ break;
+ case NC_ERR_INVALID_VALUE:
+ nc_err_set_msg(ctx, ret, "The request specifies an unacceptable value for one or more parameters.", "en");
+ break;
+ case NC_ERR_TOO_BIG:
+ nc_err_set_msg(ctx, ret, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
+ break;
+ case NC_ERR_MISSING_ATTR:
+ nc_err_set_msg(ctx, ret, "An expected attribute is missing.", "en");
+ break;
+ case NC_ERR_BAD_ATTR:
+ nc_err_set_msg(ctx, ret, "An attribute value is not correct.", "en");
+ break;
+ case NC_ERR_UNKNOWN_ATTR:
+ nc_err_set_msg(ctx, ret, "An unexpected attribute is present.", "en");
+ break;
+ case NC_ERR_MISSING_ELEM:
+ nc_err_set_msg(ctx, ret, "An expected element is missing.", "en");
+ break;
+ case NC_ERR_BAD_ELEM:
+ nc_err_set_msg(ctx, ret, "An element value is not correct.", "en");
+ break;
+ case NC_ERR_UNKNOWN_ELEM:
+ nc_err_set_msg(ctx, ret, "An unexpected element is present.", "en");
+ break;
+ case NC_ERR_UNKNOWN_NS:
+ nc_err_set_msg(ctx, ret, "An unexpected namespace is present.", "en");
+ break;
+ case NC_ERR_ACCESS_DENIED:
+ nc_err_set_msg(ctx, ret, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
+ break;
+ case NC_ERR_LOCK_DENIED:
+ nc_err_set_msg(ctx, ret, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
+ break;
+ case NC_ERR_RES_DENIED:
+ nc_err_set_msg(ctx, ret, "Request could not be completed because of insufficient resources.", "en");
+ break;
+ case NC_ERR_ROLLBACK_FAILED:
+ nc_err_set_msg(ctx, ret, "Request to roll back some configuration change was not completed for some reason.", "en");
+ break;
+ case NC_ERR_DATA_EXISTS:
+ nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content already exists.", "en");
+ break;
+ case NC_ERR_DATA_MISSING:
+ nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content does not exist.", "en");
+ break;
+ case NC_ERR_OP_NOT_SUPPORTED:
+ nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
+ break;
+ case NC_ERR_OP_FAILED:
+ nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
+ break;
+ case NC_ERR_MALFORMED_MSG:
+ nc_err_set_msg(ctx, ret, "A message could not be handled because it failed to be parsed correctly.", "en");
+ break;
+ default:
+ goto fail;
+ }
+
+ va_end(ap);
+
+ ret->type = type;
+ ret->tag = tag;
+ return ret;
+
+fail:
+ ERRARG;
+ free(ret);
+ return NULL;
+}
+
+API int
+nc_err_set_app_tag(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_app_tag)
+{
+ if (!ctx || !err || !error_app_tag) {
+ ERRARG;
+ return -1;
+ }
+
+ if (err->apptag) {
+ lydict_remove(ctx, err->apptag);
+ }
+ err->apptag = lydict_insert(ctx, error_app_tag, 0);
+ return 0;
+}
+
+API int
+nc_err_set_path(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_path)
+{
+ if (!ctx || !err || !error_path) {
+ ERRARG;
+ return -1;
+ }
+
+ if (err->path) {
+ lydict_remove(ctx, err->path);
+ }
+ err->path = lydict_insert(ctx, error_path, 0);
+ return 0;
+}
+
+API int
+nc_err_set_msg(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_message, const char *lang)
+{
+ if (!ctx || !err || !error_message) {
+ ERRARG;
+ return -1;
+ }
+
+ if (err->message) {
+ lydict_remove(ctx, err->apptag);
+ }
+ err->message = lydict_insert(ctx, error_message, 0);
+
+ if (err->message_lang) {
+ lydict_remove(ctx, err->message_lang);
+ }
+ if (lang) {
+ err->message_lang = lydict_insert(ctx, lang, 0);
+ } else {
+ lang = NULL;
+ }
+ return 0;
+}
+
+API int
+nc_err_set_sid(struct nc_server_error *err, uint32_t session_id)
+{
+ if (!err || !session_id) {
+ ERRARG;
+ return -1;
+ }
+
+ err->sid = session_id;
+ return 0;
+}
+
+API int
+nc_err_add_bad_attr(struct ly_ctx *ctx, struct nc_server_error *err, const char *attr_name)
+{
+ if (!ctx || !err || !attr_name) {
+ ERRARG;
+ return -1;
+ }
+
+ ++err->attr_count;
+ err->attr = realloc(err->attr, err->attr_count * sizeof *err->attr);
+ err->attr[err->attr_count - 1] = lydict_insert(ctx, attr_name, 0);
+ return 0;
+}
+
+API int
+nc_err_add_bad_elem(struct ly_ctx *ctx, struct nc_server_error *err, const char *elem_name)
+{
+ if (!ctx || !err || !elem_name) {
+ ERRARG;
+ return -1;
+ }
+
+ ++err->elem_count;
+ err->elem = realloc(err->elem, err->elem_count * sizeof *err->elem);
+ err->elem[err->elem_count - 1] = lydict_insert(ctx, elem_name, 0);
+ return 0;
+}
+
+API int
+nc_err_add_bad_ns(struct ly_ctx *ctx, struct nc_server_error *err, const char *ns_name)
+{
+ if (!ctx || !err || !ns_name) {
+ ERRARG;
+ return -1;
+ }
+
+ ++err->ns_count;
+ err->ns = realloc(err->ns, err->ns_count * sizeof *err->ns);
+ err->ns[err->ns_count - 1] = lydict_insert(ctx, ns_name, 0);
+ return 0;
+}
+
+API int
+nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other)
+{
+ if (!err || !other) {
+ ERRARG;
+ return -1;
+ }
+
+ ++err->other_count;
+ err->other = realloc(err->other, err->other_count * sizeof *err->other);
+ err->other[err->other_count - 1] = other;
+ return 0;
+}
+
+void
+nc_server_rpc_free(struct nc_server_rpc *rpc)
+{
+ lyxml_free(rpc->tree->schema->module->ctx, rpc->root);
+ lyd_free(rpc->tree);
+ free(rpc);
+}
+
+API void
+nc_server_reply_free(struct nc_server_reply *reply)
+{
+ uint32_t i;
+ struct nc_server_reply_data *data_rpl;
+ struct nc_server_reply_error *error_rpl;
+
+ if (!reply) {
+ return;
+ }
+
+ switch (reply->type) {
+ case NC_RPL_DATA:
+ data_rpl = (struct nc_server_reply_data *)reply;
+ if (data_rpl->free) {
+ lyd_free_withsiblings(data_rpl->data);
+ }
+ break;
+ case NC_RPL_OK:
+ /* nothing to free */
+ break;
+ case NC_RPL_ERROR:
+ error_rpl = (struct nc_server_reply_error *)reply;
+ for (i = 0; i < error_rpl->count; ++i) {
+ nc_err_free(error_rpl->ctx, error_rpl->err[i]);
+ }
+ free(error_rpl->err);
+ break;
+ default:
+ break;
+ }
+ free(reply);
+}
+
+API void
+nc_err_free(struct ly_ctx *ctx, struct nc_server_error *err)
+{
+ uint32_t i;
+
+ if (!err) {
+ ERRARG;
+ return;
+ }
+
+ lydict_remove(ctx, err->apptag);
+ lydict_remove(ctx, err->path);
+ lydict_remove(ctx, err->message);
+ lydict_remove(ctx, err->message_lang);
+ for (i = 0; i < err->attr_count; ++i) {
+ lydict_remove(ctx, err->attr[i]);
+ }
+ free(err->attr);
+ for (i = 0; i < err->elem_count; ++i) {
+ lydict_remove(ctx, err->elem[i]);
+ }
+ free(err->elem);
+ for (i = 0; i < err->ns_count; ++i) {
+ lydict_remove(ctx, err->ns[i]);
+ }
+ free(err->ns);
+ for (i = 0; i < err->other_count; ++i) {
+ lyxml_free(ctx, err->other[i]);
+ }
+ free(err->other);
+ free(err);
+}
diff --git a/src/messages_server.h b/src/messages_server.h
new file mode 100644
index 0000000..017ea63
--- /dev/null
+++ b/src/messages_server.h
@@ -0,0 +1,98 @@
+/**
+ * \file messages_server.h
+ * \author Michal Vasko <mvasko@cesnet.cz>
+ * \brief libnetconf2's functions and structures of server NETCONF messages.
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ */
+
+#ifndef NC_MESSAGES_SERVER_H_
+#define NC_MESSAGES_SERVER_H_
+
+#include <stdint.h>
+
+#include "netconf.h"
+
+typedef enum {
+ NC_ERR_UNKNOWN = 0,
+ NC_ERR_IN_USE,
+ NC_ERR_INVALID_VALUE,
+ NC_ERR_TOO_BIG,
+ NC_ERR_MISSING_ATTR,
+ NC_ERR_BAD_ATTR,
+ NC_ERR_UNKNOWN_ATTR,
+ NC_ERR_MISSING_ELEM,
+ NC_ERR_BAD_ELEM,
+ NC_ERR_UNKNOWN_ELEM,
+ NC_ERR_UNKNOWN_NS,
+ NC_ERR_ACCESS_DENIED,
+ NC_ERR_LOCK_DENIED,
+ NC_ERR_RES_DENIED,
+ NC_ERR_ROLLBACK_FAILED,
+ NC_ERR_DATA_EXISTS,
+ NC_ERR_DATA_MISSING,
+ NC_ERR_OP_NOT_SUPPORTED,
+ NC_ERR_OP_FAILED,
+ NC_ERR_MALFORMED_MSG
+} NC_ERR;
+
+typedef enum {
+ NC_ERR_TYPE_UNKNOWN = 0,
+ NC_ERR_TYPE_TRAN,
+ NC_ERR_TYPE_RPC,
+ NC_ERR_TYPE_PROT,
+ NC_ERR_TYPE_APP
+} NC_ERR_TYPE;
+
+/**
+ * @brief NETCONF server RPC reply object
+ */
+struct nc_server_reply;
+
+struct nc_server_error;
+
+struct nc_server_reply *nc_server_reply_ok(void);
+
+struct nc_server_reply *nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype);
+
+struct nc_server_reply *nc_server_reply_err(struct ly_ctx *ctx, struct nc_server_error *err);
+
+int nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err);
+
+struct nc_server_error *nc_err(struct ly_ctx *ctx, NC_ERR tag, ...);
+
+int nc_err_set_app_tag(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_app_tag);
+
+int nc_err_set_path(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_path);
+
+int nc_err_set_msg(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_message, const char *lang);
+
+int nc_err_set_sid(struct nc_server_error *err, uint32_t session_id);
+
+int nc_err_add_bad_attr(struct ly_ctx *ctx, struct nc_server_error *err, const char *attr_name);
+
+int nc_err_add_bad_elem(struct ly_ctx *ctx, struct nc_server_error *err, const char *elem_name);
+
+int nc_err_add_bad_ns(struct ly_ctx *ctx, struct nc_server_error *err, const char *ns_name);
+
+int nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other);
+
+void nc_server_reply_free(struct nc_server_reply *reply);
+
+void nc_err_free(struct ly_ctx *ctx, struct nc_server_error *err);
+
+#endif /* NC_MESSAGES_SERVER_H_ */
diff --git a/src/netconf.h b/src/netconf.h
index b9cca31..c15d0ec 100644
--- a/src/netconf.h
+++ b/src/netconf.h
@@ -83,6 +83,14 @@
NC_DATASTORE_CANDIDATE /**< separated working datastore as defined in Candidate Configuration Capability */
} NC_DATASTORE;
+typedef enum NC_WITHDEFAULTS_MODE {
+ NC_WD_UNKNOWN = 0,
+ NC_WD_ALL = 0x01,
+ NC_WD_ALL_TAG = 0x02,
+ NC_WD_TRIM = 0x04,
+ NC_WD_EXPLICIT = 0x08
+} NC_WD_MODE;
+
/**
* @brief Transform given time_t (seconds since the epoch) into the RFC 3339 format
* accepted by NETCONF functions.
diff --git a/src/session_client.c b/src/session_client.c
index 71cd067..5f4fe1e 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -39,6 +39,7 @@
#include "session_client.h"
#include "libnetconf.h"
#include "messages_p.h"
+#include "messages_client.h"
static char *schema_searchpath = NULL;
diff --git a/src/session_client.h b/src/session_client.h
index 16a6c3b..f30403e 100644
--- a/src/session_client.h
+++ b/src/session_client.h
@@ -40,6 +40,7 @@
#include "session.h"
#include "netconf.h"
#include "messages.h"
+#include "messages_client.h"
/**
* @brief Set location where libnetconf tries to search for YANG/YIN schemas.
diff --git a/src/session_p.h b/src/session_p.h
index 466bfbd..ef8de16 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -27,7 +27,9 @@
#include <pthread.h>
#include <libyang/libyang.h>
+
#include "libnetconf.h"
+#include "netconf.h"
#include "session.h"
#include "messages.h"