diff --git a/CHANGELOG.md b/CHANGELOG.md
index fdb7ae89..8044c3b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,8 +26,6 @@
* The main example explains how to implement a Yang extension in a backend plugin.
### API changes on existing features (you may need to change your code)
-* New clixon-lib@2019-08-13.yang revision
- * Added new rpc: `get-state` to get only state info in the internal Restconf/backend communication
* Netconf edit-config "operation" attribute namespace check is enforced
* This is enforced: `
* This was previously allowed: `
@@ -49,6 +47,8 @@
* Other empty values remain as `null`
### Minor changes
+* Added experimental binary search API function: `xml_binsearch`
+* Added content parameter to `clicon_rpc_get` (-1 or CONTENT_ALL is default)
* Removed unnecessary configure dependencies
* libnsl, libcrypt, if_vlan,...
* pseudo-plugin added, to enable callbacks also for main programs. Useful for extensions
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index 1d532db1..c6b46b74 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -856,7 +856,7 @@ from_client_unlock(clicon_handle h,
* @retval 0 OK
* @retval -1 Error
*
- * @see from_client_get_config
+ * @see from_client_get_config
*/
static int
from_client_get(clicon_handle h,
@@ -875,6 +875,8 @@ from_client_get(clicon_handle h,
cxobj *xnacm = NULL;
char *username;
cvec *nsc = NULL; /* Create a netconf namespace context from filter */
+ char *attr;
+ netconf_content content = CONTENT_ALL;
username = clicon_username_get(h);
if ((xfilter = xml_find(xe, "filter")) != NULL){
@@ -888,24 +890,31 @@ from_client_get(clicon_handle h,
if (xml_nsctx_node(xfilter, &nsc) < 0)
goto done;
}
- /* Get config
- * Note xret can be pruned by nacm below and change name and
- * metrged with state data, so zero-copy cant be used
- * Also, must use external namespace context here due to
- * @param[out] cbret Return xml tree, eg ...,
- * The set of namespace declarations are those in scope on the
- * element.
- */
- else
- if (xml_nsctx_node(xfilter, &nsc) < 0)
- goto done;
- }
- /* Get state data from plugins as defined by plugin_statedata(), if any */
- clicon_err_reset();
- if ((ret = client_statedata(h, xpath, nsc, &xret)) < 0)
- goto done;
- if (ret == 0){ /* Error from callback (error in xret) */
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
- goto done;
- goto ok;
- }
- /* Pre-NACM access step */
- if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
- goto done;
- if (ret == 0){ /* Do NACM validation */
- if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
- goto done;
- /* NACM datanode/module read validation */
- if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
- goto done;
- }
- cprintf(cbret, ""); /* OK */
- if (xret==NULL)
- cprintf(cbret, "");
- else{
- if (xml_name_set(xret, "data") < 0)
- goto done;
- if (clicon_xml2cbuf(cbret, xret, 0, 0) < 0)
- goto done;
- }
- cprintf(cbret, "");
- ok:
- retval = 0;
- done:
- clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
- if (xnacm)
- xml_free(xnacm);
- if (xvec)
- free(xvec);
- if (nsc)
- xml_nsctx_free(nsc);
- if (xret)
- xml_free(xret);
- return retval;
-}
-
-
/*! Request graceful termination of a NETCONF session.
* @param[in] h Clicon handle
* @param[in] xe Request:
@@ -1512,9 +1433,6 @@ backend_rpc_init(clicon_handle h)
"urn:ietf:params:xml:ns:netmod:notification", "create-subscription") < 0)
goto done;
/* Clixon RPC */
- if (rpc_callback_register(h, from_client_get_state, NULL,
- "http://clicon.org/lib", "get-state") < 0)
- goto done;
if (rpc_callback_register(h, from_client_debug, NULL,
"http://clicon.org/lib", "debug") < 0)
goto done;
diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c
index 8be21f88..51285bba 100644
--- a/apps/cli/cli_show.c
+++ b/apps/cli/cli_show.c
@@ -472,7 +472,7 @@ cli_show_config1(clicon_handle h,
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
goto done;
}
- if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, &xt) < 0)
+ if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, CONTENT_ALL, &xt) < 0)
goto done;
}
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
@@ -723,7 +723,7 @@ cli_show_auto1(clicon_handle h,
clicon_err(OE_FATAL, 0, "Show state only for running database, not %s", db);
goto done;
}
- if (clicon_rpc_get(h, xpath, namespace, &xt) < 0)
+ if (clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, &xt) < 0)
goto done;
}
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index b4a245db..82db21a9 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -153,16 +153,6 @@ static const map_str2int http_media_map[] = {
{NULL, -1}
};
-/* See RFC 8040 4.8.1
- * @see query_content_str2int
- */
-static const map_str2int query_content_map[] = {
- {"config", CONTENT_CONFIG},
- {"nonconfig", CONTENT_NONCONFIG},
- {"all", CONTENT_ALL},
- {NULL, -1}
-};
-
int
restconf_err2code(char *tag)
{
@@ -187,18 +177,6 @@ restconf_media_int2str(restconf_media media)
return clicon_int2str(http_media_map, media);
}
-const query_content
-query_content_str2int(char *str)
-{
- return clicon_str2int(query_content_map, str);
-}
-
-const char *
-query_content_int2str(query_content nr)
-{
- return clicon_int2str(query_content_map, nr);
-}
-
/*! Return media_in from Content-Type, -1 if not found or unrecognized
* @note media-type syntax does not support parameters
* @see RFC7231 Sec 3.1.1.1 for media-type syntax type:
diff --git a/apps/restconf/restconf_lib.h b/apps/restconf/restconf_lib.h
index a7da11d5..6c4a2613 100644
--- a/apps/restconf/restconf_lib.h
+++ b/apps/restconf/restconf_lib.h
@@ -57,16 +57,6 @@ enum restconf_media{
};
typedef enum restconf_media restconf_media;
-/*! Content query parameter RFC 8040 Sec 4.8.1
- */
-enum query_content{
- CONTENT_CONFIG,
- CONTENT_NONCONFIG,
- CONTENT_ALL /* default */
-
-};
-typedef enum query_content query_content;
-
/*
* Prototypes (also in clixon_restconf.h)
*/
@@ -76,8 +66,6 @@ const char *restconf_code2reason(int code);
const restconf_media restconf_media_str2int(char *media);
const char *restconf_media_int2str(restconf_media media);
restconf_media restconf_content_type(FCGX_Request *r);
-const query_content query_content_str2int(char *str);
-const char *query_content_int2str(query_content nr);
int restconf_badrequest(FCGX_Request *r);
int restconf_unauthorized(FCGX_Request *r);
int restconf_forbidden(FCGX_Request *r);
diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c
index dc9f5918..3cba9b47 100644
--- a/apps/restconf/restconf_methods_get.c
+++ b/apps/restconf/restconf_methods_get.c
@@ -115,7 +115,7 @@ api_data_get2(clicon_handle h,
char *namespace = NULL;
cvec *nsc = NULL;
char *str;
- query_content content = CONTENT_ALL;
+ netconf_content content = CONTENT_ALL;
clicon_debug(1, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
@@ -125,7 +125,7 @@ api_data_get2(clicon_handle h,
/* Check for content attribute */
if ((str = cvec_find_str(qvec, "content")) != NULL){
clicon_debug(1, "%s content=%s", __FUNCTION__, str);
- if ((content = query_content_str2int(str)) == -1){
+ if ((content = netconf_content_str2int(str)) == -1){
if (netconf_bad_attribute_xml(&xerr, "application",
"content", "Unrecognized value of content attribute") < 0)
goto done;
@@ -168,10 +168,10 @@ api_data_get2(clicon_handle h,
ret = clicon_rpc_get_config(h, "running", xpath, namespace, &xret);
break;
case CONTENT_NONCONFIG:
- ret = clicon_rpc_get_state(h, xpath, namespace, &xret);
+ ret = clicon_rpc_get(h, xpath, namespace, CONTENT_NONCONFIG, &xret);
break;
case CONTENT_ALL:
- ret = clicon_rpc_get(h, xpath, namespace, &xret);
+ ret = clicon_rpc_get(h, xpath, namespace, CONTENT_ALL, &xret);
break;
default:
clicon_err(OE_XML, EINVAL, "Invalid content attribute %d", content);
diff --git a/lib/clixon/clixon.h.in b/lib/clixon/clixon.h.in
index c4170742..a13800fd 100644
--- a/lib/clixon/clixon.h.in
+++ b/lib/clixon/clixon.h.in
@@ -80,6 +80,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -90,7 +91,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h
index ccd9b528..8f662295 100644
--- a/lib/clixon/clixon_netconf_lib.h
+++ b/lib/clixon/clixon_netconf_lib.h
@@ -38,6 +38,20 @@
#ifndef _CLIXON_NETCONF_LIB_H
#define _CLIXON_NETCONF_LIB_H
+/*
+ * Types
+ */
+/*! Content query parameter RFC 8040 Sec 4.8.1
+ * Clixon extention: content so that RFC8040 content attribute can be conveyed
+ * internally used in
+ */
+enum netconf_content{
+ CONTENT_CONFIG, /* config data only */
+ CONTENT_NONCONFIG, /* state data only */
+ CONTENT_ALL /* default */
+};
+typedef enum netconf_content netconf_content;
+
/*
* Prototypes
*/
@@ -77,5 +91,7 @@ int netconf_module_features(clicon_handle h);
int netconf_module_load(clicon_handle h);
char *netconf_db_find(cxobj *xn, char *name);
int netconf_err2cb(cxobj *xerr, cbuf **cberr);
+const netconf_content netconf_content_str2int(char *str);
+const char *netconf_content_int2str(netconf_content nr);
#endif /* _CLIXON_NETCONF_LIB_H */
diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h
index d49d1314..d16615bf 100644
--- a/lib/clixon/clixon_proto_client.h
+++ b/lib/clixon/clixon_proto_client.h
@@ -52,8 +52,7 @@ int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
int clicon_rpc_delete_config(clicon_handle h, char *db);
int clicon_rpc_lock(clicon_handle h, char *db);
int clicon_rpc_unlock(clicon_handle h, char *db);
-int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, cxobj **xret);
-int clicon_rpc_get_state(clicon_handle h, char *xpath, char *namespace, cxobj **xret);
+int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, netconf_content content, cxobj **xret);
int clicon_rpc_close_session(clicon_handle h);
int clicon_rpc_kill_session(clicon_handle h, int session_id);
int clicon_rpc_validate(clicon_handle h, char *db);
diff --git a/lib/clixon/clixon_xml_sort.h b/lib/clixon/clixon_xml_sort.h
index 4c74cad7..b204a4bf 100644
--- a/lib/clixon/clixon_xml_sort.h
+++ b/lib/clixon/clixon_xml_sort.h
@@ -45,5 +45,6 @@ int xml_sort(cxobj *x0, void *arg);
int xml_insert(cxobj *xp, cxobj *xc, enum insert_type ins, char *key_val);
int xml_sort_verify(cxobj *x, void *arg);
int match_base_child(cxobj *x0, cxobj *x1c, yang_stmt *yc, cxobj **x0cp);
+cxobj *xml_binsearch(cxobj *xp, char *name, char *keyname, char *keyval);
#endif /* _CLIXON_XML_SORT_H */
diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c
index cb38c34d..85538586 100644
--- a/lib/src/clixon_data.c
+++ b/lib/src/clixon_data.c
@@ -216,7 +216,7 @@ clicon_conf_xml_set(clicon_handle h,
/*! Get authorized user name
* @param[in] h Clicon handle
- * @retval xh XMLDB storage handle. If not connected return NULL
+ * @retval username
*/
char *
clicon_username_get(clicon_handle h)
@@ -228,7 +228,7 @@ clicon_username_get(clicon_handle h)
/*! Set authorized user name
* @param[in] h Clicon handle
- * @param[in] xh XMLDB storage handle. If NULL reset it
+ * @param[in] username
* @note Just keep note of it, dont allocate it or so.
*/
int
diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c
index c237cc00..bf24e203 100644
--- a/lib/src/clixon_netconf_lib.c
+++ b/lib/src/clixon_netconf_lib.c
@@ -1375,3 +1375,25 @@ netconf_err2cb(cxobj *xerr,
done:
return retval;
}
+
+/* See RFC 8040 4.8.1
+ * @see netconf_content_str2int
+ */
+static const map_str2int netconf_content_map[] = {
+ {"config", CONTENT_CONFIG},
+ {"nonconfig", CONTENT_NONCONFIG},
+ {"all", CONTENT_ALL},
+ {NULL, -1}
+};
+
+const netconf_content
+netconf_content_str2int(char *str)
+{
+ return clicon_str2int(netconf_content_map, str);
+}
+
+const char *
+netconf_content_int2str(netconf_content nr)
+{
+ return clicon_int2str(netconf_content_map, nr);
+}
diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c
index 2cedc722..a7cfcf79 100644
--- a/lib/src/clixon_proto_client.c
+++ b/lib/src/clixon_proto_client.c
@@ -541,6 +541,7 @@ clicon_rpc_unlock(clicon_handle h,
* @param[in] h Clicon handle
* @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
* @param[in] namespace Namespace associated w xpath
+ * @param[in] content CLixon extension: all, config, noconfig. -1 means all
* @param[out] xt XML tree. Free with xml_free.
* Either or .
* @retval 0 OK
@@ -549,7 +550,7 @@ clicon_rpc_unlock(clicon_handle h,
* namespace will be used which is most probably wrong.
* @code
* cxobj *xt = NULL;
- * if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", &xt) < 0)
+ * if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", CONTENT_ALL, &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr);
@@ -558,13 +559,15 @@ clicon_rpc_unlock(clicon_handle h,
* if (xt)
* xml_free(xt);
* @endcode
+ * @see clicon_rpc_get_config which is almost the same as with content=config, but you can also select dbname
* @see clicon_rpc_generate_error
*/
int
-clicon_rpc_get(clicon_handle h,
- char *xpath,
- char *namespace,
- cxobj **xt)
+clicon_rpc_get(clicon_handle h,
+ char *xpath,
+ char *namespace,
+ netconf_content content,
+ cxobj **xt)
{
int retval = -1;
struct clicon_msg *msg = NULL;
@@ -580,7 +583,13 @@ clicon_rpc_get(clicon_handle h,
cprintf(cb, " username=\"%s\"", username);
if (namespace)
cprintf(cb, " xmlns:nc=\"%s\"", NETCONF_BASE_NAMESPACE);
- cprintf(cb, ">");
+ cprintf(cb, ">");
if (xpath && strlen(xpath)) {
if (namespace)
cprintf(cb, "",
@@ -615,85 +624,6 @@ clicon_rpc_get(clicon_handle h,
return retval;
}
-/*! Get database state data, clixon extension
- * @param[in] h Clicon handle
- * @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
- * @param[in] namespace Namespace associated w xpath
- * @param[out] xt XML tree. Free with xml_free.
- * Either or .
- * @retval 0 OK
- * @retval -1 Error, fatal or xml
- * @note if xpath is set but namespace is NULL, the default, netconf base
- * namespace will be used which is most probably wrong.
- * @code
- * cxobj *xt = NULL;
- * if (clicon_rpc_get_state(h, "/hello/world", "urn:example:hello", &xt) < 0)
- * err;
- * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
- * clicon_rpc_generate_error(xerr);
- * err;
- * }
- * if (xt)
- * xml_free(xt);
- * @endcode
- * @see clicon_rpc_generate_error
- */
-int
-clicon_rpc_get_state(clicon_handle h,
- char *xpath,
- char *namespace,
- cxobj **xt)
-{
- int retval = -1;
- struct clicon_msg *msg = NULL;
- cbuf *cb = NULL;
- cxobj *xret = NULL;
- cxobj *xd;
- char *username;
-
- if ((cb = cbuf_new()) == NULL)
- goto done;
- cprintf(cb, "");
- if (xpath && strlen(xpath)) {
- if (namespace)
- cprintf(cb, "",
- xpath, namespace);
- else /* If xpath != /, this will probably yield an error later */
- cprintf(cb, "", xpath);
- }
- cprintf(cb, "");
- if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
- goto done;
- if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
- goto done;
- /* Send xml error back: first check error, then ok */
- if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
- xd = xml_parent(xd); /* point to rpc-reply */
- else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
- if ((xd = xml_new("data", NULL, NULL)) == NULL)
- goto done;
- if (xt){
- if (xml_rm(xd) < 0)
- goto done;
- *xt = xd;
- }
- retval = 0;
- done:
- if (cb)
- cbuf_free(cb);
- if (xret)
- xml_free(xret);
- if (msg)
- free(msg);
- return retval;
-}
-
-
/*! Close a (user) session
* @param[in] h CLICON handle
* @retval 0 OK
diff --git a/lib/src/clixon_xml_sort.c b/lib/src/clixon_xml_sort.c
index 56454667..b79f0a81 100644
--- a/lib/src/clixon_xml_sort.c
+++ b/lib/src/clixon_xml_sort.c
@@ -401,10 +401,9 @@ xml_search_userorder(cxobj *xp,
/*!
* @param[in] xp Parent xml node.
+ * @param[in] x1 Find this object among xp:s children
+ * @param[in] userorder If x1 is ordered by user
* @param[in] yangi Yang order
- * @param[in] keynr Length of keyvec/keyval vector when applicable
- * @param[in] keyvec Array of of yang key identifiers
- * @param[in] keyval Array of of yang key values
* @param[in] low Lower bound of childvec search interval
* @param[in] upper Lower bound of childvec search interval
*/
@@ -447,10 +446,8 @@ xml_search1(cxobj *xp,
/*! Find XML child under xp matching x1 using binary search
* @param[in] xp Parent xml node.
- * @param[in] yangi Yang child order
- * @param[in] keynr Length of keyvec/keyval vector when applicable
- * @param[in] keyvec Array of of yang key identifiers
- * @param[in] keyval Array of of yang key values
+ * @param[in] x1 Find this object among xp:s children
+ * @param[in] yc Yang spec of x1
*/
static cxobj *
xml_search(cxobj *xp,
@@ -826,3 +823,37 @@ match_base_child(cxobj *x0,
return retval;
}
+/*! Experimental API for binary search
+ */
+cxobj *
+xml_binsearch(cxobj *xp,
+ char *name,
+ char *keyname,
+ char *keyval)
+{
+ cxobj *xc = NULL;
+ cxobj *xa = NULL;
+ cxobj *xret = NULL;
+ yang_stmt *yp;
+ yang_stmt *yc;
+
+ if ((yp = xml_spec(xp)) == NULL){
+ clicon_err(OE_YANG, ENOENT, "yang spec not found");
+ goto done;
+ }
+ if ((yc = yang_find(yp, 0, name)) == NULL){
+ clicon_err(OE_YANG, ENOENT, "yang not found");
+ goto done;
+ }
+ if ((xc = xml_new(name, xp, yc)) == NULL)
+ goto done;
+ if ((xa = xml_new(keyname, xc, NULL)) == NULL)
+ goto done;
+ if (xml_value_set(xa, keyval) < 0)
+ goto done;
+ xret = xml_search(xp, xc, yc);
+ done:
+ if (xc)
+ xml_free(xc);
+ return xret;
+}
diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh
index 3d5f2edf..d4b55b99 100755
--- a/test/test_restconf_jukebox.sh
+++ b/test/test_restconf_jukebox.sh
@@ -61,7 +61,7 @@ EOF
# Common Jukebox spec (fjukebox must be set)
. ./jukebox.sh
-new "test params: -f $cfg"
+new "test params: -f $cfg -- -s"
if [ $BE -ne 0 ]; then
new "kill old backend"
diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in
index 87d5e65b..c982ddc2 100644
--- a/yang/clixon/Makefile.in
+++ b/yang/clixon/Makefile.in
@@ -42,7 +42,7 @@ datarootdir = @datarootdir@
YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2019-06-05.yang
-YANGSPECS += clixon-lib@2019-08-13.yang
+YANGSPECS += clixon-lib@2019-06-05.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang
diff --git a/yang/clixon/clixon-lib@2019-08-13.yang b/yang/clixon/clixon-lib@2019-06-05.yang
similarity index 97%
rename from yang/clixon/clixon-lib@2019-08-13.yang
rename to yang/clixon/clixon-lib@2019-06-05.yang
index 343ca634..5c163870 100644
--- a/yang/clixon/clixon-lib@2019-08-13.yang
+++ b/yang/clixon/clixon-lib@2019-06-05.yang
@@ -52,6 +52,11 @@ module clixon-lib {
description
"Released in Clixon 3.9";
}
+ import ietf-netconf {
+ description "for the get-state extension";
+ prefix nc;
+ }
+
rpc debug {
description "Set debug level of backend.";
input {
@@ -92,5 +97,4 @@ module clixon-lib {
}
}
}
-
}