* Corrected client session handling to make internal IPC socket persistent
* Applies to cli/netconf/restconf/client-api code
* Previous behaviour:
* Close socket after each rpc, but now keeps the socket open until the client terminates
* Kept locks over socket life-cycle, but according to RFC 6241 7.5 a lock should be relaeased when session ends
This commit is contained in:
parent
b41f68b677
commit
f5f013c739
18 changed files with 371 additions and 145 deletions
|
|
@ -55,6 +55,11 @@ Users may have to change how they access the system
|
|||
|
||||
### Minor changes
|
||||
|
||||
* Corrected client session handling to make internal IPC socket persistent
|
||||
* Applies to cli/netconf/restconf/client-api code
|
||||
* Previous behaviour:
|
||||
* Close socket after each rpc, but now keeps the socket open until the client terminates
|
||||
* Kept locks over socket life-cycle, but according to RFC 6241 7.5 a lock should be relaeased when session ends
|
||||
* Restconf evhtp using network namespaces implemented
|
||||
* Added validation of clixon-restconf.yang: server-key-path and server-cert-path must be present if ssl enabled.
|
||||
* Only if `CLICON_BACKEND_RESTCONF_PROCESS` is true
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ backend_terminate(clicon_handle h)
|
|||
yang_stmt *yspec;
|
||||
char *pidfile = clicon_backend_pidfile(h);
|
||||
int sockfamily = clicon_sock_family(h);
|
||||
char *sockpath = clicon_sock(h);
|
||||
char *sockpath = clicon_sock_str(h);
|
||||
cxobj *x;
|
||||
struct stat st;
|
||||
int ss;
|
||||
|
|
@ -552,6 +552,36 @@ restconf_pseudo_process_reg(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/* Debug timer */
|
||||
int
|
||||
backend_timer_setup(int fd,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
clicon_handle h = (clicon_handle)arg;
|
||||
struct timeval now;
|
||||
struct timeval t;
|
||||
struct timeval t1 = {10, 0};
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
backend_client_print(h, stderr);
|
||||
xmldb_print(h, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* Initiate new timer */
|
||||
timeradd(&now, &t1, &t);
|
||||
if (clixon_event_reg_timeout(t,
|
||||
backend_timer_setup, /* this function */
|
||||
h, /* clicon handle */
|
||||
"backend timer setup") < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! usage
|
||||
*/
|
||||
static void
|
||||
|
|
@ -559,7 +589,7 @@ usage(clicon_handle h,
|
|||
char *argv0)
|
||||
{
|
||||
char *plgdir = clicon_backend_dir(h);
|
||||
char *confsock = clicon_sock(h);
|
||||
char *confsock = clicon_sock_str(h);
|
||||
char *confpid = clicon_backend_pidfile(h);
|
||||
char *group = clicon_sock_group(h);
|
||||
|
||||
|
|
@ -829,7 +859,7 @@ main(int argc,
|
|||
goto done;
|
||||
}
|
||||
sockfamily = clicon_sock_family(h);
|
||||
if ((sock = clicon_sock(h)) == NULL){
|
||||
if ((sock = clicon_sock_str(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "sock not set");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1132,7 +1162,9 @@ main(int argc,
|
|||
|
||||
/* Start session-id for clients */
|
||||
clicon_session_id_set(h, 0);
|
||||
|
||||
if (clicon_debug_get() &&
|
||||
backend_timer_setup(0, h) < 0)
|
||||
goto done;
|
||||
if (stream_timer_setup(0, h) < 0)
|
||||
goto done;
|
||||
if (clixon_event_loop() < 0)
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ backend_socket_init(clicon_handle h)
|
|||
{
|
||||
char *sock; /* unix path or ip address string */
|
||||
|
||||
if ((sock = clicon_sock(h)) == NULL){
|
||||
if ((sock = clicon_sock_str(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ typedef void *clixon_client_handle;
|
|||
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_SSH /* NYI External Netconf over SSH */
|
||||
} clixon_client_type;
|
||||
|
||||
/*
|
||||
|
|
@ -68,6 +68,9 @@ int clixon_client_get_uint16(clixon_client_handle ch, uint16_t *rval, const ch
|
|||
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);
|
||||
|
||||
/* Access functions */
|
||||
int clixon_client_socket_get(clixon_client_handle ch);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -102,10 +102,14 @@ int clicon_username_set(clicon_handle h, void *username);
|
|||
enum startup_status clicon_startup_status_get(clicon_handle h);
|
||||
int clicon_startup_status_set(clicon_handle h, enum startup_status status);
|
||||
|
||||
/* Set and get socket fd (ie backend server socket / restconf fcgx socket */
|
||||
/* Set and get server socket fd (ie backend server socket / restconf fcgi socket */
|
||||
int clicon_socket_get(clicon_handle h);
|
||||
int clicon_socket_set(clicon_handle h, int s);
|
||||
|
||||
/* Set and get client socket fd (ie client cli / netconf / restconf / client-api socket */
|
||||
int clicon_client_socket_get(clicon_handle h);
|
||||
int clicon_client_socket_set(clicon_handle h, int s);
|
||||
|
||||
/*! Set and get module state full and brief cached tree */
|
||||
cxobj *clicon_modst_cache_get(clicon_handle h, int brief);
|
||||
int clicon_modst_cache_set(clicon_handle h, int brief, cxobj *xms);
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ static inline int clicon_cli_tab_mode(clicon_handle h){
|
|||
static inline char *clicon_cli_model_treename(clicon_handle h){
|
||||
return clicon_option_str(h, "CLICON_CLI_MODEL_TREENAME");
|
||||
}
|
||||
static inline char *clicon_sock(clicon_handle h){
|
||||
static inline char *clicon_sock_str(clicon_handle h){
|
||||
return clicon_option_str(h, "CLICON_SOCK");
|
||||
}
|
||||
static inline char *clicon_sock_group(clicon_handle h){
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ typedef int (proc_cb_t)(clicon_handle h, process_entry_t *pe, char **operation);
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int clixon_proc_socket(char **argv, pid_t *pid, int *fdin, int *fdout);
|
||||
int clixon_proc_socket_close(pid_t pid, int fdin, int fdout);
|
||||
int clixon_proc_socket(char **argv, pid_t *pid, int *sock);
|
||||
int clixon_proc_socket_close(pid_t pid, int sock);
|
||||
int clixon_proc_background(char **argv, const char *netns, pid_t *pid);
|
||||
int clixon_process_register(clicon_handle h, const char *name, const char *netns, proc_cb_t *callback, char **argv, int argc);
|
||||
int clixon_process_delete_all(clicon_handle h);
|
||||
|
|
|
|||
|
|
@ -83,9 +83,9 @@ int clicon_rpc_connect_inet(clicon_handle h,
|
|||
uint16_t port,
|
||||
int *sock0);
|
||||
|
||||
int clicon_rpc(int fdin, int fdout, struct clicon_msg *msg, char **xret);
|
||||
int clicon_rpc(int sock, struct clicon_msg *msg, char **xret);
|
||||
|
||||
int clicon_rpc1(int fdin, int fdout, cbuf *msgin, cbuf *msgret);
|
||||
int clicon_rpc1(int sock, cbuf *msgin, cbuf *msgret);
|
||||
|
||||
int clicon_msg_send(int s, struct clicon_msg *msg);
|
||||
|
||||
|
|
|
|||
|
|
@ -84,9 +84,9 @@
|
|||
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_socket; /* Input/output socket */
|
||||
int cch_pid; /* Sub-process-id Only applies for NETCONF/SSH */
|
||||
int cch_locked; /* State variable: 1 means locked */
|
||||
};
|
||||
|
||||
/*! Check struct magic number for sanity checks
|
||||
|
|
@ -104,10 +104,9 @@ clixon_client_handle_check(clixon_client_handle ch)
|
|||
}
|
||||
|
||||
/*! 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, or NULL for default
|
||||
* @retval h Clixon handler
|
||||
* @retval NULL Error
|
||||
* @see clixon_client_close
|
||||
*/
|
||||
clixon_handle
|
||||
|
|
@ -129,6 +128,7 @@ clixon_client_init(const char *config_file)
|
|||
}
|
||||
|
||||
/*! Deallocate everything from client_init
|
||||
* @param[in] h Clixon handle
|
||||
* @see clixon_client_init
|
||||
*/
|
||||
int
|
||||
|
|
@ -139,12 +139,67 @@ clixon_client_terminate(clicon_handle h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Send a lock request (internal)
|
||||
* @param[in] sock Open socket
|
||||
* @param[in] lock 0: unlock, 1: lock
|
||||
* @param[in] db Datastore name
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
clixon_client_lock(int sock,
|
||||
const int lock,
|
||||
const char *db)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xd;
|
||||
cbuf *msg = NULL;
|
||||
cbuf *msgret = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (db == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "Expected db");
|
||||
goto done;
|
||||
}
|
||||
if ((msg = cbuf_new()) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((msgret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(msg, "<rpc xmlns=\"%s\">"
|
||||
"<%slock><target><%s/></target></%slock></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
lock?"":"un", db, lock?"":"un");
|
||||
if (clicon_rpc1(sock, msg, msgret) < 0)
|
||||
goto done;
|
||||
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 */
|
||||
clixon_netconf_error(xd, "Get config", NULL);
|
||||
goto done; /* Not fatal */
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (msg)
|
||||
cbuf_free(msg);
|
||||
if (msgret)
|
||||
cbuf_free(msgret);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Connect client to clixon backend according to config and return a socket
|
||||
* @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
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] socktype Type of socket, internal/external/netconf/ssh
|
||||
* @retval ch Clixon session handler
|
||||
* @retval NULL Error
|
||||
* @see clixon_client_disconnect Close the socket returned here
|
||||
*/
|
||||
clixon_client_handle
|
||||
|
|
@ -170,9 +225,8 @@ clixon_client_connect(clicon_handle h,
|
|||
cch->cch_type = socktype;
|
||||
switch (socktype){
|
||||
case CLIXON_CLIENT_IPC:
|
||||
if (clicon_rpc_connect(h, &cch->cch_fdin) < 0)
|
||||
if (clicon_rpc_connect(h, &cch->cch_socket) < 0)
|
||||
goto err;
|
||||
cch->cch_fdout = cch->cch_fdin;
|
||||
break;
|
||||
case CLIXON_CLIENT_NETCONF:
|
||||
nr = 7;
|
||||
|
|
@ -203,23 +257,29 @@ clixon_client_connect(clicon_handle h,
|
|||
}
|
||||
argv[i++] = NULL;
|
||||
assert(i==nr);
|
||||
if (clixon_proc_socket(argv, &cch->cch_pid, &cch->cch_fdin, &cch->cch_fdout) < 0){
|
||||
if (clixon_proc_socket(argv, &cch->cch_pid, &cch->cch_socket) < 0){
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case CLIXON_CLIENT_SSH:
|
||||
break;
|
||||
} /* switch */
|
||||
/* lock */
|
||||
if (clixon_client_lock(cch->cch_socket, 1, "running") < 0)
|
||||
goto err;
|
||||
cch->cch_locked = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%p", __FUNCTION__, cch);
|
||||
return cch;
|
||||
err:
|
||||
free(cch);
|
||||
if (cch)
|
||||
clixon_client_disconnect(cch);
|
||||
cch = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Connect client to clixon backend according to config and return a socket
|
||||
* @param[in] cch Clixon client session handle
|
||||
* @param[in] ch Clixon client session handle
|
||||
* @see clixon_client_connect where the handle is created
|
||||
* The handle is deallocated
|
||||
*/
|
||||
|
|
@ -234,14 +294,17 @@ clixon_client_disconnect(clixon_client_handle ch)
|
|||
clicon_err(OE_XML, EINVAL, "Expected cch handle");
|
||||
goto done;
|
||||
}
|
||||
/* unlock (if locked) */
|
||||
if (cch->cch_locked)
|
||||
;// (void)clixon_client_lock(cch->cch_socket, 0, "running");
|
||||
|
||||
switch(cch->cch_type){
|
||||
case CLIXON_CLIENT_IPC:
|
||||
close(cch->cch_fdin);
|
||||
close(cch->cch_socket);
|
||||
break;
|
||||
case CLIXON_CLIENT_NETCONF:
|
||||
if (clixon_proc_socket_close(cch->cch_pid,
|
||||
cch->cch_fdin,
|
||||
cch->cch_fdout) < 0)
|
||||
cch->cch_socket) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case CLIXON_CLIENT_SSH:
|
||||
|
|
@ -253,6 +316,11 @@ clixon_client_disconnect(clixon_client_handle ch)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Get the bottom-most leaf in an xml tree being a result of xpath
|
||||
* @param[in] xtop Pointer to XML top-of-tree
|
||||
* @param[out] xbotp Pointer to XML bottom node
|
||||
* @retval 0 OK
|
||||
*/
|
||||
static int
|
||||
clixon_xml_bottom(cxobj *xtop,
|
||||
cxobj **xbotp)
|
||||
|
|
@ -283,14 +351,15 @@ clixon_xml_bottom(cxobj *xtop,
|
|||
|
||||
/*! Internal function to construct a get-config and query a value from the backend
|
||||
*
|
||||
* @param[in] sock Stream socket
|
||||
* @param[in] xpath XPath
|
||||
* @param[in] sock Socket
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[out] val String value
|
||||
* @param[in] xpath XPath
|
||||
* @param[out] xdata XML data tree (may or may not include the intended data)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
clixon_client_get_xdata(int fdin,
|
||||
int fdout,
|
||||
clixon_client_get_xdata(int sock,
|
||||
const char *namespace,
|
||||
const char *xpath,
|
||||
cxobj **xdata)
|
||||
|
|
@ -303,6 +372,7 @@ clixon_client_get_xdata(int fdin,
|
|||
const char *db = "running";
|
||||
cvec *nsc = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((msg = cbuf_new()) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -327,7 +397,7 @@ clixon_client_get_xdata(int fdin,
|
|||
cprintf(msg, "/>");
|
||||
}
|
||||
cprintf(msg, "</get-config></rpc>");
|
||||
if (clicon_rpc1(fdin, fdout, msg, msgret) < 0)
|
||||
if (clicon_rpc1(sock, msg, msgret) < 0)
|
||||
goto done;
|
||||
if (clixon_xml_parse_string(cbuf_get(msgret), YB_NONE, NULL, &xret, NULL) < 0)
|
||||
goto done;
|
||||
|
|
@ -357,35 +427,61 @@ clixon_client_get_xdata(int fdin,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Generic get value of body
|
||||
* @param[in] sock Open socket
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath.
|
||||
* @param[in] xpath XPath
|
||||
* @param[out] val Output value
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
clixon_client_get_val(int fdin,
|
||||
int fdout,
|
||||
const char *namespace,
|
||||
const char *xpath,
|
||||
char **val)
|
||||
clixon_client_get_body_val(int sock,
|
||||
const char *namespace,
|
||||
const char *xpath,
|
||||
char **val)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xdata = NULL;
|
||||
cxobj *xobj;
|
||||
cxobj *xobj = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (val == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "Expected val");
|
||||
goto done;
|
||||
}
|
||||
if (clixon_client_get_xdata(fdin, fdout, namespace, xpath, &xdata) < 0)
|
||||
if (clixon_client_get_xdata(sock, namespace, xpath, &xdata) < 0)
|
||||
goto done;
|
||||
if (xdata == NULL){
|
||||
clicon_err(OE_XML, ENODATA, "No xml obj found");
|
||||
goto done;
|
||||
}
|
||||
/* Is this an error, maybe an "unset" retval ? */
|
||||
if (xml_child_nr_type(xdata, CX_ELMNT) == 0){
|
||||
clicon_err(OE_XML, ENODATA, "Value not found");
|
||||
goto done;
|
||||
}
|
||||
if (clixon_xml_bottom(xdata, &xobj) < 0)
|
||||
goto done;
|
||||
if (xobj == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "No bottom xml found");
|
||||
clicon_err(OE_XML, ENODATA, "No xml value found");
|
||||
goto done;
|
||||
}
|
||||
*val = xml_body(xobj);
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Client-api get boolean
|
||||
* @param[in] ch Clixon client handle
|
||||
* @param[out] rval Return value
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_client_get_bool(clixon_client_handle ch,
|
||||
int *rval,
|
||||
|
|
@ -400,9 +496,8 @@ clixon_client_get_bool(clixon_client_handle ch,
|
|||
uint8_t val0=0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clixon_client_get_val(cch->cch_fdin,
|
||||
cch->cch_fdout,
|
||||
namespace, xpath, &val) < 0)
|
||||
if (clixon_client_get_body_val(cch->cch_socket,
|
||||
namespace, xpath, &val) < 0)
|
||||
goto done;
|
||||
if ((ret = parse_bool(val, &val0, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_bool");
|
||||
|
|
@ -420,12 +515,14 @@ clixon_client_get_bool(clixon_client_handle ch,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Get string using get-config
|
||||
* @param[in] sock Stream socket
|
||||
/*! Client-api get string
|
||||
* @param[in] ch Clixon client handle
|
||||
* @param[out] rval Return value string
|
||||
* @param[in] n Length of string
|
||||
* @param[in] xpath XPath
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_client_get_str(clixon_client_handle ch,
|
||||
|
|
@ -439,9 +536,8 @@ clixon_client_get_str(clixon_client_handle ch,
|
|||
char *val = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clixon_client_get_val(cch->cch_fdin,
|
||||
cch->cch_fdout,
|
||||
namespace, xpath, &val) < 0)
|
||||
if (clixon_client_get_body_val(cch->cch_socket,
|
||||
namespace, xpath, &val) < 0)
|
||||
goto done;
|
||||
strncpy(rval, val, n-1);
|
||||
rval[n-1]= '\0';
|
||||
|
|
@ -450,6 +546,14 @@ clixon_client_get_str(clixon_client_handle ch,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Client-api get uint8
|
||||
* @param[in] ch Clixon client handle
|
||||
* @param[out] rval Return value
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_client_get_uint8(clixon_client_handle ch,
|
||||
uint8_t *rval,
|
||||
|
|
@ -463,9 +567,8 @@ clixon_client_get_uint8(clixon_client_handle ch,
|
|||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clixon_client_get_val(cch->cch_fdin,
|
||||
cch->cch_fdout,
|
||||
namespace, xpath, &val) < 0)
|
||||
if (clixon_client_get_body_val(cch->cch_socket,
|
||||
namespace, xpath, &val) < 0)
|
||||
goto done;
|
||||
if ((ret = parse_uint8(val, rval, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_bool");
|
||||
|
|
@ -482,6 +585,14 @@ clixon_client_get_uint8(clixon_client_handle ch,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Client-api get uint16
|
||||
* @param[in] ch Clixon client handle
|
||||
* @param[out] rval Return value
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_client_get_uint16(clixon_client_handle ch,
|
||||
uint16_t *rval,
|
||||
|
|
@ -495,9 +606,8 @@ clixon_client_get_uint16(clixon_client_handle ch,
|
|||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clixon_client_get_val(cch->cch_fdin,
|
||||
cch->cch_fdout,
|
||||
namespace, xpath, &val) < 0)
|
||||
if (clixon_client_get_body_val(cch->cch_socket,
|
||||
namespace, xpath, &val) < 0)
|
||||
goto done;
|
||||
if ((ret = parse_uint16(val, rval, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_bool");
|
||||
|
|
@ -514,6 +624,14 @@ clixon_client_get_uint16(clixon_client_handle ch,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Client-api get uint32
|
||||
* @param[in] ch Clixon client handle
|
||||
* @param[out] rval Return value
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_client_get_uint32(clixon_client_handle ch,
|
||||
uint32_t *rval,
|
||||
|
|
@ -527,10 +645,13 @@ clixon_client_get_uint32(clixon_client_handle ch,
|
|||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clixon_client_get_val(cch->cch_fdin,
|
||||
cch->cch_fdout,
|
||||
namespace, xpath, &val) < 0)
|
||||
if (clixon_client_get_body_val(cch->cch_socket,
|
||||
namespace, xpath, &val) < 0)
|
||||
goto done;
|
||||
if (val == NULL){
|
||||
clicon_err(OE_XML, EFAULT, "val is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = parse_uint32(val, rval, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_bool");
|
||||
goto done;
|
||||
|
|
@ -541,11 +662,20 @@ clixon_client_get_uint32(clixon_client_handle ch,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (reason)
|
||||
free(reason);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Client-api get uint64
|
||||
* @param[in] ch Clixon client handle
|
||||
* @param[out] rval Return value
|
||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||
* @param[in] xpath XPath
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_client_get_uint64(clixon_client_handle ch,
|
||||
uint64_t *rval,
|
||||
|
|
@ -559,9 +689,8 @@ clixon_client_get_uint64(clixon_client_handle ch,
|
|||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clixon_client_get_val(cch->cch_fdin,
|
||||
cch->cch_fdout,
|
||||
namespace, xpath, &val) < 0)
|
||||
if (clixon_client_get_body_val(cch->cch_socket,
|
||||
namespace, xpath, &val) < 0)
|
||||
goto done;
|
||||
if ((ret = parse_uint64(val, rval, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_bool");
|
||||
|
|
@ -577,3 +706,17 @@ clixon_client_get_uint64(clixon_client_handle ch,
|
|||
free(reason);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Access functions */
|
||||
/*! Client-api get uint64
|
||||
* @param[in] ch Clixon client handle
|
||||
* @retval s Open socket
|
||||
* @retval -1 No/closed socket
|
||||
*/
|
||||
int
|
||||
clixon_client_socket_get(clixon_client_handle ch)
|
||||
{
|
||||
struct clixon_client_handle *cch = chandle(ch);
|
||||
|
||||
return cch->cch_socket;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ clicon_startup_status_set(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Get socket fd (ie backend server socket / restconf fcgx socket)
|
||||
/*! Get server socket fd (ie backend server socket / restconf fcgi socket)
|
||||
* @param[in] h Clicon handle
|
||||
* @retval -1 No open socket
|
||||
* @retval s Socket
|
||||
|
|
@ -536,7 +536,7 @@ clicon_socket_get(clicon_handle h)
|
|||
return *(int*)p;
|
||||
}
|
||||
|
||||
/*! Set socket fd (ie backend server socket / restconf fcgx socket)
|
||||
/*! Set server socket fd (ie backend server socket / restconf fcgi socket)
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] s Open socket (or -1 to close)
|
||||
* @retval 0 OK
|
||||
|
|
@ -553,6 +553,39 @@ clicon_socket_set(clicon_handle h,
|
|||
return clicon_hash_add(cdat, "socket", &s, sizeof(int))==NULL?-1:0;
|
||||
}
|
||||
|
||||
/*! Get client socket fd (ie client cli / netconf / restconf / client-api socket
|
||||
* @param[in] h Clicon handle
|
||||
* @retval -1 No open socket
|
||||
* @retval s Socket
|
||||
*/
|
||||
int
|
||||
clicon_client_socket_get(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
void *p;
|
||||
|
||||
if ((p = clicon_hash_value(cdat, "client-socket", NULL)) == NULL)
|
||||
return -1;
|
||||
return *(int*)p;
|
||||
}
|
||||
|
||||
/*! Set client socket fd (ie client cli / netconf / restconf / client-api socket
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] s Open socket (or -1 to close)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clicon_client_socket_set(clicon_handle h,
|
||||
int s)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
if (s == -1)
|
||||
return clicon_hash_del(cdat, "client-socket");
|
||||
return clicon_hash_add(cdat, "client-socket", &s, sizeof(int))==NULL?-1:0;
|
||||
}
|
||||
|
||||
/*! Get module state cache
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] brief 0: Full module state tree, 1: Brief tree (datastore)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "clixon_err.h"
|
||||
|
|
@ -158,6 +159,14 @@ create_socket(struct sockaddr *sa,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Fork a child, create and bind a socket in a separate network namespace and send back to parent
|
||||
*
|
||||
* @param[in] netns Network namespace
|
||||
* @param[in] sa Socketaddress
|
||||
* @param[in] sa_len Length of sa. Tecynicaliyu to be independent of sockaddr sa_len
|
||||
* @param[in] backlog Listen backlog, queie of pending connections
|
||||
* @param[out] sock Server socket (bound for accept)
|
||||
*/
|
||||
int
|
||||
fork_netns_socket(const char *netns,
|
||||
struct sockaddr *sa,
|
||||
|
|
@ -166,8 +175,9 @@ fork_netns_socket(const char *netns,
|
|||
int *sock)
|
||||
{
|
||||
int retval = -1;
|
||||
int sp[2] = {0,};
|
||||
int sp[2] = {-1, -1};
|
||||
pid_t child;
|
||||
int status = 0;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, sp) < 0){
|
||||
clicon_err(OE_UNIX, errno, "socketpair");
|
||||
|
|
@ -209,7 +219,8 @@ fork_netns_socket(const char *netns,
|
|||
if (get_sock(sp[0], sock) < 0)
|
||||
goto done;
|
||||
close(sp[0]);
|
||||
retval = 0;
|
||||
if(waitpid(child, &status, 0) == child)
|
||||
retval = WEXITSTATUS(status);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,23 +105,21 @@ clixon_proc_sigint(int sig)
|
|||
kill(_clicon_proc_child, SIGINT);
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! Fork a child, exec a child and setup socket to child and return to caller
|
||||
* @param[in] argv NULL-terminated Argument vector
|
||||
* @param[in] doerr If non-zero, stderr will be directed to the pipe as well.
|
||||
* @param[out] s Socket
|
||||
* @retval O OK
|
||||
* @retval -1 Error.
|
||||
* @note need to cleanup and wait on sub-process
|
||||
* @see clixon_proc_socket_close close sockets, kill child and wait for child termination
|
||||
*/
|
||||
int
|
||||
clixon_proc_socket(char **argv,
|
||||
pid_t *pid,
|
||||
int *fdin,
|
||||
int *fdout)
|
||||
int *sock)
|
||||
{
|
||||
int retval = -1;
|
||||
int p2c[2] = { -1, -1 }; /* parent->child */
|
||||
int c2p[2] = { -1, -1 }; /* child->parent */
|
||||
int sp[2] = {-1, -1};
|
||||
pid_t child;
|
||||
sigfn_t oldhandler = NULL;
|
||||
sigset_t oset;
|
||||
|
|
@ -131,15 +129,10 @@ clixon_proc_socket(char **argv,
|
|||
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
||||
goto done;
|
||||
}
|
||||
if (pipe2(p2c, O_DIRECT) == -1){ /* parent->child */
|
||||
clicon_err(OE_UNIX, errno, "pipe");
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, sp) < 0){
|
||||
clicon_err(OE_UNIX, errno, "socketpair");
|
||||
goto done;
|
||||
}
|
||||
if (pipe2(c2p, O_DIRECT) == -1){ /* child->parent */
|
||||
clicon_err(OE_UNIX, errno, "pipe");
|
||||
goto done;
|
||||
}
|
||||
// clicon_debug(1, "%s p2c: %d -> %d c2p: %d <- %d", __FUNCTION__, p2c[1], p2c[0], c2p[0], c2p[1]);
|
||||
sigprocmask(0, NULL, &oset);
|
||||
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
|
||||
sig++;
|
||||
|
|
@ -152,24 +145,18 @@ clixon_proc_socket(char **argv,
|
|||
clicon_signal_unblock(0);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
close(sp[0]);
|
||||
close(0);
|
||||
|
||||
if (dup2(p2c[0], STDIN_FILENO) < 0){
|
||||
// if (dup(p2c[0]) < 0){
|
||||
if (dup2(sp[1], STDIN_FILENO) < 0){
|
||||
perror("dup2");
|
||||
return -1;
|
||||
}
|
||||
close(p2c[1]);
|
||||
close(p2c[0]);
|
||||
|
||||
close(1);
|
||||
if (dup2(c2p[1], STDOUT_FILENO) < 0){
|
||||
// if (dup(c2p[1]) < 0){
|
||||
if (dup2(sp[1], STDOUT_FILENO) < 0){
|
||||
perror("dup2");
|
||||
return -1;
|
||||
}
|
||||
close(c2p[1]);
|
||||
close(c2p[0]);
|
||||
close(sp[1]);
|
||||
|
||||
if (execvp(argv[0], argv) < 0){
|
||||
perror("execvp");
|
||||
|
|
@ -178,11 +165,9 @@ clixon_proc_socket(char **argv,
|
|||
exit(-1); /* Shouldnt reach here */
|
||||
}
|
||||
/* Parent */
|
||||
close(p2c[0]);
|
||||
close(c2p[1]);
|
||||
close(sp[1]);
|
||||
*pid = child;
|
||||
*fdout = p2c[1];
|
||||
*fdin = c2p[0];
|
||||
*sock = sp[0];
|
||||
retval = 0;
|
||||
done:
|
||||
if (sig){ /* Restore sigmask and fn */
|
||||
|
|
@ -192,18 +177,18 @@ clixon_proc_socket(char **argv,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @see clixon_proc_socket which creates the child and sockets closed and killed here
|
||||
*/
|
||||
int
|
||||
clixon_proc_socket_close(pid_t pid,
|
||||
int fdin,
|
||||
int fdout)
|
||||
int sock)
|
||||
{
|
||||
int retval = -1;
|
||||
int status;
|
||||
int retval = -1;
|
||||
int status;
|
||||
|
||||
if (fdin != -1)
|
||||
close(fdin);
|
||||
if (fdout != -1)
|
||||
close(fdout); /* Usually kills */
|
||||
if (sock != -1)
|
||||
close(sock); /* usually kills */
|
||||
kill(pid, SIGTERM);
|
||||
// usleep(100000); /* Wait for child to finish */
|
||||
if(waitpid(pid, &status, 0) == pid)
|
||||
|
|
|
|||
|
|
@ -435,6 +435,7 @@ clicon_msg_rcv1(int s,
|
|||
int poll;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
*eof = 0;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
while (1){
|
||||
if ((len = read(s, buf, sizeof(buf))) < 0){
|
||||
|
|
@ -446,7 +447,7 @@ clicon_msg_rcv1(int s,
|
|||
}
|
||||
} /* read */
|
||||
if (len == 0){ /* EOF */
|
||||
// cc_closed++;
|
||||
*eof = 1;
|
||||
close(s);
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -473,8 +474,6 @@ clicon_msg_rcv1(int s,
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s done", __FUNCTION__);
|
||||
// if (cc_closed)
|
||||
// retval = -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -597,31 +596,29 @@ clicon_rpc_connect_inet(clicon_handle h,
|
|||
* errno set to ENOTCONN which means that socket is now closed probably
|
||||
* due to remote peer disconnecting. The caller may have to do something,...
|
||||
*
|
||||
* @param[in] fdin Input file descriptor
|
||||
* @param[in] fdout Output file descriptor (for socket same as fdin)
|
||||
* @param[in] sock Socket / file descriptor
|
||||
* @param[in] msg CLICON msg data structure. It has fixed header and variable body.
|
||||
* @param[out] xret Returned data as netconf xml tree.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clicon_rpc(int fdin,
|
||||
int fdout,
|
||||
struct clicon_msg *msg,
|
||||
char **ret)
|
||||
clicon_rpc(int sock,
|
||||
struct clicon_msg *msg,
|
||||
char **ret)
|
||||
{
|
||||
int retval = -1;
|
||||
struct clicon_msg *reply = NULL;
|
||||
int eof;
|
||||
char *data = NULL;
|
||||
|
||||
if (clicon_msg_send(fdout, msg) < 0)
|
||||
if (clicon_msg_send(sock, msg) < 0)
|
||||
goto done;
|
||||
if (clicon_msg_rcv(fdin, &reply, &eof) < 0)
|
||||
if (clicon_msg_rcv(sock, &reply, &eof) < 0)
|
||||
goto done;
|
||||
if (eof){
|
||||
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
|
||||
close(fdin); /* assume socket */
|
||||
close(sock); /* assume socket */
|
||||
errno = ESHUTDOWN;
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -645,8 +642,7 @@ clicon_rpc(int fdin,
|
|||
* errno set to ENOTCONN which means that socket is now closed probably
|
||||
* due to remote peer disconnecting. The caller may have to do something,...
|
||||
*
|
||||
* @param[in] fdin Input file descriptor
|
||||
* @param[in] fdout Output file descriptor (for socket same as fdin)
|
||||
* @param[in] sock Socket / file descriptor
|
||||
* @param[in] msgin CLICON msg data structure. It has fixed header and variable body.
|
||||
* @param[out] msgret Returned data as netconf xml tree.
|
||||
* @retval 0 OK
|
||||
|
|
@ -654,22 +650,21 @@ clicon_rpc(int fdin,
|
|||
* see clicon_rpc using clicon_msg
|
||||
*/
|
||||
int
|
||||
clicon_rpc1(int fdin,
|
||||
int fdout,
|
||||
cbuf *msg,
|
||||
cbuf *msgret)
|
||||
clicon_rpc1(int sock,
|
||||
cbuf *msg,
|
||||
cbuf *msgret)
|
||||
{
|
||||
int retval = -1;
|
||||
int eof;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (clicon_msg_send1(fdout, msg) < 0)
|
||||
if (clicon_msg_send1(sock, msg) < 0)
|
||||
goto done;
|
||||
if (clicon_msg_rcv1(fdin, msgret, &eof) < 0)
|
||||
if (clicon_msg_rcv1(sock, msgret, &eof) < 0)
|
||||
goto done;
|
||||
if (eof){
|
||||
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
|
||||
close(fdin); /* assume socket */
|
||||
close(sock);
|
||||
errno = ESHUTDOWN;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,20 +86,20 @@
|
|||
*/
|
||||
int
|
||||
clicon_rpc_connect(clicon_handle h,
|
||||
int *sock0)
|
||||
int *sockp)
|
||||
{
|
||||
int retval = -1;
|
||||
char *sock = NULL;
|
||||
char *sockstr = NULL;
|
||||
int port;
|
||||
|
||||
if ((sock = clicon_sock(h)) == NULL){
|
||||
if ((sockstr = clicon_sock_str(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||
goto done;
|
||||
}
|
||||
/* What to do if inet socket? */
|
||||
switch (clicon_sock_family(h)){
|
||||
case AF_UNIX:
|
||||
if (clicon_rpc_connect_unix(h, sock, sock0) < 0){
|
||||
if (clicon_rpc_connect_unix(h, sockstr, sockp) < 0){
|
||||
#if 0
|
||||
if (errno == ESHUTDOWN)
|
||||
/* Maybe could reconnect on a higher layer, but lets fail
|
||||
|
|
@ -118,7 +118,7 @@ clicon_rpc_connect(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "CLICON_SOCK_PORT not set");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_connect_inet(h, sock, port, sock0) < 0)
|
||||
if (clicon_rpc_connect_inet(h, sockstr, port, sockp) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
|
@ -152,9 +152,12 @@ clicon_rpc_msg(clicon_handle h,
|
|||
#endif
|
||||
clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body);
|
||||
/* Create a socket and connect to it, either UNIX, IPv4 or IPv6 per config options */
|
||||
if (clicon_rpc_connect(h, &s) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc(s, s, msg, &retdata) < 0)
|
||||
if ((s = clicon_client_socket_get(h)) < 0){
|
||||
if (clicon_rpc_connect(h, &s) < 0)
|
||||
goto done;
|
||||
clicon_client_socket_set(h, s);
|
||||
}
|
||||
if (clicon_rpc(s, msg, &retdata) < 0)
|
||||
goto done;
|
||||
|
||||
clicon_debug(1, "%s retdata:%s", __FUNCTION__, retdata);
|
||||
|
|
@ -177,8 +180,6 @@ clicon_rpc_msg(clicon_handle h,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (s != -1)
|
||||
close(s);
|
||||
if (retdata)
|
||||
free(retdata);
|
||||
if (xret)
|
||||
|
|
@ -308,7 +309,6 @@ clicon_rpc_netconf_xml(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Get database configuration
|
||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
||||
* @param[in] h CLICON handle
|
||||
|
|
@ -786,10 +786,12 @@ clicon_rpc_get(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Close a (user) session
|
||||
/*! Send a close a netconf user session. Socket is also closed if still open
|
||||
* @param[in] h CLICON handle
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error and logged to syslog
|
||||
* Session is implicitly created in eg clicon_rpc_netconf
|
||||
* @note Maybe separate closing session and closing socket.
|
||||
*/
|
||||
int
|
||||
clicon_rpc_close_session(clicon_handle h)
|
||||
|
|
@ -800,6 +802,7 @@ clicon_rpc_close_session(clicon_handle h)
|
|||
cxobj *xerr;
|
||||
char *username;
|
||||
uint32_t session_id;
|
||||
int s;
|
||||
|
||||
if (session_id_check(h, &session_id) < 0)
|
||||
goto done;
|
||||
|
|
@ -810,6 +813,10 @@ clicon_rpc_close_session(clicon_handle h)
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((s = clicon_client_socket_get(h)) >= 0){
|
||||
close(s);
|
||||
clicon_client_socket_set(h, -1);
|
||||
}
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clixon_netconf_error(xerr, "Close session", NULL);
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ fyang=$dir/example-client.yang
|
|||
cfile=$dir/example-client.c
|
||||
pdir=$dir/plugin
|
||||
app=$dir/clixon-app
|
||||
debug=0
|
||||
|
||||
if [ ! -d $pdir ]; then
|
||||
mkdir $pdir
|
||||
|
|
@ -68,19 +69,21 @@ cat<<EOF > $cfile
|
|||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syslog.h> // debug
|
||||
|
||||
#include <clixon/clixon_log.h>
|
||||
#include <clixon/clixon_log.h> // debug
|
||||
#include <clixon/clixon_client.h>
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
clixon_handle h = NULL; /* clixon handle */
|
||||
clixon_client_handle ch = NULL; /* clixon client handle */
|
||||
|
||||
// clicon_log_init("client", LOG_DEBUG, CLICON_LOG_STDERR); // debug
|
||||
// clicon_debug_init(1, NULL); // debug
|
||||
clicon_log_init("client", LOG_DEBUG, CLICON_LOG_STDERR); // debug
|
||||
clicon_debug_init($debug, NULL); // debug
|
||||
|
||||
/* Provide a clixon config-file, get a clixon handle */
|
||||
if ((h = clixon_client_init("$cfg")) == NULL)
|
||||
|
|
@ -94,12 +97,15 @@ main(int argc,
|
|||
{
|
||||
uint32_t u = 0;
|
||||
if (clixon_client_get_uint32(ch, &u, "urn:example:clixon-client", "/table/parameter[name='a']/value") < 0)
|
||||
return -1;
|
||||
goto done;
|
||||
printf("%u\n", u); /* for test output */
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clixon_client_disconnect(ch);
|
||||
clixon_client_terminate(h);
|
||||
return 0;
|
||||
printf("done\n"); /* for test output */
|
||||
return retval;
|
||||
}
|
||||
EOF
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<xx:rpc xmlns:xx=\"urn:ietf:params:xml:n
|
|||
new "netconf lock/unlock"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>]]>]]><rpc $DEFAULTNS><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]><rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf lock/unlock/lock"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>]]>]]><rpc $DEFAULTNS><unlock><target><candidate/></target></unlock></rpc>]]>]]><rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]><rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]><rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf lock/lock"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>]]>]]><rpc $DEFAULTNS><lock><target><candidate/></target></lock></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]><rpc-reply $DEFAULTNS><rpc-error><error-type>protocol</error-type><error-tag>lock-denied</error-tag><error-info><session-id>"
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' http:
|
|||
|
||||
# Negative
|
||||
new "restconf get config on wrong port in netns:$netns"
|
||||
expectpart "$(sudo ip netns exec $netns curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://$vaddr:8888/restconf/data/clixon-example:table)" 7
|
||||
expectpart "$(sudo ip netns exec $netns curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://$vaddr:8888/restconf/data/clixon-example:table 2> /dev/null)" 7
|
||||
|
||||
if [ $RC -ne 0 ]; then
|
||||
new "Kill restconf daemon"
|
||||
|
|
@ -192,4 +192,3 @@ new "endtest"
|
|||
endtest
|
||||
|
||||
rm -rf $dir
|
||||
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ main(int argc,
|
|||
else
|
||||
if (clicon_rpc_connect_inet(h, sockpath, 4535, &s) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc(s, s, msg, &retdata) < 0)
|
||||
if (clicon_rpc(s, msg, &retdata) < 0)
|
||||
goto done;
|
||||
close(s);
|
||||
fprintf(stdout, "%s\n", retdata);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue