Change internal protocol from clicon_proto.h to netconf.
This commit is contained in:
parent
2e09f54d12
commit
2fcefda831
66 changed files with 3012 additions and 5141 deletions
|
|
@ -49,6 +49,7 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
@ -56,38 +57,42 @@
|
|||
/* clicon */
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_chunk.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xsl.h"
|
||||
#include "clixon_proto.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_proto_encode.h"
|
||||
#include "clixon_proto_client.h"
|
||||
|
||||
/*! Internal rpc function
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] msg Encoded message
|
||||
* @param[out] ret Return value from backend server (reply)
|
||||
* @param[out] retlen Length of return value
|
||||
* @param[in] msg Encoded message. Deallocate woth free
|
||||
* @param[out] xret Return value from backend as netconf xml tree. Free w xml_free
|
||||
* @param[inout] sock0 If pointer exists, do not close socket to backend on success
|
||||
* and return it here. For keeping a notify socket open
|
||||
* @param[in] label Chunk label for deallocating return values
|
||||
* Deallocate with unchunk_group(label)
|
||||
* Note: sock0 is if connection should be persistent, like a notification/subscribe api
|
||||
*/
|
||||
static int
|
||||
int
|
||||
clicon_rpc_msg(clicon_handle h,
|
||||
struct clicon_msg *msg,
|
||||
char **ret,
|
||||
uint16_t *retlen,
|
||||
int *sock0,
|
||||
const char *label)
|
||||
cxobj **xret0,
|
||||
int *sock0)
|
||||
{
|
||||
int retval = -1;
|
||||
char *sock;
|
||||
int port;
|
||||
char *retdata = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *x;
|
||||
uint32_t err;
|
||||
uint32_t suberr;
|
||||
char *errmsg = NULL;
|
||||
char *etype = NULL;
|
||||
|
||||
if ((sock = clicon_sock(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||
|
|
@ -96,7 +101,7 @@ clicon_rpc_msg(clicon_handle h,
|
|||
/* What to do if inet socket? */
|
||||
switch (clicon_sock_family(h)){
|
||||
case AF_UNIX:
|
||||
if (clicon_rpc_connect_unix(msg, sock, ret, retlen, sock0, label) < 0){
|
||||
if (clicon_rpc_connect_unix(msg, sock, &retdata, sock0) < 0){
|
||||
#if 0
|
||||
if (errno == ESHUTDOWN)
|
||||
/* Maybe could reconnect on a higher layer, but lets fail
|
||||
|
|
@ -115,12 +120,428 @@ clicon_rpc_msg(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "CLICON_SOCK_PORT not set");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_connect_inet(msg, sock, port, ret, retlen, sock0, label) < 0)
|
||||
if (clicon_rpc_connect_inet(msg, sock, port, &retdata, sock0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
#if 1 /* Parse return data and intercept clixon errors */
|
||||
if (retdata) {
|
||||
if (clicon_xml_parse_str(retdata, &xret) < 0)
|
||||
goto done;
|
||||
if (xpath_first(xret, "/rpc-reply/ok") != NULL ||
|
||||
xpath_first(xret, "/rpc-reply/data") != NULL)
|
||||
;
|
||||
else if (xpath_first(xret, "/rpc-reply/rpc-error") != NULL){
|
||||
if ((x=xpath_first(xret, "//error-type"))!=NULL)
|
||||
etype = xml_body(x);
|
||||
if (etype&&strcmp(etype, "clixon")==0){
|
||||
if ((x=xpath_first(xret, "//error-tag"))!=NULL)
|
||||
err = atoi(xml_body(x));
|
||||
if ((x=xpath_first(xret, "//error-message"))!=NULL)
|
||||
suberr = atoi(xml_body(x));
|
||||
if ((x=xpath_first(xret, "//error-info"))!=NULL)
|
||||
errmsg = xml_body(x);
|
||||
if (debug)
|
||||
clicon_err(err, suberr, "%s msgtype:%hu", errmsg, ntohs(msg->op_type));
|
||||
else
|
||||
clicon_err(err, suberr, "%s", errmsg);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
clicon_err(OE_PROTO, 0, "%s: unexpected reply",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
if (xret0){
|
||||
*xret0 = xret;
|
||||
xret = NULL;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (retdata)
|
||||
free(retdata);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Generic xml netconf clicon rpc
|
||||
* Want to go over to use netconf directly between client and server,...
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xi XML netconf tree
|
||||
* @param[out] xret Return XML, error or OK
|
||||
* @param[out] sp Socket pointer for notification, otherwise NULL
|
||||
*/
|
||||
int
|
||||
clicon_rpc_netconf_xml(clicon_handle h,
|
||||
cxobj *xin,
|
||||
cxobj **xret,
|
||||
int *sp)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode_xml(xin)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, xret, sp) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_rpc_generate_error(cxobj *xerr)
|
||||
{
|
||||
cxobj *x;
|
||||
char *etype="";
|
||||
char *etag="";
|
||||
char *emsg="";
|
||||
char *einfo="";
|
||||
|
||||
if ((x=xpath_first(xerr, "error-type"))!=NULL)
|
||||
etype = xml_body(x);
|
||||
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
|
||||
etag = xml_body(x);
|
||||
if ((x=xpath_first(xerr, "error-message"))!=NULL)
|
||||
emsg = xml_body(x);
|
||||
if ((x=xpath_first(xerr, "error-info"))!=NULL)
|
||||
einfo = xml_body(x);
|
||||
clicon_err(OE_XML, 0, "%s %s %s %s", etype, etag, emsg, einfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get database configuration
|
||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @param[in] xpath XPath (or "")
|
||||
* @param[out] xt XML tree. must be freed by caller with xml_free
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error, fatal or xml
|
||||
* @code
|
||||
* cxobj *xt = NULL;
|
||||
* if (clicon_rpc_get_config(h, "running", "/", &xt) < 0)
|
||||
* err;
|
||||
* if (xt)
|
||||
* xml_free(xt);
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
clicon_rpc_get_config(clicon_handle h,
|
||||
char *db,
|
||||
char *xpath,
|
||||
cxobj **xt)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *xd;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "<rpc><get-config><source><%s/></source>", db);
|
||||
if (xpath && strlen(xpath))
|
||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||
cprintf(cb, "</get-config></rpc>");
|
||||
if ((msg = clicon_msg_netconf_encode(cbuf_get(cb))) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
if ((xd = xpath_first(xret, "//data/config")) == NULL)
|
||||
if ((xd = xml_new("config", 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;
|
||||
}
|
||||
|
||||
/*! Send database entries as XML to backend daemon
|
||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @param[in] op Operation on database item: OP_MERGE, OP_REPLACE
|
||||
* @param[in] api_path restconf API Path (or "")
|
||||
* @param[in] xml XML string. Ex: <a>..</a><b>...</b>
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* if (clicon_rpc_edit_config(h, "running", OP_MERGE, "/",
|
||||
* "<config><a>4</a></config>") < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
clicon_rpc_edit_config(clicon_handle h,
|
||||
char *db,
|
||||
enum operation_type op,
|
||||
char *api_path,
|
||||
char *xml)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "<rpc><edit-config><target><%s/></target>", db);
|
||||
cprintf(cb, "<default-operation>%s</default-operation>",
|
||||
xml_operation2str(op));
|
||||
if (api_path && strlen(api_path))
|
||||
cprintf(cb, "<filter type=\"restconf\" select=\"%s\"/>", api_path);
|
||||
if (xml)
|
||||
cprintf(cb, "%s", xml);
|
||||
cprintf(cb, "</edit-config></rpc>");
|
||||
if ((msg = clicon_msg_netconf_encode(cbuf_get(cb))) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send a request to backend to copy a file from one location to another
|
||||
* Note this assumes the backend can access these files and (usually) assumes
|
||||
* clients and servers have the access to the same filesystem.
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db1 src database, eg "running"
|
||||
* @param[in] db2 dst database, eg "startup"
|
||||
* @code
|
||||
* if (clicon_rpc_copy_config(h, "running", "startup") < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
clicon_rpc_copy_config(clicon_handle h,
|
||||
char *db1,
|
||||
char *db2)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>", db1, db2)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send a request to backend to delete a config database
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db database, eg "running"
|
||||
* @code
|
||||
* if (clicon_rpc_delete_config(h, "startup") < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
clicon_rpc_delete_config(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><delete-config><target><%s/></target></delete-config></rpc>", db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_rpc_lock(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><lock><target><%s/></target></lock></rpc>", db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_rpc_unlock(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><unlock><target><%s/></target></unlock></rpc>", db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_rpc_close_session(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><close-session/></rpc>")) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_rpc_kill_session(clicon_handle h,
|
||||
int session_id)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><kill-session><session-id>%d</session-id></kill-session></rpc>", session_id)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Send validate request to backend daemon
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
clicon_rpc_validate(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *x;
|
||||
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><validate><source><%s/></source></validate></rpc>", db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
x=xpath_first(xerr, "error-message");
|
||||
clicon_log(LOG_ERR, "Validate failed: \"%s\". Edit and try again or discard changes", x?xml_body(x):"");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (msg)
|
||||
free(msg);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -128,45 +549,69 @@ clicon_rpc_msg(clicon_handle h,
|
|||
* @param[in] h CLICON handle
|
||||
* @param[in] from name of 'from' database (eg "candidate")
|
||||
* @param[in] db name of 'to' database (eg "running")
|
||||
* @retval 0 Copy current->candidate
|
||||
* @retval 0 OK
|
||||
*/
|
||||
int
|
||||
clicon_rpc_commit(clicon_handle h,
|
||||
char *from,
|
||||
char *to)
|
||||
clicon_rpc_commit(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg=clicon_msg_commit_encode(from, to, __FUNCTION__)) == NULL)
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><commit/></rpc>")) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send validate request to backend daemon
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @retval 0
|
||||
/*! Create a new notification subscription
|
||||
* @param[in] h Clicon handle
|
||||
* @param{in] stream name of notificatio/log stream (CLICON is predefined)
|
||||
* @param{in] filter message filter, eg xpath for xml notifications
|
||||
* @param[out] s0 socket returned where notification mesages will appear
|
||||
* @note When using netconf create-subsrciption,status and format is not supported
|
||||
*/
|
||||
int
|
||||
clicon_rpc_validate(clicon_handle h,
|
||||
char *db)
|
||||
clicon_rpc_create_subscription(clicon_handle h,
|
||||
char *stream,
|
||||
char *filter,
|
||||
int *s0)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg=clicon_msg_validate_encode(db, __FUNCTION__)) == NULL)
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><create-subscription>"
|
||||
"<stream>%s</stream>"
|
||||
"<filter>%s</filter>"
|
||||
"</create-subscription></rpc>",
|
||||
stream?stream:"", filter?filter:"")) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -189,160 +634,24 @@ clicon_rpc_change(clicon_handle h,
|
|||
char *val)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
struct clicon_msg *msg = NULL;
|
||||
|
||||
if ((msg = clicon_msg_change_encode(db,
|
||||
op,
|
||||
key,
|
||||
val,
|
||||
val?strlen(val)+1:0,
|
||||
__FUNCTION__)) == NULL)
|
||||
val?strlen(val)+1:0)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
if (msg)
|
||||
free(msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Send database entries as XML to backend daemon
|
||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @param[in] op Operation on database item: OP_MERGE, OP_REPLACE
|
||||
* @param[in] api_path restconf API Path (or "")
|
||||
* @param[in] xml XML string. Ex: <a>..</a><b>...</b>
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clicon_rpc_xmlput(clicon_handle h,
|
||||
char *db,
|
||||
enum operation_type op,
|
||||
char *api_path,
|
||||
char *xml)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
|
||||
if ((msg = clicon_msg_xmlput_encode(db,
|
||||
(uint32_t)op,
|
||||
api_path,
|
||||
xml,
|
||||
__FUNCTION__)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! Send database save request to backend daemon
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @param[in] snapshot Save to snapshot file
|
||||
* @param[in] filename Save to file (backend file-system)
|
||||
*/
|
||||
int
|
||||
clicon_rpc_save(clicon_handle h,
|
||||
char *db,
|
||||
int snapshot,
|
||||
char *filename)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
|
||||
if ((msg=clicon_msg_save_encode(db, snapshot, filename,
|
||||
__FUNCTION__)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send database load request to backend daemon
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] replace 0: merge with existing data, 1:replace completely
|
||||
* @param[in] db Name of database
|
||||
* @param[in] filename Load from file (backend file-system)
|
||||
*/
|
||||
int
|
||||
clicon_rpc_load(clicon_handle h,
|
||||
int replace,
|
||||
char *db,
|
||||
char *filename)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
|
||||
if ((msg=clicon_msg_load_encode(replace, db, filename,
|
||||
__FUNCTION__)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send a request to backend to copy a file from one location to another
|
||||
* Note this assumes the backend can access these files and (usually) assumes
|
||||
* clients and servers have the access to the same filesystem.
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] db1 src database, eg "candidate"
|
||||
* @param[in] db2 dst database, eg "running"
|
||||
*/
|
||||
int
|
||||
clicon_rpc_copy(clicon_handle h,
|
||||
char *db1,
|
||||
char *db2)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
|
||||
if ((msg=clicon_msg_copy_encode(db1, db2, __FUNCTION__)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Send a kill session request to backend server
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] session_id Id of session to kill
|
||||
*/
|
||||
int
|
||||
clicon_rpc_kill(clicon_handle h,
|
||||
int session_id)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
|
||||
if ((msg=clicon_msg_kill_encode(session_id, __FUNCTION__)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Send a debug request to backend server
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] level Debug level
|
||||
|
|
@ -352,107 +661,28 @@ clicon_rpc_debug(clicon_handle h,
|
|||
int level)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
struct clicon_msg *msg = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
|
||||
if ((msg=clicon_msg_debug_encode(level, __FUNCTION__)) == NULL)
|
||||
if ((msg = clicon_msg_netconf_encode("<rpc><debug><level>%d</level></debug></rpc>", level)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! An rpc call from a frontend module to a function in a backend module
|
||||
*
|
||||
* A CLI/netconf frontend module can make a functional call to a backend
|
||||
* module and get return value back.
|
||||
* The backend module needs to be specified (XXX would be nice to avoid this)
|
||||
* parameters can be sent, and value returned.
|
||||
* A function (func) must be defined in the backend module (plugin)
|
||||
* An example signature of such a downcall function is:
|
||||
* @code
|
||||
* char name[16];
|
||||
* char *ret;
|
||||
* uint16_t retlen;
|
||||
* clicon_rpc_call(h, 0, "my-backend-plugin", "my_fn", name, 16,
|
||||
* &ret, &retlen, __FUNCTION__);
|
||||
* unchunk_group(__FUNCTION__); # deallocate 'ret'
|
||||
* @endcode
|
||||
* Backend example function:
|
||||
* @code
|
||||
int
|
||||
downcall(clicon_handle h, uint16_t op, uint16_t len, void *arg,
|
||||
uint16_t *reply_data_len, void **reply_data)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] op Generic application-defined operation
|
||||
* @param[in] plugin Name of backend plugin (XXX look in backend plugin dir)
|
||||
* @param[in] func Name of function i backend (ie downcall above) as string
|
||||
* @param[in] param Input parameter given to function (void* arg in downcall)
|
||||
* @param[in] paramlen Length of input parameter
|
||||
* @param[out] ret Returned data as byte-string. Deallocate w unchunk...(..., label)
|
||||
* @param[out] retlen Length of returned data
|
||||
* @param[in] label Label used in chunk (de)allocation. Use:
|
||||
* unchunk_group(label) to deallocate
|
||||
*/
|
||||
int
|
||||
clicon_rpc_call(clicon_handle h,
|
||||
uint16_t op,
|
||||
char *plugin,
|
||||
char *func,
|
||||
void *param,
|
||||
uint16_t paramlen,
|
||||
char **ret,
|
||||
uint16_t *retlen,
|
||||
const void *label)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *msg;
|
||||
|
||||
if ((msg = clicon_msg_call_encode(op, plugin, func,
|
||||
paramlen, param,
|
||||
label)) == NULL)
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(xerr);
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, (char**)ret, retlen, NULL, label) < 0)
|
||||
}
|
||||
if (xpath_first(xret, "//rpc-reply/ok") == NULL){
|
||||
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create a new notification subscription
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] status 0: stop existing notification stream 1: start new stream.
|
||||
* @param{in] stream name of notificatio/log stream (CLICON is predefined)
|
||||
* @param{in] filter message filter, eg xpath for xml notifications
|
||||
* @param[out] s0 socket returned where notification mesages will appear
|
||||
*/
|
||||
int
|
||||
clicon_rpc_subscription(clicon_handle h,
|
||||
int status,
|
||||
char *stream,
|
||||
enum format_enum format,
|
||||
char *filter,
|
||||
int *s0)
|
||||
{
|
||||
struct clicon_msg *msg;
|
||||
int retval = -1;
|
||||
|
||||
if ((msg=clicon_msg_subscription_encode(status, stream, format, filter,
|
||||
__FUNCTION__)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, NULL, NULL, s0, __FUNCTION__) < 0)
|
||||
goto done;
|
||||
if (status == 0 && s0){
|
||||
close(*s0);
|
||||
*s0 = -1;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
unchunk_group(__FUNCTION__);
|
||||
done:
|
||||
if (msg)
|
||||
free(msg);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue