From 3fe218da2e7396dd63a45ab03c22de4512c60e67 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Fri, 22 Jan 2021 14:50:07 +0100 Subject: [PATCH] New clixon_client API for external access --- CHANGELOG.md | 2 + lib/clixon/clixon_client.h | 43 ++-- lib/src/clixon_client.c | 441 +++++++++++++++++++++++-------------- test/test_client.sh | 44 ++-- 4 files changed, 324 insertions(+), 206 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b02825f..512158c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ Expected: February 2021 ### New features +* New clixon_client API for external access + ### C/CLI-API changes on existing features Developers may need to change their code diff --git a/lib/clixon/clixon_client.h b/lib/clixon/clixon_client.h index f576632e..d2524117 100644 --- a/lib/clixon/clixon_client.h +++ b/lib/clixon/clixon_client.h @@ -2,7 +2,6 @@ * ***** BEGIN LICENSE BLOCK ***** - Copyright (C) 2009-2019 Olof Hagsand Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate) This file is part of CLIXON. @@ -31,11 +30,25 @@ the terms of any one of the Apache License version 2 or the GPL. ***** END LICENSE BLOCK ***** + * */ #ifndef _CLIXON_CLIENT_H #define _CLIXON_CLIENT_H +/* + * Types + */ +typedef void *clixon_handle; +typedef void *clixon_client_handle; + +/* Connection type as parameter to connect */ +typedef enum { + CLIXON_CLIENT_IPC, /* Internal IPC API, only experimental use */ + CLIXON_CLIENT_NETCONF, /* External Netconf */ + CLIXON_CLIENT_SSH /* External Netconf over SSH */ +} clixon_client_type; + /* * Prototypes */ @@ -44,24 +57,16 @@ extern "C" { #endif -int clixon_client_connect(void *h, const struct sockaddr* srv, int srv_sz); -int clixon_client_close(int sock); -int clixon_client_session_start(void *h, const char *db); -int clixon_client_session_end(void *h); -int clixon_client_subscribe(int sock, int priority, int nspace, - int *spoint, const char *fmt, ...); -int clixon_client_subscribe_done(int sock); -int clixon_client_read_subscription_socket(int sock, int sub_points[], int *resultlen); -int clixon_client_num_instances(int sock, const char *xnamespace, const char *xpath); -int clixon_client_get_bool(int sock, int *rval, const char *xnamespace, const char *xpath); -int clixon_client_get_str(int sock, char *rval, int n, const char *xnamespace, const char *xpath); -int clixon_client_get_u_int8(int sock, uint8_t *rval, const char *xnamespace, const char *xpath); -int clixon_client_get_u_int16(int sock, uint16_t *rval, const char *xnamespace, const char *xpath); -int clixon_client_get_u_int32(int sock, uint32_t *rval, const char *xnamespace, const char *xpath); -int clixon_client_get_u_int64(int sock, uint64_t *rval, const char *xnamespace, const char *xpath); - -void *clixon_client_init(const char *name, FILE *estream, const int debug, const char *config_file); -int clixon_client_terminate(void *h); +clixon_handle clixon_client_init(const char *config_file); +int clixon_client_terminate(clixon_handle h); +clixon_client_handle clixon_client_connect(clixon_handle h, clixon_client_type socktype); +int clixon_client_disconnect(clixon_client_handle ch); +int clixon_client_get_bool(clixon_client_handle ch, int *rval, const char *xnamespace, const char *xpath); +int clixon_client_get_str(clixon_client_handle ch, char *rval, int n, const char *xnamespace, const char *xpath); +int clixon_client_get_uint8(clixon_client_handle ch, uint8_t *rval, const char *xnamespace, const char *xpath); +int clixon_client_get_uint16(clixon_client_handle ch, uint16_t *rval, const char *xnamespace, const char *xpath); +int clixon_client_get_uint32(clixon_client_handle ch, uint32_t *rval, const char *xnamespace, const char *xpath); +int clixon_client_get_uint64(clixon_client_handle ch, uint64_t *rval, const char *xnamespace, const char *xpath); #ifdef __cplusplus } diff --git a/lib/src/clixon_client.c b/lib/src/clixon_client.c index 84565344..4b8d7faa 100644 --- a/lib/src/clixon_client.c +++ b/lib/src/clixon_client.c @@ -2,7 +2,6 @@ * ***** BEGIN LICENSE BLOCK ***** - Copyright (C) 2009-2019 Olof Hagsand Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate) This file is part of CLIXON. @@ -31,6 +30,7 @@ the terms of any one of the Apache License version 2 or the GPL. ***** END LICENSE BLOCK ***** + * */ #ifdef HAVE_CONFIG_H #include "clixon_config.h" /* generated by config & autoconf */ @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include /* cligen */ @@ -54,6 +56,7 @@ #include "clixon_err.h" #include "clixon_yang.h" #include "clixon_options.h" +#include "clixon_proc.h" #include "clixon_xml.h" #include "clixon_xml_nsctx.h" #include "clixon_xml_io.h" @@ -64,29 +67,61 @@ #include "clixon_proto_client.h" #include "clixon_client.h" +/* + * Constants + */ +/* Netconf binary default, override with environment variable: CLIXON_NETCONF_BIN + * Could try to get path from install/makefile data + */ +#define CLIXON_NETCONF_BIN "/usr/local/bin/clixon_netconf" + +#define CLIXON_CLIENT_MAGIC 0x54fe649a + +#define chandle(ch) (assert(clixon_client_handle_check(ch)==0),(struct clixon_client_handle *)(ch)) + +/*! Internal structure of clixon client handle. + */ +struct clixon_client_handle{ + uint32_t cch_magic; /* magic number */ + clixon_client_type cch_type; /* Clixon socket type */ + int cch_fdin; /* Input file descriptor */ + int cch_fdout; /* Output file descriptor, Only applies for NETCONF/SSH */ + int cch_pid; /* Sub-process-id Only applies for NETCONF/SSH */ +}; + +/*! Check struct magic number for sanity checks + * @param[in] h Clicon client handle + * @retval 0 Sanity check OK + * @retval -1 Sanity check failed + */ +static int +clixon_client_handle_check(clixon_client_handle ch) +{ + /* Dont use handle macro to avoid recursion */ + struct clixon_client_handle *cch = (struct clixon_client_handle *)(ch); + + return cch->cch_magic == CLIXON_CLIENT_MAGIC ? 0 : -1; +} + /*! Initialize Clixon client API * @param[in] name Name of client (NYI) * @param[in] estream Error/debug file (NULL: syslog) * @param[in] debug Clixon debug flag - * @param[in] config_file Clixon configuration file (eg for CLICON_SOCK) + * @param[in] config_file Clixon configuration file, or NULL for default * @see clixon_client_close */ -clicon_handle -clixon_client_init(const char *name, - FILE *estream, - const int debug, - const char *config_file) +clixon_handle +clixon_client_init(const char *config_file) { clicon_handle h; - clicon_log_init("clixon", LOG_DEBUG, CLICON_LOG_STDERR); - clicon_debug_init(debug, estream); - fprintf(stderr, "fprintf %s\n", __FUNCTION__); + clicon_debug(1, "%s", __FUNCTION__); /* Initiate CLICON handle. CLIgen is also initialized */ if ((h = clicon_handle_init()) == NULL) return NULL; /* Set clixon config file - reuse the one in the main installation */ - clicon_option_str_set(h, "CLICON_CONFIGFILE", (char*)config_file); + clicon_option_str_set(h, "CLICON_CONFIGFILE", + config_file?(char*)config_file:CLIXON_DEFAULT_CONFIG); /* Find, read and parse configfile */ if (clicon_options_main(h) < 0) return NULL; @@ -105,60 +140,145 @@ clixon_client_terminate(clicon_handle h) } /*! Connect client to clixon backend according to config and return a socket - * @param[in] h Clixon handle - * @retval s Socket, need to be closed by caller - * @see clixon_client_close Close the socket returned here + * @param[in] h Clixon handle + * @param[out] fdin Open netconf output file descr + * @param[out] fdout Open netconf output file descr. If socket same as fdin + * @retval cs Clixon session handler + * @retval NULL Error + * @see clixon_client_disconnect Close the socket returned here */ -int -clixon_client_connect(clicon_handle h, - const struct sockaddr* srv, - int srv_sz) +clixon_client_handle +clixon_client_connect(clicon_handle h, + clixon_client_type socktype) { - int s = -1; - + struct clixon_client_handle *cch = NULL; + char **argv = NULL; + int nr; + int i; + char *netconf_bin = NULL; + struct stat st = {0,}; + size_t sz = sizeof(struct clixon_client_handle); + char dbgstr[8]; + clicon_debug(1, "%s", __FUNCTION__); - if (clicon_rpc_connect(h, &s) < 0) - return -1; - return s; + if ((cch = malloc(sz)) == NULL){ + clicon_err(OE_NETCONF, errno, "malloc"); + goto done; + } + memset(cch, 0, sz); + cch->cch_magic = CLIXON_CLIENT_MAGIC; + cch->cch_type = socktype; + switch (socktype){ + case CLIXON_CLIENT_IPC: + if (clicon_rpc_connect(h, &cch->cch_fdin) < 0) + goto err; + cch->cch_fdout = cch->cch_fdin; + break; + case CLIXON_CLIENT_NETCONF: + nr = 7; + if (clicon_debug_get() != 0) + nr += 2; + if ((argv = calloc(nr, sizeof(char *))) == NULL){ + clicon_err(OE_UNIX, errno, "calloc"); + goto err; + } + i = 0; + if ((netconf_bin = getenv("CLIXON_NETCONF_BIN")) == NULL) + netconf_bin = CLIXON_NETCONF_BIN; + if (stat(netconf_bin, &st) < 0){ + clicon_err(OE_NETCONF, 0, "netconf binary %s: %s. Set with CLIXON_NETCONF_BIN=", + netconf_bin, strerror(errno)); + goto err; + } + argv[i++] = netconf_bin; + argv[i++] = "-q"; + argv[i++] = "-f"; + argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE"); + argv[i++] = "-l"; /* log to syslog */ + argv[i++] = "s"; + if (clicon_debug_get() != 0){ + argv[i++] = "-D"; + snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get()); + argv[i++] = dbgstr; + } + argv[i++] = NULL; + assert(i==nr); + if (clixon_proc_socket(argv, &cch->cch_pid, &cch->cch_fdin, &cch->cch_fdout) < 0){ + goto err; + } + break; + case CLIXON_CLIENT_SSH: + break; + } /* switch */ + done: + return cch; + err: + free(cch); + cch = NULL; + goto done; } /*! Connect client to clixon backend according to config and return a socket - * @param[in] s Socket, opened by connect call - * @see clixon_client_connect + * @param[in] cch Clixon client session handle + * @see clixon_client_connect where the handle is created + * The handle is deallocated */ int -clixon_client_close(int s) +clixon_client_disconnect(clixon_client_handle ch) { + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + clicon_debug(1, "%s", __FUNCTION__); - close(s); - return 0; + if (cch == NULL){ + clicon_err(OE_XML, EINVAL, "Expected cch handle"); + goto done; + } + switch(cch->cch_type){ + case CLIXON_CLIENT_IPC: + close(cch->cch_fdin); + break; + case CLIXON_CLIENT_NETCONF: + if (clixon_proc_socket_close(cch->cch_pid, + cch->cch_fdin, + cch->cch_fdout) < 0) + goto done; + break; + case CLIXON_CLIENT_SSH: + break; + } + free(cch); + retval = 0; + done: + return retval; } -int -clixon_client_subscribe(int sock, - int priority, - int nspace, - int *spoint, - const char *fmt, ...) +static int +clixon_xml_bottom(cxobj *xtop, + cxobj **xbotp) { - clicon_debug(1, "%s", __FUNCTION__); - return 0; -} - -int -clixon_client_subscribe_done(int sock) -{ - clicon_debug(1, "%s", __FUNCTION__); - return 0; -} - -int -clixon_client_read_subscription_socket(int sock, - int sub_points[], - int *resultlen) -{ - clicon_debug(1, "%s", __FUNCTION__); - return 0; + int retval = -1; + cxobj *x; + cxobj *xp; + cxobj *xc = NULL; + + xp = xtop; + while (xp != NULL){ + /* Find child, if many, one which is not a key, if any */ + xc = NULL; + x = NULL; + while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) + xc = x; + /* xc is last XXX */ + if (xc == NULL) + break; + xp = xc; + } + retval = 0; + *xbotp = xp; + retval = 0; + // done: + return retval; } /*! Internal function to construct a get-config and query a value from the backend @@ -169,44 +289,47 @@ clixon_client_read_subscription_socket(int sock, * @param[out] val String value */ static int -clixon_client_get_xdata(int sock, +clixon_client_get_xdata(int fdin, + int fdout, const char *namespace, const char *xpath, cxobj **xdata) { int retval = -1; - char *retdata = NULL; cxobj *xret = NULL; cxobj *xd; - cbuf *cb = NULL; - struct clicon_msg *msg = NULL; + cbuf *msg = NULL; + cbuf *msgret = NULL; const char *db = "running"; cvec *nsc = NULL; - if ((cb = cbuf_new()) == NULL) + if ((msg = cbuf_new()) == NULL){ + clicon_err(OE_PLUGIN, errno, "cbuf_new"); goto done; - cprintf(cb, "<%s/>", db); + cprintf(msg, "><%s/>", db); if (xpath && strlen(xpath)){ - cprintf(cb, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"", + cprintf(msg, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_PREFIX, namespace, NETCONF_BASE_PREFIX, xpath); - if (xml_nsctx_cbuf(cb, nsc) < 0) + if (xml_nsctx_cbuf(msg, nsc) < 0) goto done; - cprintf(cb, "/>"); + cprintf(msg, "/>"); } - cprintf(cb, ""); - clicon_debug(1, "%s xml:%s", __FUNCTION__, cbuf_get(cb)); - if ((msg = clicon_msg_encode(0, "%s", cbuf_get(cb))) == NULL) + cprintf(msg, ""); + if (clicon_rpc1(fdin, fdout, msg, msgret) < 0) goto done; - if (clicon_rpc(sock, msg, &retdata) < 0) - goto done; - if (clixon_xml_parse_string(retdata, YB_NONE, NULL, &xret, NULL) < 0) + if (clixon_xml_parse_string(cbuf_get(msgret), YB_NONE, NULL, &xret, NULL) < 0) goto done; if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL){ xd = xml_parent(xd); /* point to rpc-reply */ @@ -224,17 +347,19 @@ clixon_client_get_xdata(int sock, *xdata = xd; retval = 0; done: + clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); if (xret) xml_free(xret); - if (cb) - cbuf_free(cb); if (msg) - free(msg); + cbuf_free(msg); + if (msgret) + cbuf_free(msgret); return retval; } static int -clixon_client_get_val(int sock, +clixon_client_get_val(int fdin, + int fdout, const char *namespace, const char *xpath, char **val) @@ -247,15 +372,12 @@ clixon_client_get_val(int sock, clicon_err(OE_XML, EINVAL, "Expected val"); goto done; } -#if 1 /* XXX: Problem is xpath with indexes used in original need to change to [0] in the 2nd access */ - if (clixon_client_get_xdata(sock, namespace, "/", &xdata) < 0) + if (clixon_client_get_xdata(fdin, fdout, namespace, xpath, &xdata) < 0) goto done; -#else - if (clixon_client_get_xdata(sock, namespace, xpath, &xdata) < 0) + if (clixon_xml_bottom(xdata, &xobj) < 0) goto done; -#endif - if ((xobj = xpath_first(xdata, NULL, "%s", xpath)) == NULL){ - clicon_err(OE_XML, ENOENT, "Expected local xpath result"); + if (xobj == NULL){ + clicon_err(OE_XML, EFAULT, "No bottom xml found"); goto done; } *val = xml_body(xobj); @@ -264,51 +386,23 @@ clixon_client_get_val(int sock, return retval; } -/*! Get number of list entries - * @param[in] sock Stream socket - * @note there is no way using netconf to get this number: instead the whole list is retrieved. - */ int -clixon_client_num_instances(int sock, - const char *namespace, - const char *xpath) +clixon_client_get_bool(clixon_client_handle ch, + int *rval, + const char *namespace, + const char *xpath) { - int retval = -1; - cxobj *xdata = NULL; - cxobj **vec = NULL; - size_t veclen; + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + char *val = NULL; + char *reason = NULL; + int ret; + uint8_t val0=0; clicon_debug(1, "%s", __FUNCTION__); -#if 1 /* XXX: Problem is xpath with indexes used in original need to change to [0] in the 2nd access */ - if (clixon_client_get_xdata(sock, namespace, "/", &xdata) < 0) - goto done; -#else - if (clixon_client_get_xdata(sock, namespace, xpath, &xdata) < 0) - goto done; -#endif - if (xpath_vec(xdata, NULL, "%s", &vec, &veclen, xpath) < 0) - goto done; - retval = veclen; - done: - if (vec) - free(vec); - return retval; -} - -int -clixon_client_get_bool(int sock, - int *rval, - const char *namespace, - const char *xpath) -{ - int retval = -1; - char *val = NULL; - char *reason = NULL; - int ret; - uint8_t val0=0; - - clicon_debug(1, "%s", __FUNCTION__); - if (clixon_client_get_val(sock, namespace, xpath, &val) < 0) + if (clixon_client_get_val(cch->cch_fdin, + cch->cch_fdout, + namespace, xpath, &val) < 0) goto done; if ((ret = parse_bool(val, &val0, &reason)) < 0){ clicon_err(OE_XML, errno, "parse_bool"); @@ -334,17 +428,20 @@ clixon_client_get_bool(int sock, * @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc) */ int -clixon_client_get_str(int sock, - char *rval, - int n, - const char *namespace, - const char *xpath) +clixon_client_get_str(clixon_client_handle ch, + char *rval, + int n, + const char *namespace, + const char *xpath) { - int retval = -1; - char *val = NULL; + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + char *val = NULL; clicon_debug(1, "%s", __FUNCTION__); - if (clixon_client_get_val(sock, namespace, xpath, &val) < 0) + if (clixon_client_get_val(cch->cch_fdin, + cch->cch_fdout, + namespace, xpath, &val) < 0) goto done; strncpy(rval, val, n-1); rval[n-1]= '\0'; @@ -354,18 +451,21 @@ clixon_client_get_str(int sock, } int -clixon_client_get_u_int8(int sock, - uint8_t *rval, - const char *namespace, - const char *xpath) +clixon_client_get_uint8(clixon_client_handle ch, + uint8_t *rval, + const char *namespace, + const char *xpath) { - int retval = -1; - char *val = NULL; - char *reason = NULL; - int ret; + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + char *val = NULL; + char *reason = NULL; + int ret; clicon_debug(1, "%s", __FUNCTION__); - if (clixon_client_get_val(sock, namespace, xpath, &val) < 0) + if (clixon_client_get_val(cch->cch_fdin, + cch->cch_fdout, + namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint8(val, rval, &reason)) < 0){ clicon_err(OE_XML, errno, "parse_bool"); @@ -383,18 +483,21 @@ clixon_client_get_u_int8(int sock, } int -clixon_client_get_u_int16(int sock, - uint16_t *rval, - const char *namespace, - const char *xpath) +clixon_client_get_uint16(clixon_client_handle ch, + uint16_t *rval, + const char *namespace, + const char *xpath) { - int retval = -1; - char *val = NULL; - char *reason = NULL; - int ret; + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + char *val = NULL; + char *reason = NULL; + int ret; clicon_debug(1, "%s", __FUNCTION__); - if (clixon_client_get_val(sock, namespace, xpath, &val) < 0) + if (clixon_client_get_val(cch->cch_fdin, + cch->cch_fdout, + namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint16(val, rval, &reason)) < 0){ clicon_err(OE_XML, errno, "parse_bool"); @@ -412,18 +515,21 @@ clixon_client_get_u_int16(int sock, } int -clixon_client_get_u_int32(int sock, - uint32_t *rval, - const char *namespace, - const char *xpath) +clixon_client_get_uint32(clixon_client_handle ch, + uint32_t *rval, + const char *namespace, + const char *xpath) { - int retval = -1; - char *val = NULL; - char *reason = NULL; - int ret; - + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + char *val = NULL; + char *reason = NULL; + int ret; + clicon_debug(1, "%s", __FUNCTION__); - if (clixon_client_get_val(sock, namespace, xpath, &val) < 0) + if (clixon_client_get_val(cch->cch_fdin, + cch->cch_fdout, + namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint32(val, rval, &reason)) < 0){ clicon_err(OE_XML, errno, "parse_bool"); @@ -441,18 +547,21 @@ clixon_client_get_u_int32(int sock, } int -clixon_client_get_u_int64(int sock, - uint64_t *rval, - const char *namespace, - const char *xpath) +clixon_client_get_uint64(clixon_client_handle ch, + uint64_t *rval, + const char *namespace, + const char *xpath) { - int retval = -1; - char *val = NULL; - char *reason = NULL; - int ret; + int retval = -1; + struct clixon_client_handle *cch = chandle(ch); + char *val = NULL; + char *reason = NULL; + int ret; clicon_debug(1, "%s", __FUNCTION__); - if (clixon_client_get_val(sock, namespace, xpath, &val) < 0) + if (clixon_client_get_val(cch->cch_fdin, + cch->cch_fdout, + namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint64(val, rval, &reason)) < 0){ clicon_err(OE_XML, errno, "parse_bool"); diff --git a/test/test_client.sh b/test/test_client.sh index 6acaacf0..ae3c74be 100755 --- a/test/test_client.sh +++ b/test/test_client.sh @@ -14,7 +14,7 @@ cfg=$dir/conf_yang.xml fyang=$dir/example-client.yang cfile=$dir/example-client.c pdir=$dir/plugin -app=$pdir/example-api +app=$dir/clixon-app if [ ! -d $pdir ]; then mkdir $pdir @@ -67,43 +67,45 @@ EOF cat< $cfile #include #include -#include -#include /* sockaddr_in */ -#include /* inet_addr */ -#include +#include -#define CLIXONCONF "$cfg" +#include +#include int main(int argc, char **argv) { - int s; - void *h = NULL; /* clixon handle */ + clixon_handle h = NULL; /* clixon handle */ + clixon_client_handle ch = NULL; /* clixon client handle */ - if ((h = clixon_client_init("server", stderr, 0, CLIXONCONF)) == NULL) +// clicon_log_init("client", LOG_DEBUG, CLICON_LOG_STDERR); // debug +// clicon_debug_init(1, NULL); // debug + + /* Provide a clixon config-file, get a clixon handle */ + if ((h = clixon_client_init("$cfg")) == NULL) return -1; - if ((s = clixon_client_connect(h)) < 0){ + /* Make a conenction over netconf or ssh/netconf */ + if ((ch = clixon_client_connect(h, CLIXON_CLIENT_NETCONF)) == NULL) return -1; - } /* Here are read functions depending on an example YANG * (Need an example YANG and XML input to confd) */ { uint32_t u = 0; - if (clixon_client_get_uint32(s, &u, "urn:example:clixon-client", "/table/parameter[name='a']/value") < 0) + if (clixon_client_get_uint32(ch, &u, "urn:example:clixon-client", "/table/parameter[name='a']/value") < 0) return -1; + printf("%u\n", u); /* for test output */ } - clixon_client_close(s); + clixon_client_disconnect(ch); clixon_client_terminate(h); return 0; } EOF new "compile $cfile -> $app" -echo "$CC -g -Wall -I/usr/local/include $cfile -o $app -lclixon" expectpart "$($CC -g -Wall -I/usr/local/include $cfile -o $app -lclixon)" 0 "" -exit + new "test params: -s init -f $cfg" if [ $BE -ne 0 ]; then @@ -130,17 +132,17 @@ if [ $RC -ne 0 ]; then wait_restconf fi -XML='235zorro7' +XML='a42
' # Add a set of entries using restconf -new "PUT a set of entries" -expectpart "$(curl $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+xml' $RCPROTO://localhost/restconf/data/example-api:c -d "$XML")" 0 "HTTP/1.1 201 Created" +new "POST the XML" +expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' $RCPROTO://localhost/restconf/data -d "$XML")" 0 "HTTP/1.1 201 Created" new "Check entries" -expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-api:c -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' "$XML" +expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/clixon-client:table -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' "$XML" -new "Send a trigger" -expectpart "$(curl $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/example-api:trigger -H 'Accept: application/yang-data+json')" 0 'HTTP/1.1 204 No Content' +new "Run $app" +expectpart "$($app)" 0 '^42$' if [ $RC -ne 0 ]; then new "Kill restconf daemon"