diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6fd5f4f..b6977be6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@
*:*
```
* logical combination of features not implemented, eg if-feature "not foo or bar and baz";
+ * ietf-netconf yang module added with candidate, validate, startup and xpath features enabled.
* YANG Module Library support
* According to RFC 7895 and implemented by ietf-yang-library.yang
* Changed Netconf hello to single capabilty urn:ietf:params:netconf:capability:yang-library:1.0 according to YANG 1.1 RFC7950 Sec 5.6.4.
@@ -32,7 +33,8 @@
### API changes on existing features (you may need to change your code)
* Netconf hello capability updated to YANG 1.1 RFC7950 Sec 5.6.4
- * A single capability is announced instead of many.
+ * Added urn:ietf:params:netconf:capability:yang-library:1.0
+ * Thanks SCadilhac for helping out, see https://github.com/clicon/clixon/issues/39
* Major rewrite of event streams
* If you used old event callbacks API, you need to switch to the streams API
* See clixon_stream.[ch]
@@ -72,8 +74,8 @@
goto done;
```
-
### Minor changes
+* uri_percent_encode() and xml_chardata_encode() changed to stdarg parameters
* Added CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml as option and in example (so you dont need to provide -f command-line option).
* Yang 1.1 action syntax added (but function is not supported)
* New function: clicon_conf_xml() returns configuration tree
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index efa705fe..391ecffd 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -751,6 +751,9 @@ main(int argc,
/* Load yang module library, RFC7895 */
if (yang_modules_init(h) < 0)
goto done;
+ /* Add netconf yang spec, used by netconf client and as internal protocol */
+ if (netconf_module_load(h) < 0)
+ goto done;
/* Load yang Restconf stream discovery */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_parse_module(h, "ietf-restconf-monitoring", CLIXON_DATADIR, NULL, yspec)< 0)
diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c
index c63b6e98..40f27d6e 100644
--- a/apps/cli/cli_main.c
+++ b/apps/cli/cli_main.c
@@ -432,6 +432,9 @@ main(int argc, char **argv)
clicon_yang_module_revision(h),
yspec) < 0)
goto done;
+ /* Load yang module library, RFC7895 */
+ if (yang_modules_init(h) < 0)
+ goto done;
if (printspec)
yang_print(stdout, (yang_node*)yspec);
diff --git a/apps/netconf/netconf_hello.c b/apps/netconf/netconf_hello.c
index 6343a299..61803c3b 100644
--- a/apps/netconf/netconf_hello.c
+++ b/apps/netconf/netconf_hello.c
@@ -106,12 +106,46 @@ netconf_hello_dispatch(cxobj *xn)
}
/*! Create Netconf hello. Single cap and defer individual to querying modules
- * This follows YANG 1.1 RFC7950 Sec 5.6.4, where a single capability announced
- * and a client may query supported modules using RFC 7895 (Yang Module
- * Library).
+
* @param[in] h Clicon handle
* @param[in] cb Msg buffer
* @param[in] session_id Id of client session
+ * Lots of dependencies here. regarding the hello protocol.
+ * RFC6241 NETCONF Protocol says: (8.1)
+ * MUST send a element containing a list of that peer's capabilities
+ * MUST send at least the base NETCONF capability, urn:ietf:params:netconf:base:1.1
+ * MAY include capabilities for previous NETCONF versions
+ * MUST include a
+ * the example shows urn:ietf:params:netconf:capability:startup:1.0
+
+ * RFC5277 NETCONF Event Notifications
+ * urn:ietf:params:netconf:capability:notification:1.0 is advertised during the capability exchange
+ *
+ * RFC6022 YANG Module for NETCONF Monitoring
+ * MUST advertise the capability URI "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
+ * RFC7895 Yang module library defines how to announce module features (not hell capabilities)
+ * RFC7950 YANG 1.1 says (5.6.4);
+ * MUST announce the modules it implements by implementing the YANG module
+ * "ietf-yang-library" (RFC7895) and listing all implemented modules in the
+ * "/modules-state/module" list.
+ * MUST advertise urn:ietf:params:netconf:capability:yang-library:1.0?
+ * revision=&module-set-id= in the message.
+ *
+ * Question: should the NETCONF in RFC6241 sections 8.2-8.9 be announced both
+ * as features and as capabilities in the message according to RFC6241?
+ * urn:ietf:params:netconf:capability:candidate:1:0 (8.3)
+ * urn:ietf:params:netconf:capability:validate:1.1 (8.6)
+ * urn:ietf:params:netconf:capability:startup:1.0 (8.7)
+ * urn:ietf:params:netconf:capability:xpath:1.0 (8.9)
+ * urn:ietf:params:netconf:capability:notification:1.0 (RFC5277)
+ *
+ * @note the hello message is created bythe netconf application, not the
+ * backend, and backend may implement more modules - please consider if using
+ * library routines for detecting capabilities here. In contrast, yang module
+ * list (RFC7895) is processed by the backend.
+ * @note encode bodies, see xml_chardata_encode()
+ * @see yang_modules_state_get
+ * @see netconf_module_load
*/
int
netconf_create_hello(clicon_handle h,
@@ -121,21 +155,27 @@ netconf_create_hello(clicon_handle h,
int retval = -1;
char *module_set_id;
char *ietf_yang_library_revision;
+ char *encstr = NULL;
module_set_id = clicon_option_str(h, "CLICON_MODULE_SET_ID");
if ((ietf_yang_library_revision = yang_modules_revision(h)) == NULL)
goto done;
add_preamble(cb);
- cprintf(cb, "");
+ cprintf(cb, "");
cprintf(cb, "");
- cprintf(cb, "urn:ietf:params:netconf:capability:yang-library:1.0?revision=\"%s\"&module-set-id=%s",
- ietf_yang_library_revision,
- module_set_id);
- cprintf(cb, "");
+ cprintf(cb, "urn:ietf:params:netconf:base:1.1");
+ if (xml_chardata_encode(&encstr, "urn:ietf:params:netconf:capability:yang-library:1.0?revision=\"%s\"&module-set-id=%s",
+ ietf_yang_library_revision,
+ module_set_id) < 0)
+ goto done;
+ cprintf(cb, "%s", encstr);
+ cprintf(cb, "");
cprintf(cb, "%lu", (long unsigned int)42+session_id);
cprintf(cb, "");
add_postamble(cb);
retval = 0;
done:
+ if (encstr)
+ free(encstr);
return retval;
}
diff --git a/apps/netconf/netconf_lib.c b/apps/netconf/netconf_lib.c
index 998b4ef0..fc24810b 100644
--- a/apps/netconf/netconf_lib.c
+++ b/apps/netconf/netconf_lib.c
@@ -182,6 +182,9 @@ netconf_get_target(cxobj *xn,
* @param[in] s
* @param[in] cb Cligen buffer that contains the XML message
* @param[in] msg Only for debug
+ * @note Assumes "cb" contains valid XML, ie encoding is correct. This is done
+ * if it is output by a xml render routine (xml_print et al), but NOT
+ * otherwise.
*/
int
netconf_output(int s,
diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c
index 7e7a279c..804902df 100644
--- a/apps/netconf/netconf_main.c
+++ b/apps/netconf/netconf_main.c
@@ -432,9 +432,11 @@ main(int argc,
argc -= optind;
argv += optind;
+ /* Create first yang spec */
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
+
/* Parse yang database spec file */
if (yang_filename){
if (yang_spec_parse_file(h, yang_filename, clicon_yang_dir(h), yspec) < 0)
@@ -446,10 +448,12 @@ main(int argc,
yspec) < 0)
goto done;
+ /* Load yang module library, RFC7895 */
+ if (yang_modules_init(h) < 0)
+ goto done;
/* Add netconf yang spec, used by netconf client and as internal protocol */
- if (yang_spec_parse_module(h, "ietf-yang-library", CLIXON_DATADIR, NULL, yspec)< 0)
- goto done;
-
+ if (netconf_module_load(h) < 0)
+ goto done;
/* Initialize plugins group */
if ((dir = clicon_netconf_dir(h)) != NULL)
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c
index aef61257..b107f6dd 100644
--- a/apps/restconf/restconf_main.c
+++ b/apps/restconf/restconf_main.c
@@ -635,6 +635,10 @@ main(int argc,
clicon_yang_module_revision(h),
yspec) < 0)
goto done;
+
+ /* Load yang module library, RFC7895 */
+ if (yang_modules_init(h) < 0)
+ goto done;
/* Add system modules */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_parse_module(h, "ietf-restconf-monitoring", CLIXON_DATADIR, NULL, yspec)< 0)
@@ -642,9 +646,7 @@ main(int argc,
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
yang_spec_parse_module(h, "ietf-netconf-notification", CLIXON_DATADIR, NULL, yspec)< 0)
goto done;
- /* Load yang module library, RFC7895 */
- if (yang_modules_init(h) < 0)
- goto done;
+
if (stream_register(h, "NETCONF", "default NETCONF event stream") < 0)
goto done;
diff --git a/datastore/keyvalue/clixon_keyvalue.c b/datastore/keyvalue/clixon_keyvalue.c
index 4e77418d..39a11134 100644
--- a/datastore/keyvalue/clixon_keyvalue.c
+++ b/datastore/keyvalue/clixon_keyvalue.c
@@ -211,7 +211,7 @@ append_listkeys(cbuf *ckey,
xml_name(xt), keyname);
goto done;
}
- if (uri_percent_encode(xml_body(xkey), &bodyenc) < 0)
+ if (uri_percent_encode(&bodyenc, "%s", xml_body(xkey)) < 0)
goto done;
if (i++)
cprintf(ckey, ",");
@@ -328,7 +328,7 @@ get(char *dbname,
* If xml element is a leaf-list, then the next element is expected to
* be a value
*/
- if (uri_percent_decode(restval, &argdec) < 0)
+ if (uri_percent_decode(&argdec, restval) < 0)
goto done;
if ((xc = xml_find(x, name))==NULL ||
(xb = xml_find(xc, argdec))==NULL){
@@ -681,7 +681,7 @@ put(char *dbfile,
goto done;
break;
case Y_LEAF_LIST:
- if (uri_percent_encode(body, &bodyenc) < 0)
+ if (uri_percent_encode(&bodyenc, "%s", body) < 0)
goto done;
cprintf(cbxk, "=%s", bodyenc);
break;
diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h
index 063345e3..cdf570e9 100644
--- a/lib/clixon/clixon_netconf_lib.h
+++ b/lib/clixon/clixon_netconf_lib.h
@@ -63,5 +63,6 @@ int netconf_operation_failed_xml(cxobj **xret, char *type, char *message);
int netconf_malformed_message(cbuf *cb, char *message);
int netconf_malformed_message_xml(cxobj **xret, char *message);
int netconf_trymerge(cxobj *x, yang_spec *yspec, cxobj **xret);
+int netconf_module_load(clicon_handle h);
#endif /* _CLIXON_NETCONF_LIB_H */
diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h
index 5b5789dd..cebb0871 100644
--- a/lib/clixon/clixon_string.h
+++ b/lib/clixon/clixon_string.h
@@ -76,9 +76,14 @@ static inline char * strdup4(char *str)
char **clicon_strsep(char *string, char *delim, int *nvec0);
char *clicon_strjoin (int argc, char **argv, char *delim);
int str2cvec(char *string, char delim1, char delim2, cvec **cvp);
-int uri_percent_encode(char *str, char **escp);
-int uri_percent_decode(char *esc, char **str);
-int xml_chardata_encode(char *str, char **escp);
+#if defined(__GNUC__) && __GNUC__ >= 3
+int uri_percent_encode(char **encp, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+int xml_chardata_encode(char **escp, char *fmt, ... ) __attribute__ ((format (printf, 2, 3)));
+#else
+int uri_percent_encode(char **encp, char *str, ...);
+int xml_chardata_encode(char **escp, char *fmt, ...);
+#endif
+int uri_percent_decode(char *enc, char **str);
const char *clicon_int2str(const map_str2int *mstab, int i);
int clicon_str2int(const map_str2int *mstab, char *str);
diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c
index d59e88c9..9c4f3dca 100644
--- a/lib/src/clixon_netconf_lib.c
+++ b/lib/src/clixon_netconf_lib.c
@@ -86,7 +86,7 @@ netconf_in_use(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -125,7 +125,7 @@ netconf_invalid_value(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -165,7 +165,7 @@ netconf_too_big(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -207,7 +207,7 @@ netconf_missing_attribute(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -248,7 +248,7 @@ netconf_bad_attribute(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -290,7 +290,7 @@ netconf_unknown_attribute(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -332,7 +332,7 @@ netconf_missing_element(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -375,7 +375,7 @@ netconf_bad_element(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -417,7 +417,7 @@ netconf_unknown_element(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -459,7 +459,7 @@ netconf_unknown_namespace(cbuf *cb,
type, info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -498,7 +498,7 @@ netconf_access_denied(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -574,7 +574,7 @@ netconf_lock_denied(cbuf *cb,
info) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -613,7 +613,7 @@ netconf_resource_denied(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -653,7 +653,7 @@ netconf_rollback_failed(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -691,7 +691,7 @@ netconf_data_exists(cbuf *cb,
"error") <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -729,7 +729,7 @@ netconf_data_missing(cbuf *cb,
"error") <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -769,7 +769,7 @@ netconf_operation_not_supported(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -809,7 +809,7 @@ netconf_operation_failed(cbuf *cb,
type) <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -884,7 +884,7 @@ netconf_malformed_message(cbuf *cb,
"error") <0)
goto err;
if (message){
- if (xml_chardata_encode(message, &encstr) < 0)
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (cprintf(cb, "%s", encstr) < 0)
goto err;
@@ -970,3 +970,40 @@ netconf_trymerge(cxobj *x,
free(reason);
return retval;
}
+
+/*! Load ietf netconf yang module and set enabled features
+ * The features added are:
+ * candidate (8.3)
+ * validate (8.6)
+ * startup (8.7)
+ * xpath (8.9)
+ */
+int
+netconf_module_load(clicon_handle h)
+{
+ int retval = -1;
+ cxobj *xc;
+ // cxobj *x;
+ yang_spec *yspec;
+
+ yspec = clicon_dbspec_yang(h);
+ /* Load yang spec */
+ if (yang_spec_parse_module(h, "ietf-netconf", CLIXON_DATADIR, NULL, yspec)< 0)
+ goto done;
+ if ((xc = clicon_conf_xml(h)) == NULL){
+ clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");
+ goto done;
+ }
+ /* Enable features (hardcoded here) */
+ if (xml_parse_string("ietf-netconf:candidate", yspec, &xc) < 0)
+ goto done;
+ if (xml_parse_string("ietf-netconf:validate", yspec, &xc) < 0)
+ goto done;
+ if (xml_parse_string("ietf-netconf:startup", yspec, &xc) < 0)
+ goto done;
+ if (xml_parse_string("ietf-netconf:xpath", yspec, &xc) < 0)
+ goto done;
+ retval = 0;
+ done:
+ return retval;
+}
diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c
index 1c0584d9..9fb9e3af 100644
--- a/lib/src/clixon_options.c
+++ b/lib/src/clixon_options.c
@@ -249,8 +249,10 @@ clicon_options_main(clicon_handle h)
xml_child_sort = 0;
retval = 0;
done:
- if (yspec) /* The clixon yang-spec is not used after this */
+#if 0 /* XXX yspec should be part of top-level yang but cant since it will be main module */
+ if (yspec)
yspec_free(yspec);
+#endif
return retval;
}
@@ -589,6 +591,7 @@ clicon_dbspec_yang_set(clicon_handle h,
/*! Get YANG specification for Clixon system options and features
* Must use hash functions directly since they are not strings.
+ * Example: features are typically accessed directly in the config tree.
*/
cxobj *
clicon_conf_xml(clicon_handle h)
diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c
index 655bc9f1..0b0f73dd 100644
--- a/lib/src/clixon_string.c
+++ b/lib/src/clixon_string.c
@@ -174,49 +174,77 @@ uri_unreserved(unsigned char in)
}
/*! Percent encoding according to RFC 3986 URI Syntax
- * @param[in] str Not-encoded input string
- * @param[out] escp Encoded/escaped malloced output string
+ * @param[out] encp Encoded malloced output string
+ * @param[in] fmt Not-encoded input string (stdarg format string)
+ * @param[in] ... stdarg variable parameters
* @retval 0 OK
* @retval -1 Error
+ * @code
+ * char *enc;
+ * if (uri_percent_encode(&enc, "formatstr: <>= %s", "substr<>") < 0)
+ * err;
+ * if(enc)
+ * free(enc);
+ * @endcode
* @see RFC 3986 Uniform Resource Identifier (URI): Generic Syntax
* @see uri_percent_decode
* @see xml_chardata_encode
*/
int
-uri_percent_encode(char *str,
- char **escp)
+uri_percent_encode(char **encp,
+ char *fmt, ...)
{
- int retval = -1;
- char *esc = NULL;
- int len;
- int i, j;
-
+ int retval = -1;
+ char *str = NULL; /* Expanded format string w stdarg */
+ char *enc = NULL;
+ int fmtlen;
+ int len;
+ int i, j;
+ va_list args;
+
+ /* Two steps: (1) read in the complete format string */
+ va_start(args, fmt); /* dryrun */
+ fmtlen = vsnprintf(NULL, 0, fmt, args) + 1;
+ va_end(args);
+ if ((str = malloc(fmtlen)) == NULL){
+ clicon_err(OE_UNIX, errno, "malloc");
+ goto done;
+ }
+ memset(str, 0, fmtlen);
+ va_start(args, fmt); /* real */
+ fmtlen = vsnprintf(str, fmtlen, fmt, args) + 1;
+ va_end(args);
+ /* Now str is the combined fmt + ... */
+
+ /* Step (2) encode and expand str --> enc */
/* This is max */
len = strlen(str)*3+1;
- if ((esc = malloc(len)) == NULL){
+ if ((enc = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
- memset(esc, 0, len);
+ memset(enc, 0, len);
j = 0;
for (i=0; i 2 &&
- isxdigit(esc[i+1]) && isxdigit(esc[i+2])){
- hstr[0] = esc[i+1];
- hstr[1] = esc[i+2];
+ for (i=0; i 2 &&
+ isxdigit(enc[i+1]) && isxdigit(enc[i+2])){
+ hstr[0] = enc[i+1];
+ hstr[1] = enc[i+2];
hstr[2] = 0;
str[j] = strtoul(hstr, &ptr, 16);
i += 2;
}
else
- str[j] = esc[i];
+ str[j] = enc[i];
j++;
}
str[j++] = '\0';
@@ -265,8 +293,9 @@ uri_percent_decode(char *esc,
}
/*! Escape characters according to XML definition
- * @param[in] str Not-encoded input string
- * @param[out] escp Encoded/escaped malloced output string
+ * @param[out] encp Encoded malloced output string
+ * @param[in] fmt Not-encoded input string (stdarg format string)
+ * @param[in] ... stdarg variable parameters
* @retval 0 OK
* @retval -1 Error
* @see https://www.w3.org/TR/2008/REC-xml-20081126/#syntax chapter 2.6
@@ -274,8 +303,7 @@ uri_percent_decode(char *esc,
* @see AMPERSAND mode in clixon_xml_parse.l
* @code
* char *encstr = NULL;
- * char *val = "a<>b";
- * if (xml_chardata_encode(str, &encstr) < 0)
+ * if (xml_chardata_encode(&encstr, "fmtstr<>& %s", "substr<>") < 0)
* err;
* if (encstr)
* free(encstr);
@@ -289,16 +317,34 @@ uri_percent_decode(char *esc,
* Optionally >
*/
int
-xml_chardata_encode(char *str,
- char **escp)
+xml_chardata_encode(char **escp,
+ char *fmt,...)
{
- int retval = -1;
- char *esc = NULL;
- int l;
- int len;
- int i, j;
- int cdata; /* when set, skip encoding */
+ int retval = -1;
+ char *str = NULL; /* Expanded format string w stdarg */
+ int fmtlen;
+ char *esc = NULL;
+ int l;
+ int len;
+ int i, j;
+ int cdata; /* when set, skip encoding */
+ va_list args;
+ /* Two steps: (1) read in the complete format string */
+ va_start(args, fmt); /* dryrun */
+ fmtlen = vsnprintf(NULL, 0, fmt, args) + 1;
+ va_end(args);
+ if ((str = malloc(fmtlen)) == NULL){
+ clicon_err(OE_UNIX, errno, "malloc");
+ goto done;
+ }
+ memset(str, 0, fmtlen);
+ va_start(args, fmt); /* real */
+ fmtlen = vsnprintf(str, fmtlen, fmt, args) + 1;
+ va_end(args);
+ /* Now str is the combined fmt + ... */
+
+ /* Step (2) encode and expand str --> enc */
/* First compute length (do nothing) */
len = 0; cdata = 0;
for (i=0; i]]>]]>" "^]]>]]>$"
new "netconf disabled feature"
-expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "foo]]>]]>" '^operation-failedprotocolerrorXML node config/A has no corresponding yang specification \(Invalid XML or wrong Yang spec?'
+expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "foo]]>]]>" '^operation-failedprotocolerrorXML node config/A has no corresponding yang specification (Invalid XML or wrong Yang spec?'
+# This is difficult test since changes to the module list are frequent
new "netconf schema resource, RFC 7895"
-expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' '^exampleAietf-inet-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-inet-typesietf-interfaces2014-05-08urn:ietf:params:xml:ns:yang:ietf-interfacesietf-routing2014-10-26urn:ietf:params:xml:ns:yang:ietf-routingrouter-idietf-yang-library2016-06-21urn:ietf:params:xml:ns:yang:ietf-yang-libraryietf-yang-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-yang-types]]>]]>$'
+expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' '^exampleAietf-inet-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-inet-typesietf-interfaces2014-05-08urn:ietf:params:xml:ns:yang:ietf-interfacesietf-netconf2011-06-01urn:ietf:params:xml:ns:netconf:base:1.0ietf-routing2014-10-26urn:ietf:params:xml:ns:yang:ietf-routingrouter-idietf-yang-library2016-06-21urn:ietf:params:xml:ns:yang:ietf-yang-libraryietf-yang-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-yang-types]]>]]>$'
new "Kill backend"
# kill backend
diff --git a/test/test_netconf.sh b/test/test_netconf.sh
index df5ac83d..68efcbdc 100755
--- a/test/test_netconf.sh
+++ b/test/test_netconf.sh
@@ -98,8 +98,8 @@ if [ $? -ne 0 ]; then
fi
new "netconf hello"
-expecteof "$clixon_netconf -f $cfg -y $fyang" 0 ']]>]]>' '^urn:ietf:params:netconf:capability:yang-library:1.0\?revision="2016-06-21"\&module-set-id=42'
-exit
+expecteof "$clixon_netconf -f $cfg -y $fyang" 0 ']]>]]>' '^urn:ietf:params:netconf:base:1.1urn:ietf:params:netconf:capability:yang-library:1.0?revision="2016-06-21"& module-set-id=42[0-9]*]]>]]>]]>]]>$'
+
new "netconf get-config"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' '^]]>]]>$'
@@ -112,6 +112,7 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 'eth/0/0ex:ethnone ]]>]]>' "^]]>]]>$"
+
# Too many quotes, (single inside double inside single) need to fool bash
cat < $tmp # new
]]>]]>
@@ -243,9 +244,6 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>"
new "netconf client-side rpc"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "example]]>]]>" "^ok]]>]]>$"
-new "netconf subscription"
-expectwait "$clixon_netconf -qf $cfg -y $fyang" "NETCONF]]>]]>" '^]]>]]>201' 10
-
new "Kill backend"
# kill backend
sudo clixon_backend -zf $cfg