* Ensured you can add multiple callbacks for any RPC, including basic ones.
* Extra RPC:s will be called _after_ the basic ones.
* One specific usecase is hook for `copy-config` (see [doc/ROADMAP.md] that can be implemented thus way.
* `rpc_callback_register` added a namespace parameter. Example:
```
rpc_callback_register(h, empty_rpc, NULL, "urn:example:clixon", "empty");
```
This commit is contained in:
parent
748c7282ea
commit
b1c74b5f1f
18 changed files with 755 additions and 514 deletions
|
|
@ -68,5 +68,6 @@ 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);
|
||||
char *netconf_db_find(cxobj *xn, char *name);
|
||||
|
||||
#endif /* _CLIXON_NETCONF_LIB_H */
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@
|
|||
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||
* @param[in] arg Domain specific arg, ec client-entry or FCGX_Request
|
||||
* @param[in] regarg User argument given at rpc_callback_register()
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
typedef int (*clicon_rpc_cb)(
|
||||
clicon_handle h,
|
||||
|
|
@ -147,17 +149,17 @@ struct clixon_plugin_api{
|
|||
plgstart_t *ca_start; /* Plugin start */
|
||||
plgexit_t *ca_exit; /* Plugin exit */
|
||||
union {
|
||||
struct {
|
||||
struct { /* cli-specific */
|
||||
cli_prompthook_t *ci_prompt; /* Prompt hook */
|
||||
cligen_susp_cb_t *ci_suspend; /* Ctrl-Z hook, see cligen getline */
|
||||
cligen_interrupt_cb_t *ci_interrupt; /* Ctrl-C, see cligen getline */
|
||||
} cau_cli;
|
||||
struct {
|
||||
struct { /* restconf-specific */
|
||||
plgauth_t *cr_auth; /* Auth credentials */
|
||||
} cau_restconf;
|
||||
struct {
|
||||
struct { /* netconf-specific */
|
||||
} cau_netconf;
|
||||
struct {
|
||||
struct { /* backend-specific */
|
||||
plgreset_t *cb_reset; /* Reset system status */
|
||||
plgstatedata_t *cb_statedata; /* Get state data from plugin (backend only) */
|
||||
upgrade_cb_t *cb_upgrade; /* Upgrade callback */
|
||||
|
|
@ -225,7 +227,7 @@ int clixon_plugin_exit(clicon_handle h);
|
|||
int clixon_plugin_auth(clicon_handle h, void *arg);
|
||||
|
||||
/* rpc callback API */
|
||||
int rpc_callback_register(clicon_handle h, clicon_rpc_cb cb, void *arg, char *tag);
|
||||
int rpc_callback_register(clicon_handle h, clicon_rpc_cb cb, void *arg, char *namespace, char *name);
|
||||
|
||||
int rpc_callback_delete_all(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -1034,7 +1034,10 @@ netconf_module_load(clicon_handle h)
|
|||
goto done;
|
||||
if (xml_parse_string("<CLICON_FEATURE>ietf-netconf:xpath</CLICON_FEATURE>", yspec, &xc) < 0)
|
||||
goto done;
|
||||
|
||||
#ifdef NYI
|
||||
if (xml_parse_string("<CLICON_FEATURE>ietf-netconf:confirmed-commit</CLICON_FEATURE>", yspec, &xc) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
/* Load yang spec */
|
||||
if (yang_spec_parse_module(h, "ietf-netconf", NULL, yspec)< 0)
|
||||
goto done;
|
||||
|
|
@ -1044,3 +1047,35 @@ netconf_module_load(clicon_handle h)
|
|||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Find some sub-child in netconf/xm request.
|
||||
* Actually, find a child with a certain name and return its body
|
||||
* @param[in] xn
|
||||
* @param[in] name
|
||||
* @retval db Name of database
|
||||
* @retval NULL Not found
|
||||
* The following code returns "source"
|
||||
* @code
|
||||
* cxobj *xt = NULL;
|
||||
* char *db;
|
||||
* xml_parse_string("<x><target>source</target></x>", NULL, &xt);
|
||||
* db = netconf_db_find(xt, "target");
|
||||
* @endcode
|
||||
*/
|
||||
char*
|
||||
netconf_db_find(cxobj *xn,
|
||||
char *name)
|
||||
{
|
||||
cxobj *xs; /* source */
|
||||
cxobj *xi;
|
||||
char *db = NULL;
|
||||
|
||||
if ((xs = xml_find(xn, name)) == NULL)
|
||||
goto done;
|
||||
if ((xi = xml_child_i(xs, 0)) == NULL)
|
||||
goto done;
|
||||
db = xml_name(xi);
|
||||
done:
|
||||
return db;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -404,35 +404,41 @@ clixon_plugin_auth(clicon_handle h,
|
|||
* specification are directly dlsym:ed to the CLI plugin.
|
||||
* It would be possible to use this rpc registering API for CLI plugins as well.
|
||||
*
|
||||
* @note may have a problem if callbacks are of different types
|
||||
* When namespace and name match, the callback is made
|
||||
*/
|
||||
typedef struct {
|
||||
qelem_t rc_qelem; /* List header */
|
||||
clicon_rpc_cb rc_callback; /* RPC Callback */
|
||||
void *rc_arg; /* Application specific argument to cb */
|
||||
char *rc_tag; /* Xml/json tag when matched, callback called */
|
||||
char *rc_namespace;/* Namespace to combine with name tag */
|
||||
char *rc_name; /* Xml/json tag/name */
|
||||
} rpc_callback_t;
|
||||
|
||||
/* List of rpc callback entries */
|
||||
static rpc_callback_t *rpc_cb_list = NULL;
|
||||
|
||||
/*! Register a RPC callback
|
||||
* Called from plugin to register a callback for a specific netconf XML tag.
|
||||
/*! Register a RPC callback by appending a new RPC to the list
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] cb, Callback called
|
||||
* @param[in] arg, Domain-specific argument to send to callback
|
||||
* @param[in] tag Xml tag when callback is made
|
||||
* @see rpc_callback_call
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] cb, Callback called
|
||||
* @param[in] arg, Domain-specific argument to send to callback
|
||||
* @param[in] namespace namespace of rpc
|
||||
* @param[in] name RPC name
|
||||
* @see rpc_callback_call which makes the actual callback
|
||||
*/
|
||||
int
|
||||
rpc_callback_register(clicon_handle h,
|
||||
clicon_rpc_cb cb,
|
||||
void *arg,
|
||||
char *tag)
|
||||
char *namespace,
|
||||
char *name)
|
||||
{
|
||||
rpc_callback_t *rc;
|
||||
|
||||
if (name == NULL || namespace == NULL){
|
||||
clicon_err(OE_DB, EINVAL, "name or namespace NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((rc = malloc(sizeof(rpc_callback_t))) == NULL) {
|
||||
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
|
||||
goto done;
|
||||
|
|
@ -440,13 +446,16 @@ rpc_callback_register(clicon_handle h,
|
|||
memset(rc, 0, sizeof(*rc));
|
||||
rc->rc_callback = cb;
|
||||
rc->rc_arg = arg;
|
||||
rc->rc_tag = strdup(tag); /* XXX strdup memleak */
|
||||
INSQ(rc, rpc_cb_list);
|
||||
rc->rc_namespace = strdup(namespace);
|
||||
rc->rc_name = strdup(name);
|
||||
ADDQ(rc, rpc_cb_list);
|
||||
return 0;
|
||||
done:
|
||||
if (rc){
|
||||
if (rc->rc_tag)
|
||||
free(rc->rc_tag);
|
||||
if (rc->rc_namespace)
|
||||
free(rc->rc_namespace);
|
||||
if (rc->rc_name)
|
||||
free(rc->rc_name);
|
||||
free(rc);
|
||||
}
|
||||
return -1;
|
||||
|
|
@ -461,8 +470,10 @@ rpc_callback_delete_all(void)
|
|||
|
||||
while((rc = rpc_cb_list) != NULL) {
|
||||
DELQ(rc, rpc_cb_list, rpc_callback_t *);
|
||||
if (rc->rc_tag)
|
||||
free(rc->rc_tag);
|
||||
if (rc->rc_namespace)
|
||||
free(rc->rc_namespace);
|
||||
if (rc->rc_name)
|
||||
free(rc->rc_name);
|
||||
free(rc);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -472,12 +483,15 @@ rpc_callback_delete_all(void)
|
|||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
|
||||
* @param[out] xret Return XML, error or OK
|
||||
* @param[out] cbret Return XML (as string in CLIgen buffer), error or OK
|
||||
* @param[in] arg Domain-speific arg (eg client_entry)
|
||||
*
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK, not found handler.
|
||||
* @retval 1 OK, handler called
|
||||
* @retval n OK, <n> handler called
|
||||
* @see rpc_callback_register which register a callback function
|
||||
* @note that several callbacks can be registered. They need to cooperate on
|
||||
* return values, ie if one writes cbret, the other needs to handle that by
|
||||
* leaving it, replacing it or amending it.
|
||||
*/
|
||||
int
|
||||
rpc_callback_call(clicon_handle h,
|
||||
|
|
@ -486,25 +500,32 @@ rpc_callback_call(clicon_handle h,
|
|||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
rpc_callback_t *rc;
|
||||
char *name;
|
||||
char *prefix;
|
||||
char *namespace;
|
||||
int nr = 0; /* How many callbacks */
|
||||
|
||||
if (rpc_cb_list == NULL)
|
||||
return 0;
|
||||
rc = rpc_cb_list;
|
||||
do {
|
||||
if (strcmp(rc->rc_tag, xml_name(xe)) == 0){
|
||||
if ((retval = rc->rc_callback(h, xe, cbret, arg, rc->rc_arg)) < 0){
|
||||
clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_tag);
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
retval = 1; /* handled */
|
||||
name = xml_name(xe);
|
||||
prefix = xml_prefix(xe);
|
||||
xml2ns(xe, prefix, &namespace);
|
||||
if (strcmp(rc->rc_name, name) == 0 &&
|
||||
namespace && rc->rc_namespace &&
|
||||
strcmp(rc->rc_namespace, namespace) == 0){
|
||||
if ((ret = rc->rc_callback(h, xe, cbret, arg, rc->rc_arg)) < 0){
|
||||
clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name);
|
||||
goto done;
|
||||
}
|
||||
nr++;
|
||||
}
|
||||
rc = NEXTQ(rpc_callback_t *, rc);
|
||||
} while (rc != rpc_cb_list);
|
||||
retval = 0;
|
||||
retval = nr; /* 0: none found, >0 nr of handlers called */
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue