Merge branch 'master' into devel
Conflicts:
.travis.yml
CMakeLists.txt
src/session.c
diff --git a/.travis.yml b/.travis.yml
index 01055c2..e5da833 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,4 +34,3 @@
after_success:
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$CC" = "gcc" ]; then codecov; fi
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8c5660a..915d307 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,8 +37,8 @@
# set version
set(LIBNETCONF2_MAJOR_VERSION 0)
-set(LIBNETCONF2_MINOR_VERSION 6)
-set(LIBNETCONF2_MICRO_VERSION 16)
+set(LIBNETCONF2_MINOR_VERSION 7)
+set(LIBNETCONF2_MICRO_VERSION 6)
set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION})
set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION})
diff --git a/src/io.c b/src/io.c
index c8b721a..e6cc293 100644
--- a/src/io.c
+++ b/src/io.c
@@ -577,6 +577,8 @@
return -1;
}
+ DBG("Session %u: sending message:\n%.*s", session->id, count, buf);
+
switch (session->ti_type) {
case NC_TI_NONE:
return -1;
diff --git a/src/messages_client.c b/src/messages_client.c
index 2b97401..cc0ecea 100644
--- a/src/messages_client.c
+++ b/src/messages_client.c
@@ -37,11 +37,11 @@
}
API struct nc_rpc *
-nc_rpc_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype)
+nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype)
{
- struct nc_rpc_generic *rpc;
+ struct nc_rpc_act_generic *rpc;
- if (!data || (data->schema->nodetype != LYS_RPC) || data->next || (data->prev != data)) {
+ if (!data || data->next || (data->prev != data)) {
ERRARG("data");
return NULL;
}
@@ -52,7 +52,7 @@
return NULL;
}
- rpc->type = NC_RPC_GENERIC;
+ rpc->type = NC_RPC_ACT_GENERIC;
rpc->has_data = 1;
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
rpc->content.data = lyd_dup(data, 1);
@@ -65,9 +65,9 @@
}
API struct nc_rpc *
-nc_rpc_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype)
+nc_rpc_act_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype)
{
- struct nc_rpc_generic *rpc;
+ struct nc_rpc_act_generic *rpc;
if (!xml_str) {
ERRARG("xml_str");
@@ -80,7 +80,7 @@
return NULL;
}
- rpc->type = NC_RPC_GENERIC;
+ rpc->type = NC_RPC_ACT_GENERIC;
rpc->has_data = 0;
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
rpc->content.xml_str = strdup(xml_str);
@@ -516,7 +516,7 @@
API void
nc_rpc_free(struct nc_rpc *rpc)
{
- struct nc_rpc_generic *rpc_generic;
+ struct nc_rpc_act_generic *rpc_generic;
struct nc_rpc_getconfig *rpc_getconfig;
struct nc_rpc_edit *rpc_edit;
struct nc_rpc_copy *rpc_copy;
@@ -533,8 +533,8 @@
}
switch (rpc->type) {
- case NC_RPC_GENERIC:
- rpc_generic = (struct nc_rpc_generic *)rpc;
+ case NC_RPC_ACT_GENERIC:
+ rpc_generic = (struct nc_rpc_act_generic *)rpc;
if (rpc_generic->free) {
if (rpc_generic->has_data) {
lyd_free(rpc_generic->content.data);
diff --git a/src/messages_client.h b/src/messages_client.h
index 6d5eca0..c3af824 100644
--- a/src/messages_client.h
+++ b/src/messages_client.h
@@ -25,7 +25,7 @@
*/
typedef enum {
NC_RPC_UNKNOWN = 0, /**< invalid RPC. */
- NC_RPC_GENERIC, /**< user-defined generic RPC. */
+ NC_RPC_ACT_GENERIC, /**< user-defined generic RPC/action. */
/* ietf-netconf */
NC_RPC_GETCONFIG, /**< \<get-config\> RPC. */
@@ -184,7 +184,7 @@
NC_RPC_TYPE nc_rpc_get_type(const struct nc_rpc *rpc);
/**
- * @brief Create a generic NETCONF RPC
+ * @brief Create a generic NETCONF RPC or action
*
* Note that created object can be sent via any NETCONF session that shares the context
* of the \p data.
@@ -193,10 +193,10 @@
* @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);
+struct nc_rpc *nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype);
/**
- * @brief Create a generic NETCONF RPC from an XML string
+ * @brief Create a generic NETCONF RPC or action 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
@@ -208,7 +208,7 @@
* @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);
+struct nc_rpc *nc_rpc_act_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype);
/**
* @brief Create NETCONF RPC \<get-config\>
diff --git a/src/messages_p.h b/src/messages_p.h
index 7a2d6d0..66e0546 100644
--- a/src/messages_p.h
+++ b/src/messages_p.h
@@ -78,8 +78,8 @@
NC_RPC_TYPE type;
};
-struct nc_rpc_generic {
- NC_RPC_TYPE type; /**< NC_RPC_GENERIC */
+struct nc_rpc_act_generic {
+ NC_RPC_TYPE type; /**< NC_RPC_ACT_GENERIC */
int has_data; /**< 1 for content.data, 0 for content.xml_str */
union {
struct lyd_node *data; /**< parsed RPC data */
diff --git a/src/session.c b/src/session.c
index ba55dbc..7eb08dd 100644
--- a/src/session.c
+++ b/src/session.c
@@ -516,10 +516,10 @@
nc_server_get_cpblts(struct ly_ctx *ctx)
{
struct lyd_node *child, *child2, *yanglib;
- struct lyd_node_leaf_list **features = NULL, *ns = NULL, *rev = NULL, *name = NULL;
+ struct lyd_node_leaf_list **features = NULL, **deviations = NULL, *ns = NULL, *rev = NULL, *name = NULL;
const char **cpblts;
const struct lys_module *mod;
- int size = 10, count, feat_count = 0, i, str_len;
+ int size = 10, count, feat_count = 0, dev_count = 0, i, str_len;
#define NC_CPBLT_BUF_LEN 512
char str[NC_CPBLT_BUF_LEN];
@@ -638,9 +638,18 @@
if (!features) {
ERRMEM;
free(cpblts);
+ free(deviations);
return NULL;
}
features[feat_count - 1] = (struct lyd_node_leaf_list *)child2;
+ } else if (!strcmp(child2->schema->name, "deviation")) {
+ deviations = nc_realloc(deviations, ++dev_count * sizeof *deviations);
+ if (!deviations) {
+ ERRMEM;
+ free(cpblts);
+ free(features);
+ return NULL;
+ }
}
}
@@ -667,15 +676,38 @@
str_len += strlen(features[i]->value_str);
}
}
+ if (dev_count) {
+ strcat(str, "&deviations=");
+ str_len += 12;
+ for (i = 0; i < dev_count; ++i) {
+ if (str_len + 1 + strlen(deviations[i]->value_str) >= NC_CPBLT_BUF_LEN) {
+ ERRINT;
+ break;
+ }
+ if (i) {
+ strcat(str, ",");
+ ++str_len;
+ }
+ strcat(str, deviations[i]->value_str);
+ str_len += strlen(deviations[i]->value_str);
+ }
+ }
add_cpblt(ctx, str, &cpblts, &size, &count);
ns = NULL;
name = NULL;
rev = NULL;
- free(features);
- features = NULL;
- feat_count = 0;
+ if (features || feat_count) {
+ free(features);
+ features = NULL;
+ feat_count = 0;
+ }
+ if (deviations || dev_count) {
+ free(deviations);
+ deviations = NULL;
+ dev_count = 0;
+ }
}
}
diff --git a/src/session_client.c b/src/session_client.c
index c048837..a3b7d85 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -191,8 +191,8 @@
}
static char *
-libyang_module_clb(const char *name, const char *revision, void *user_data, LYS_INFORMAT *format,
- void (**free_model_data)(void *model_data))
+libyang_module_clb(const char *mod_name, const char *mod_rev, const char *submod_name, const char *submod_rev,
+ void *user_data, LYS_INFORMAT *format, void (**free_model_data)(void *model_data))
{
struct nc_session *session = (struct nc_session *)user_data;
struct nc_rpc *rpc;
@@ -204,7 +204,11 @@
uint64_t msgid;
/* TODO later replace with yang to reduce model size? */
- rpc = nc_rpc_getschema(name, revision, "yin", NC_PARAMTYPE_CONST);
+ if (submod_name) {
+ rpc = nc_rpc_getschema(submod_name, submod_rev, "yin", NC_PARAMTYPE_CONST);
+ } else {
+ rpc = nc_rpc_getschema(mod_name, mod_rev, "yin", NC_PARAMTYPE_CONST);
+ }
*format = LYS_IN_YIN;
while ((msg = nc_send_rpc(session, rpc, 0, &msgid)) == NC_MSG_WOULDBLOCK) {
@@ -735,11 +739,11 @@
{
struct lyxml_elem *iter;
const struct lys_node *schema = NULL;
- struct lyd_node *data = NULL;
+ struct lyd_node *data = NULL, *next, *elem;
struct nc_client_reply_error *error_rpl;
struct nc_reply_data *data_rpl;
struct nc_reply *reply = NULL;
- struct nc_rpc_generic *rpc_gen;
+ struct nc_rpc_act_generic *rpc_gen;
int i;
if (!xml->child) {
@@ -803,22 +807,39 @@
/* some RPC output */
} else {
switch (rpc->type) {
- case NC_RPC_GENERIC:
- rpc_gen = (struct nc_rpc_generic *)rpc;
+ case NC_RPC_ACT_GENERIC:
+ rpc_gen = (struct nc_rpc_act_generic *)rpc;
if (rpc_gen->has_data) {
- schema = rpc_gen->content.data->schema;
+ data = rpc_gen->content.data;
} else {
data = lyd_parse_mem(ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC | parseroptions);
if (!data) {
- ERR("Failed to parse a generic RPC XML.");
+ ERR("Failed to parse a generic RPC/action XML.");
return NULL;
}
+ }
+ if (data->schema->nodetype == LYS_RPC) {
+ /* RPC */
schema = data->schema;
+ } else {
+ /* action */
+ LY_TREE_DFS_BEGIN(data, next, elem) {
+ if (elem->schema->nodetype == LYS_ACTION) {
+ schema = elem->schema;
+ break;
+ }
+ LY_TREE_DFS_END(data, next, elem);
+ }
+ }
+
+ /* cleanup */
+ if (data != rpc_gen->content.data) {
lyd_free(data);
data = NULL;
}
if (!schema) {
+ /* only with action, if there is no action, it should not have gotten this far */
ERRINT;
return NULL;
}
@@ -1278,7 +1299,7 @@
{
NC_MSG_TYPE r;
int ret;
- struct nc_rpc_generic *rpc_gen;
+ struct nc_rpc_act_generic *rpc_gen;
struct nc_rpc_getconfig *rpc_gc;
struct nc_rpc_edit *rpc_e;
struct nc_rpc_copy *rpc_cp;
@@ -1310,7 +1331,7 @@
return NC_MSG_ERROR;
}
- if ((rpc->type != NC_RPC_GETSCHEMA) && (rpc->type != NC_RPC_GENERIC) && (rpc->type != NC_RPC_SUBSCRIBE)) {
+ if ((rpc->type != NC_RPC_GETSCHEMA) && (rpc->type != NC_RPC_ACT_GENERIC) && (rpc->type != NC_RPC_SUBSCRIBE)) {
ietfnc = ly_ctx_get_module(session->ctx, "ietf-netconf", NULL);
if (!ietfnc) {
ERR("Session %u: missing ietf-netconf schema in the context.", session->id);
@@ -1319,8 +1340,8 @@
}
switch (rpc->type) {
- case NC_RPC_GENERIC:
- rpc_gen = (struct nc_rpc_generic *)rpc;
+ case NC_RPC_ACT_GENERIC:
+ rpc_gen = (struct nc_rpc_act_generic *)rpc;
if (rpc_gen->has_data) {
data = rpc_gen->content.data;
diff --git a/src/session_server.c b/src/session_server.c
index 1e15754..7744ede 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -923,6 +923,8 @@
{
nc_rpc_clb clb;
struct nc_server_reply *reply;
+ struct lys_node *rpc_act = NULL;
+ struct lyd_node *next, *elem;
int ret = 0, r;
if (!rpc) {
@@ -930,11 +932,29 @@
return NC_PSPOLL_ERROR;
}
- /* no callback, reply with a not-implemented error */
- if (!rpc->tree->schema->priv) {
+ if (rpc->tree->schema->nodetype == LYS_RPC) {
+ /* RPC */
+ rpc_act = rpc->tree->schema;
+ } else {
+ /* action */
+ LY_TREE_DFS_BEGIN(rpc->tree, next, elem) {
+ if (elem->schema->nodetype == LYS_ACTION) {
+ rpc_act = elem->schema;
+ break;
+ }
+ LY_TREE_DFS_END(rpc->tree, next, elem);
+ }
+ if (!rpc_act) {
+ ERRINT;
+ return NC_PSPOLL_ERROR;
+ }
+ }
+
+ if (!rpc_act->priv) {
+ /* no callback, reply with a not-implemented error */
reply = nc_server_reply_err(nc_err(NC_ERR_OP_NOT_SUPPORTED, NC_ERR_TYPE_PROT));
} else {
- clb = (nc_rpc_clb)rpc->tree->schema->priv;
+ clb = (nc_rpc_clb)rpc_act->priv;
reply = clb(rpc->tree, session);
}