* 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
|
### 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
|
* 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.
|
* 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
|
* Only if `CLICON_BACKEND_RESTCONF_PROCESS` is true
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ backend_terminate(clicon_handle h)
|
||||||
yang_stmt *yspec;
|
yang_stmt *yspec;
|
||||||
char *pidfile = clicon_backend_pidfile(h);
|
char *pidfile = clicon_backend_pidfile(h);
|
||||||
int sockfamily = clicon_sock_family(h);
|
int sockfamily = clicon_sock_family(h);
|
||||||
char *sockpath = clicon_sock(h);
|
char *sockpath = clicon_sock_str(h);
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int ss;
|
int ss;
|
||||||
|
|
@ -552,6 +552,36 @@ restconf_pseudo_process_reg(clicon_handle h,
|
||||||
return retval;
|
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
|
/*! usage
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
|
@ -559,7 +589,7 @@ usage(clicon_handle h,
|
||||||
char *argv0)
|
char *argv0)
|
||||||
{
|
{
|
||||||
char *plgdir = clicon_backend_dir(h);
|
char *plgdir = clicon_backend_dir(h);
|
||||||
char *confsock = clicon_sock(h);
|
char *confsock = clicon_sock_str(h);
|
||||||
char *confpid = clicon_backend_pidfile(h);
|
char *confpid = clicon_backend_pidfile(h);
|
||||||
char *group = clicon_sock_group(h);
|
char *group = clicon_sock_group(h);
|
||||||
|
|
||||||
|
|
@ -829,7 +859,7 @@ main(int argc,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
sockfamily = clicon_sock_family(h);
|
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");
|
clicon_err(OE_FATAL, 0, "sock not set");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1132,7 +1162,9 @@ main(int argc,
|
||||||
|
|
||||||
/* Start session-id for clients */
|
/* Start session-id for clients */
|
||||||
clicon_session_id_set(h, 0);
|
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)
|
if (stream_timer_setup(0, h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clixon_event_loop() < 0)
|
if (clixon_event_loop() < 0)
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ backend_socket_init(clicon_handle h)
|
||||||
{
|
{
|
||||||
char *sock; /* unix path or ip address string */
|
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");
|
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ typedef void *clixon_client_handle;
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CLIXON_CLIENT_IPC, /* Internal IPC API, only experimental use */
|
CLIXON_CLIENT_IPC, /* Internal IPC API, only experimental use */
|
||||||
CLIXON_CLIENT_NETCONF, /* External Netconf */
|
CLIXON_CLIENT_NETCONF, /* External Netconf */
|
||||||
CLIXON_CLIENT_SSH /* External Netconf over SSH */
|
CLIXON_CLIENT_SSH /* NYI External Netconf over SSH */
|
||||||
} clixon_client_type;
|
} 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_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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -102,10 +102,14 @@ int clicon_username_set(clicon_handle h, void *username);
|
||||||
enum startup_status clicon_startup_status_get(clicon_handle h);
|
enum startup_status clicon_startup_status_get(clicon_handle h);
|
||||||
int clicon_startup_status_set(clicon_handle h, enum startup_status status);
|
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_get(clicon_handle h);
|
||||||
int clicon_socket_set(clicon_handle h, int s);
|
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 */
|
/*! Set and get module state full and brief cached tree */
|
||||||
cxobj *clicon_modst_cache_get(clicon_handle h, int brief);
|
cxobj *clicon_modst_cache_get(clicon_handle h, int brief);
|
||||||
int clicon_modst_cache_set(clicon_handle h, int brief, cxobj *xms);
|
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){
|
static inline char *clicon_cli_model_treename(clicon_handle h){
|
||||||
return clicon_option_str(h, "CLICON_CLI_MODEL_TREENAME");
|
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");
|
return clicon_option_str(h, "CLICON_SOCK");
|
||||||
}
|
}
|
||||||
static inline char *clicon_sock_group(clicon_handle h){
|
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
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int clixon_proc_socket(char **argv, 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 fdin, int fdout);
|
int clixon_proc_socket_close(pid_t pid, int sock);
|
||||||
int clixon_proc_background(char **argv, const char *netns, pid_t *pid);
|
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_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);
|
int clixon_process_delete_all(clicon_handle h);
|
||||||
|
|
|
||||||
|
|
@ -83,9 +83,9 @@ int clicon_rpc_connect_inet(clicon_handle h,
|
||||||
uint16_t port,
|
uint16_t port,
|
||||||
int *sock0);
|
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);
|
int clicon_msg_send(int s, struct clicon_msg *msg);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,9 @@
|
||||||
struct clixon_client_handle{
|
struct clixon_client_handle{
|
||||||
uint32_t cch_magic; /* magic number */
|
uint32_t cch_magic; /* magic number */
|
||||||
clixon_client_type cch_type; /* Clixon socket type */
|
clixon_client_type cch_type; /* Clixon socket type */
|
||||||
int cch_fdin; /* Input file descriptor */
|
int cch_socket; /* Input/output socket */
|
||||||
int cch_fdout; /* Output file descriptor, Only applies for NETCONF/SSH */
|
|
||||||
int cch_pid; /* Sub-process-id Only applies for NETCONF/SSH */
|
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
|
/*! Check struct magic number for sanity checks
|
||||||
|
|
@ -104,10 +104,9 @@ clixon_client_handle_check(clixon_client_handle ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Initialize Clixon client API
|
/*! 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
|
* @param[in] config_file Clixon configuration file, or NULL for default
|
||||||
|
* @retval h Clixon handler
|
||||||
|
* @retval NULL Error
|
||||||
* @see clixon_client_close
|
* @see clixon_client_close
|
||||||
*/
|
*/
|
||||||
clixon_handle
|
clixon_handle
|
||||||
|
|
@ -129,6 +128,7 @@ clixon_client_init(const char *config_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Deallocate everything from client_init
|
/*! Deallocate everything from client_init
|
||||||
|
* @param[in] h Clixon handle
|
||||||
* @see clixon_client_init
|
* @see clixon_client_init
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -139,12 +139,67 @@ clixon_client_terminate(clicon_handle h)
|
||||||
return 0;
|
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
|
/*! Connect client to clixon backend according to config and return a socket
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[out] fdin Open netconf output file descr
|
* @param[in] socktype Type of socket, internal/external/netconf/ssh
|
||||||
* @param[out] fdout Open netconf output file descr. If socket same as fdin
|
* @retval ch Clixon session handler
|
||||||
* @retval cs Clixon session handler
|
* @retval NULL Error
|
||||||
* @retval NULL Error
|
|
||||||
* @see clixon_client_disconnect Close the socket returned here
|
* @see clixon_client_disconnect Close the socket returned here
|
||||||
*/
|
*/
|
||||||
clixon_client_handle
|
clixon_client_handle
|
||||||
|
|
@ -170,9 +225,8 @@ clixon_client_connect(clicon_handle h,
|
||||||
cch->cch_type = socktype;
|
cch->cch_type = socktype;
|
||||||
switch (socktype){
|
switch (socktype){
|
||||||
case CLIXON_CLIENT_IPC:
|
case CLIXON_CLIENT_IPC:
|
||||||
if (clicon_rpc_connect(h, &cch->cch_fdin) < 0)
|
if (clicon_rpc_connect(h, &cch->cch_socket) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
cch->cch_fdout = cch->cch_fdin;
|
|
||||||
break;
|
break;
|
||||||
case CLIXON_CLIENT_NETCONF:
|
case CLIXON_CLIENT_NETCONF:
|
||||||
nr = 7;
|
nr = 7;
|
||||||
|
|
@ -203,23 +257,29 @@ clixon_client_connect(clicon_handle h,
|
||||||
}
|
}
|
||||||
argv[i++] = NULL;
|
argv[i++] = NULL;
|
||||||
assert(i==nr);
|
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;
|
goto err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLIXON_CLIENT_SSH:
|
case CLIXON_CLIENT_SSH:
|
||||||
break;
|
break;
|
||||||
} /* switch */
|
} /* switch */
|
||||||
|
/* lock */
|
||||||
|
if (clixon_client_lock(cch->cch_socket, 1, "running") < 0)
|
||||||
|
goto err;
|
||||||
|
cch->cch_locked = 1;
|
||||||
done:
|
done:
|
||||||
|
clicon_debug(1, "%s retval:%p", __FUNCTION__, cch);
|
||||||
return cch;
|
return cch;
|
||||||
err:
|
err:
|
||||||
free(cch);
|
if (cch)
|
||||||
|
clixon_client_disconnect(cch);
|
||||||
cch = NULL;
|
cch = NULL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Connect client to clixon backend according to config and return a socket
|
/*! 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
|
* @see clixon_client_connect where the handle is created
|
||||||
* The handle is deallocated
|
* The handle is deallocated
|
||||||
*/
|
*/
|
||||||
|
|
@ -234,14 +294,17 @@ clixon_client_disconnect(clixon_client_handle ch)
|
||||||
clicon_err(OE_XML, EINVAL, "Expected cch handle");
|
clicon_err(OE_XML, EINVAL, "Expected cch handle");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* unlock (if locked) */
|
||||||
|
if (cch->cch_locked)
|
||||||
|
;// (void)clixon_client_lock(cch->cch_socket, 0, "running");
|
||||||
|
|
||||||
switch(cch->cch_type){
|
switch(cch->cch_type){
|
||||||
case CLIXON_CLIENT_IPC:
|
case CLIXON_CLIENT_IPC:
|
||||||
close(cch->cch_fdin);
|
close(cch->cch_socket);
|
||||||
break;
|
break;
|
||||||
case CLIXON_CLIENT_NETCONF:
|
case CLIXON_CLIENT_NETCONF:
|
||||||
if (clixon_proc_socket_close(cch->cch_pid,
|
if (clixon_proc_socket_close(cch->cch_pid,
|
||||||
cch->cch_fdin,
|
cch->cch_socket) < 0)
|
||||||
cch->cch_fdout) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case CLIXON_CLIENT_SSH:
|
case CLIXON_CLIENT_SSH:
|
||||||
|
|
@ -253,6 +316,11 @@ clixon_client_disconnect(clixon_client_handle ch)
|
||||||
return retval;
|
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
|
static int
|
||||||
clixon_xml_bottom(cxobj *xtop,
|
clixon_xml_bottom(cxobj *xtop,
|
||||||
cxobj **xbotp)
|
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
|
/*! Internal function to construct a get-config and query a value from the backend
|
||||||
*
|
*
|
||||||
* @param[in] sock Stream socket
|
* @param[in] sock Socket
|
||||||
* @param[in] xpath XPath
|
|
||||||
* @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
* @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
|
static int
|
||||||
clixon_client_get_xdata(int fdin,
|
clixon_client_get_xdata(int sock,
|
||||||
int fdout,
|
|
||||||
const char *namespace,
|
const char *namespace,
|
||||||
const char *xpath,
|
const char *xpath,
|
||||||
cxobj **xdata)
|
cxobj **xdata)
|
||||||
|
|
@ -303,6 +372,7 @@ clixon_client_get_xdata(int fdin,
|
||||||
const char *db = "running";
|
const char *db = "running";
|
||||||
cvec *nsc = NULL;
|
cvec *nsc = NULL;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((msg = cbuf_new()) == NULL){
|
if ((msg = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -327,7 +397,7 @@ clixon_client_get_xdata(int fdin,
|
||||||
cprintf(msg, "/>");
|
cprintf(msg, "/>");
|
||||||
}
|
}
|
||||||
cprintf(msg, "</get-config></rpc>");
|
cprintf(msg, "</get-config></rpc>");
|
||||||
if (clicon_rpc1(fdin, fdout, msg, msgret) < 0)
|
if (clicon_rpc1(sock, msg, msgret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clixon_xml_parse_string(cbuf_get(msgret), YB_NONE, NULL, &xret, NULL) < 0)
|
if (clixon_xml_parse_string(cbuf_get(msgret), YB_NONE, NULL, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -357,35 +427,61 @@ clixon_client_get_xdata(int fdin,
|
||||||
return retval;
|
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
|
static int
|
||||||
clixon_client_get_val(int fdin,
|
clixon_client_get_body_val(int sock,
|
||||||
int fdout,
|
const char *namespace,
|
||||||
const char *namespace,
|
const char *xpath,
|
||||||
const char *xpath,
|
char **val)
|
||||||
char **val)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xdata = NULL;
|
cxobj *xdata = NULL;
|
||||||
cxobj *xobj;
|
cxobj *xobj = NULL;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (val == NULL){
|
if (val == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "Expected val");
|
clicon_err(OE_XML, EINVAL, "Expected val");
|
||||||
goto done;
|
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;
|
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)
|
if (clixon_xml_bottom(xdata, &xobj) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xobj == NULL){
|
if (xobj == NULL){
|
||||||
clicon_err(OE_XML, EFAULT, "No bottom xml found");
|
clicon_err(OE_XML, ENODATA, "No xml value found");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
*val = xml_body(xobj);
|
*val = xml_body(xobj);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
return 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
|
int
|
||||||
clixon_client_get_bool(clixon_client_handle ch,
|
clixon_client_get_bool(clixon_client_handle ch,
|
||||||
int *rval,
|
int *rval,
|
||||||
|
|
@ -400,9 +496,8 @@ clixon_client_get_bool(clixon_client_handle ch,
|
||||||
uint8_t val0=0;
|
uint8_t val0=0;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clixon_client_get_val(cch->cch_fdin,
|
if (clixon_client_get_body_val(cch->cch_socket,
|
||||||
cch->cch_fdout,
|
namespace, xpath, &val) < 0)
|
||||||
namespace, xpath, &val) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if ((ret = parse_bool(val, &val0, &reason)) < 0){
|
if ((ret = parse_bool(val, &val0, &reason)) < 0){
|
||||||
clicon_err(OE_XML, errno, "parse_bool");
|
clicon_err(OE_XML, errno, "parse_bool");
|
||||||
|
|
@ -420,12 +515,14 @@ clixon_client_get_bool(clixon_client_handle ch,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get string using get-config
|
/*! Client-api get string
|
||||||
* @param[in] sock Stream socket
|
* @param[in] ch Clixon client handle
|
||||||
* @param[out] rval Return value string
|
* @param[out] rval Return value string
|
||||||
* @param[in] n Length of 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] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc)
|
||||||
|
* @param[in] xpath XPath
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_client_get_str(clixon_client_handle ch,
|
clixon_client_get_str(clixon_client_handle ch,
|
||||||
|
|
@ -439,9 +536,8 @@ clixon_client_get_str(clixon_client_handle ch,
|
||||||
char *val = NULL;
|
char *val = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clixon_client_get_val(cch->cch_fdin,
|
if (clixon_client_get_body_val(cch->cch_socket,
|
||||||
cch->cch_fdout,
|
namespace, xpath, &val) < 0)
|
||||||
namespace, xpath, &val) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
strncpy(rval, val, n-1);
|
strncpy(rval, val, n-1);
|
||||||
rval[n-1]= '\0';
|
rval[n-1]= '\0';
|
||||||
|
|
@ -450,6 +546,14 @@ clixon_client_get_str(clixon_client_handle ch,
|
||||||
return retval;
|
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
|
int
|
||||||
clixon_client_get_uint8(clixon_client_handle ch,
|
clixon_client_get_uint8(clixon_client_handle ch,
|
||||||
uint8_t *rval,
|
uint8_t *rval,
|
||||||
|
|
@ -463,9 +567,8 @@ clixon_client_get_uint8(clixon_client_handle ch,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clixon_client_get_val(cch->cch_fdin,
|
if (clixon_client_get_body_val(cch->cch_socket,
|
||||||
cch->cch_fdout,
|
namespace, xpath, &val) < 0)
|
||||||
namespace, xpath, &val) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if ((ret = parse_uint8(val, rval, &reason)) < 0){
|
if ((ret = parse_uint8(val, rval, &reason)) < 0){
|
||||||
clicon_err(OE_XML, errno, "parse_bool");
|
clicon_err(OE_XML, errno, "parse_bool");
|
||||||
|
|
@ -482,6 +585,14 @@ clixon_client_get_uint8(clixon_client_handle ch,
|
||||||
return retval;
|
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
|
int
|
||||||
clixon_client_get_uint16(clixon_client_handle ch,
|
clixon_client_get_uint16(clixon_client_handle ch,
|
||||||
uint16_t *rval,
|
uint16_t *rval,
|
||||||
|
|
@ -495,9 +606,8 @@ clixon_client_get_uint16(clixon_client_handle ch,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clixon_client_get_val(cch->cch_fdin,
|
if (clixon_client_get_body_val(cch->cch_socket,
|
||||||
cch->cch_fdout,
|
namespace, xpath, &val) < 0)
|
||||||
namespace, xpath, &val) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if ((ret = parse_uint16(val, rval, &reason)) < 0){
|
if ((ret = parse_uint16(val, rval, &reason)) < 0){
|
||||||
clicon_err(OE_XML, errno, "parse_bool");
|
clicon_err(OE_XML, errno, "parse_bool");
|
||||||
|
|
@ -514,6 +624,14 @@ clixon_client_get_uint16(clixon_client_handle ch,
|
||||||
return retval;
|
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
|
int
|
||||||
clixon_client_get_uint32(clixon_client_handle ch,
|
clixon_client_get_uint32(clixon_client_handle ch,
|
||||||
uint32_t *rval,
|
uint32_t *rval,
|
||||||
|
|
@ -527,10 +645,13 @@ clixon_client_get_uint32(clixon_client_handle ch,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clixon_client_get_val(cch->cch_fdin,
|
if (clixon_client_get_body_val(cch->cch_socket,
|
||||||
cch->cch_fdout,
|
namespace, xpath, &val) < 0)
|
||||||
namespace, xpath, &val) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
if (val == NULL){
|
||||||
|
clicon_err(OE_XML, EFAULT, "val is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((ret = parse_uint32(val, rval, &reason)) < 0){
|
if ((ret = parse_uint32(val, rval, &reason)) < 0){
|
||||||
clicon_err(OE_XML, errno, "parse_bool");
|
clicon_err(OE_XML, errno, "parse_bool");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -541,11 +662,20 @@ clixon_client_get_uint32(clixon_client_handle ch,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
if (reason)
|
if (reason)
|
||||||
free(reason);
|
free(reason);
|
||||||
return retval;
|
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
|
int
|
||||||
clixon_client_get_uint64(clixon_client_handle ch,
|
clixon_client_get_uint64(clixon_client_handle ch,
|
||||||
uint64_t *rval,
|
uint64_t *rval,
|
||||||
|
|
@ -559,9 +689,8 @@ clixon_client_get_uint64(clixon_client_handle ch,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clixon_client_get_val(cch->cch_fdin,
|
if (clixon_client_get_body_val(cch->cch_socket,
|
||||||
cch->cch_fdout,
|
namespace, xpath, &val) < 0)
|
||||||
namespace, xpath, &val) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if ((ret = parse_uint64(val, rval, &reason)) < 0){
|
if ((ret = parse_uint64(val, rval, &reason)) < 0){
|
||||||
clicon_err(OE_XML, errno, "parse_bool");
|
clicon_err(OE_XML, errno, "parse_bool");
|
||||||
|
|
@ -577,3 +706,17 @@ clixon_client_get_uint64(clixon_client_handle ch,
|
||||||
free(reason);
|
free(reason);
|
||||||
return retval;
|
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;
|
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
|
* @param[in] h Clicon handle
|
||||||
* @retval -1 No open socket
|
* @retval -1 No open socket
|
||||||
* @retval s Socket
|
* @retval s Socket
|
||||||
|
|
@ -536,7 +536,7 @@ clicon_socket_get(clicon_handle h)
|
||||||
return *(int*)p;
|
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] h Clicon handle
|
||||||
* @param[in] s Open socket (or -1 to close)
|
* @param[in] s Open socket (or -1 to close)
|
||||||
* @retval 0 OK
|
* @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;
|
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
|
/*! Get module state cache
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] brief 0: Full module state tree, 1: Brief tree (datastore)
|
* @param[in] brief 0: Full module state tree, 1: Brief tree (datastore)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
|
|
@ -158,6 +159,14 @@ create_socket(struct sockaddr *sa,
|
||||||
return retval;
|
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
|
int
|
||||||
fork_netns_socket(const char *netns,
|
fork_netns_socket(const char *netns,
|
||||||
struct sockaddr *sa,
|
struct sockaddr *sa,
|
||||||
|
|
@ -166,8 +175,9 @@ fork_netns_socket(const char *netns,
|
||||||
int *sock)
|
int *sock)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int sp[2] = {0,};
|
int sp[2] = {-1, -1};
|
||||||
pid_t child;
|
pid_t child;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, sp) < 0){
|
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, sp) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "socketpair");
|
clicon_err(OE_UNIX, errno, "socketpair");
|
||||||
|
|
@ -209,7 +219,8 @@ fork_netns_socket(const char *netns,
|
||||||
if (get_sock(sp[0], sock) < 0)
|
if (get_sock(sp[0], sock) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
close(sp[0]);
|
close(sp[0]);
|
||||||
retval = 0;
|
if(waitpid(child, &status, 0) == child)
|
||||||
|
retval = WEXITSTATUS(status);
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,23 +105,21 @@ clixon_proc_sigint(int sig)
|
||||||
kill(_clicon_proc_child, SIGINT);
|
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] argv NULL-terminated Argument vector
|
||||||
* @param[in] doerr If non-zero, stderr will be directed to the pipe as well.
|
* @param[in] doerr If non-zero, stderr will be directed to the pipe as well.
|
||||||
* @param[out] s Socket
|
* @param[out] s Socket
|
||||||
* @retval O OK
|
* @retval O OK
|
||||||
* @retval -1 Error.
|
* @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
|
int
|
||||||
clixon_proc_socket(char **argv,
|
clixon_proc_socket(char **argv,
|
||||||
pid_t *pid,
|
pid_t *pid,
|
||||||
int *fdin,
|
int *sock)
|
||||||
int *fdout)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int p2c[2] = { -1, -1 }; /* parent->child */
|
int sp[2] = {-1, -1};
|
||||||
int c2p[2] = { -1, -1 }; /* child->parent */
|
|
||||||
pid_t child;
|
pid_t child;
|
||||||
sigfn_t oldhandler = NULL;
|
sigfn_t oldhandler = NULL;
|
||||||
sigset_t oset;
|
sigset_t oset;
|
||||||
|
|
@ -131,15 +129,10 @@ clixon_proc_socket(char **argv,
|
||||||
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (pipe2(p2c, O_DIRECT) == -1){ /* parent->child */
|
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, sp) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "pipe");
|
clicon_err(OE_UNIX, errno, "socketpair");
|
||||||
goto done;
|
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);
|
sigprocmask(0, NULL, &oset);
|
||||||
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
|
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
|
||||||
sig++;
|
sig++;
|
||||||
|
|
@ -152,24 +145,18 @@ clixon_proc_socket(char **argv,
|
||||||
clicon_signal_unblock(0);
|
clicon_signal_unblock(0);
|
||||||
signal(SIGTSTP, SIG_IGN);
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
|
||||||
|
close(sp[0]);
|
||||||
close(0);
|
close(0);
|
||||||
|
if (dup2(sp[1], STDIN_FILENO) < 0){
|
||||||
if (dup2(p2c[0], STDIN_FILENO) < 0){
|
|
||||||
// if (dup(p2c[0]) < 0){
|
|
||||||
perror("dup2");
|
perror("dup2");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(p2c[1]);
|
|
||||||
close(p2c[0]);
|
|
||||||
|
|
||||||
close(1);
|
close(1);
|
||||||
if (dup2(c2p[1], STDOUT_FILENO) < 0){
|
if (dup2(sp[1], STDOUT_FILENO) < 0){
|
||||||
// if (dup(c2p[1]) < 0){
|
|
||||||
perror("dup2");
|
perror("dup2");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(c2p[1]);
|
close(sp[1]);
|
||||||
close(c2p[0]);
|
|
||||||
|
|
||||||
if (execvp(argv[0], argv) < 0){
|
if (execvp(argv[0], argv) < 0){
|
||||||
perror("execvp");
|
perror("execvp");
|
||||||
|
|
@ -178,11 +165,9 @@ clixon_proc_socket(char **argv,
|
||||||
exit(-1); /* Shouldnt reach here */
|
exit(-1); /* Shouldnt reach here */
|
||||||
}
|
}
|
||||||
/* Parent */
|
/* Parent */
|
||||||
close(p2c[0]);
|
close(sp[1]);
|
||||||
close(c2p[1]);
|
|
||||||
*pid = child;
|
*pid = child;
|
||||||
*fdout = p2c[1];
|
*sock = sp[0];
|
||||||
*fdin = c2p[0];
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (sig){ /* Restore sigmask and fn */
|
if (sig){ /* Restore sigmask and fn */
|
||||||
|
|
@ -192,18 +177,18 @@ clixon_proc_socket(char **argv,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @see clixon_proc_socket which creates the child and sockets closed and killed here
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clixon_proc_socket_close(pid_t pid,
|
clixon_proc_socket_close(pid_t pid,
|
||||||
int fdin,
|
int sock)
|
||||||
int fdout)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (fdin != -1)
|
if (sock != -1)
|
||||||
close(fdin);
|
close(sock); /* usually kills */
|
||||||
if (fdout != -1)
|
|
||||||
close(fdout); /* Usually kills */
|
|
||||||
kill(pid, SIGTERM);
|
kill(pid, SIGTERM);
|
||||||
// usleep(100000); /* Wait for child to finish */
|
// usleep(100000); /* Wait for child to finish */
|
||||||
if(waitpid(pid, &status, 0) == pid)
|
if(waitpid(pid, &status, 0) == pid)
|
||||||
|
|
|
||||||
|
|
@ -435,6 +435,7 @@ clicon_msg_rcv1(int s,
|
||||||
int poll;
|
int poll;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
|
*eof = 0;
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
while (1){
|
while (1){
|
||||||
if ((len = read(s, buf, sizeof(buf))) < 0){
|
if ((len = read(s, buf, sizeof(buf))) < 0){
|
||||||
|
|
@ -446,7 +447,7 @@ clicon_msg_rcv1(int s,
|
||||||
}
|
}
|
||||||
} /* read */
|
} /* read */
|
||||||
if (len == 0){ /* EOF */
|
if (len == 0){ /* EOF */
|
||||||
// cc_closed++;
|
*eof = 1;
|
||||||
close(s);
|
close(s);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
@ -473,8 +474,6 @@ clicon_msg_rcv1(int s,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s done", __FUNCTION__);
|
clicon_debug(1, "%s done", __FUNCTION__);
|
||||||
// if (cc_closed)
|
|
||||||
// retval = -1;
|
|
||||||
return retval;
|
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
|
* errno set to ENOTCONN which means that socket is now closed probably
|
||||||
* due to remote peer disconnecting. The caller may have to do something,...
|
* due to remote peer disconnecting. The caller may have to do something,...
|
||||||
*
|
*
|
||||||
* @param[in] fdin Input file descriptor
|
* @param[in] sock Socket / file descriptor
|
||||||
* @param[in] fdout Output file descriptor (for socket same as fdin)
|
|
||||||
* @param[in] msg CLICON msg data structure. It has fixed header and variable body.
|
* @param[in] msg CLICON msg data structure. It has fixed header and variable body.
|
||||||
* @param[out] xret Returned data as netconf xml tree.
|
* @param[out] xret Returned data as netconf xml tree.
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc(int fdin,
|
clicon_rpc(int sock,
|
||||||
int fdout,
|
struct clicon_msg *msg,
|
||||||
struct clicon_msg *msg,
|
char **ret)
|
||||||
char **ret)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *reply = NULL;
|
struct clicon_msg *reply = NULL;
|
||||||
int eof;
|
int eof;
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
|
|
||||||
if (clicon_msg_send(fdout, msg) < 0)
|
if (clicon_msg_send(sock, msg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_msg_rcv(fdin, &reply, &eof) < 0)
|
if (clicon_msg_rcv(sock, &reply, &eof) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (eof){
|
if (eof){
|
||||||
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
|
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;
|
errno = ESHUTDOWN;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -645,8 +642,7 @@ clicon_rpc(int fdin,
|
||||||
* errno set to ENOTCONN which means that socket is now closed probably
|
* errno set to ENOTCONN which means that socket is now closed probably
|
||||||
* due to remote peer disconnecting. The caller may have to do something,...
|
* due to remote peer disconnecting. The caller may have to do something,...
|
||||||
*
|
*
|
||||||
* @param[in] fdin Input file descriptor
|
* @param[in] sock Socket / file descriptor
|
||||||
* @param[in] fdout Output file descriptor (for socket same as fdin)
|
|
||||||
* @param[in] msgin CLICON msg data structure. It has fixed header and variable body.
|
* @param[in] msgin CLICON msg data structure. It has fixed header and variable body.
|
||||||
* @param[out] msgret Returned data as netconf xml tree.
|
* @param[out] msgret Returned data as netconf xml tree.
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -654,22 +650,21 @@ clicon_rpc(int fdin,
|
||||||
* see clicon_rpc using clicon_msg
|
* see clicon_rpc using clicon_msg
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc1(int fdin,
|
clicon_rpc1(int sock,
|
||||||
int fdout,
|
cbuf *msg,
|
||||||
cbuf *msg,
|
cbuf *msgret)
|
||||||
cbuf *msgret)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int eof;
|
int eof;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if (clicon_msg_send1(fdout, msg) < 0)
|
if (clicon_msg_send1(sock, msg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_msg_rcv1(fdin, msgret, &eof) < 0)
|
if (clicon_msg_rcv1(sock, msgret, &eof) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (eof){
|
if (eof){
|
||||||
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
|
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
|
||||||
close(fdin); /* assume socket */
|
close(sock);
|
||||||
errno = ESHUTDOWN;
|
errno = ESHUTDOWN;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,20 +86,20 @@
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_connect(clicon_handle h,
|
clicon_rpc_connect(clicon_handle h,
|
||||||
int *sock0)
|
int *sockp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *sock = NULL;
|
char *sockstr = NULL;
|
||||||
int port;
|
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");
|
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* What to do if inet socket? */
|
/* What to do if inet socket? */
|
||||||
switch (clicon_sock_family(h)){
|
switch (clicon_sock_family(h)){
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
if (clicon_rpc_connect_unix(h, sock, sock0) < 0){
|
if (clicon_rpc_connect_unix(h, sockstr, sockp) < 0){
|
||||||
#if 0
|
#if 0
|
||||||
if (errno == ESHUTDOWN)
|
if (errno == ESHUTDOWN)
|
||||||
/* Maybe could reconnect on a higher layer, but lets fail
|
/* 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");
|
clicon_err(OE_FATAL, 0, "CLICON_SOCK_PORT not set");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_connect_inet(h, sock, port, sock0) < 0)
|
if (clicon_rpc_connect_inet(h, sockstr, port, sockp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -152,9 +152,12 @@ clicon_rpc_msg(clicon_handle h,
|
||||||
#endif
|
#endif
|
||||||
clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body);
|
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 */
|
/* Create a socket and connect to it, either UNIX, IPv4 or IPv6 per config options */
|
||||||
if (clicon_rpc_connect(h, &s) < 0)
|
if ((s = clicon_client_socket_get(h)) < 0){
|
||||||
goto done;
|
if (clicon_rpc_connect(h, &s) < 0)
|
||||||
if (clicon_rpc(s, s, msg, &retdata) < 0)
|
goto done;
|
||||||
|
clicon_client_socket_set(h, s);
|
||||||
|
}
|
||||||
|
if (clicon_rpc(s, msg, &retdata) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
clicon_debug(1, "%s retdata:%s", __FUNCTION__, retdata);
|
clicon_debug(1, "%s retdata:%s", __FUNCTION__, retdata);
|
||||||
|
|
@ -177,8 +180,6 @@ clicon_rpc_msg(clicon_handle h,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (s != -1)
|
|
||||||
close(s);
|
|
||||||
if (retdata)
|
if (retdata)
|
||||||
free(retdata);
|
free(retdata);
|
||||||
if (xret)
|
if (xret)
|
||||||
|
|
@ -308,7 +309,6 @@ clicon_rpc_netconf_xml(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Get database configuration
|
/*! Get database configuration
|
||||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
* Same as clicon_proto_change just with a cvec instead of lvec
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
|
|
@ -786,10 +786,12 @@ clicon_rpc_get(clicon_handle h,
|
||||||
return retval;
|
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
|
* @param[in] h CLICON handle
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error and logged to syslog
|
* @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
|
int
|
||||||
clicon_rpc_close_session(clicon_handle h)
|
clicon_rpc_close_session(clicon_handle h)
|
||||||
|
|
@ -800,6 +802,7 @@ clicon_rpc_close_session(clicon_handle h)
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
char *username;
|
char *username;
|
||||||
uint32_t session_id;
|
uint32_t session_id;
|
||||||
|
int s;
|
||||||
|
|
||||||
if (session_id_check(h, &session_id) < 0)
|
if (session_id_check(h, &session_id) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -810,6 +813,10 @@ clicon_rpc_close_session(clicon_handle h)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
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){
|
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||||
clixon_netconf_error(xerr, "Close session", NULL);
|
clixon_netconf_error(xerr, "Close session", NULL);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ fyang=$dir/example-client.yang
|
||||||
cfile=$dir/example-client.c
|
cfile=$dir/example-client.c
|
||||||
pdir=$dir/plugin
|
pdir=$dir/plugin
|
||||||
app=$dir/clixon-app
|
app=$dir/clixon-app
|
||||||
|
debug=0
|
||||||
|
|
||||||
if [ ! -d $pdir ]; then
|
if [ ! -d $pdir ]; then
|
||||||
mkdir $pdir
|
mkdir $pdir
|
||||||
|
|
@ -68,19 +69,21 @@ cat<<EOF > $cfile
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <syslog.h> // debug
|
||||||
|
|
||||||
#include <clixon/clixon_log.h>
|
#include <clixon/clixon_log.h> // debug
|
||||||
#include <clixon/clixon_client.h>
|
#include <clixon/clixon_client.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc,
|
main(int argc,
|
||||||
char **argv)
|
char **argv)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
clixon_handle h = NULL; /* clixon handle */
|
clixon_handle h = NULL; /* clixon handle */
|
||||||
clixon_client_handle ch = NULL; /* clixon client handle */
|
clixon_client_handle ch = NULL; /* clixon client handle */
|
||||||
|
|
||||||
// clicon_log_init("client", LOG_DEBUG, CLICON_LOG_STDERR); // debug
|
clicon_log_init("client", LOG_DEBUG, CLICON_LOG_STDERR); // debug
|
||||||
// clicon_debug_init(1, NULL); // debug
|
clicon_debug_init($debug, NULL); // debug
|
||||||
|
|
||||||
/* Provide a clixon config-file, get a clixon handle */
|
/* Provide a clixon config-file, get a clixon handle */
|
||||||
if ((h = clixon_client_init("$cfg")) == NULL)
|
if ((h = clixon_client_init("$cfg")) == NULL)
|
||||||
|
|
@ -94,12 +97,15 @@ main(int argc,
|
||||||
{
|
{
|
||||||
uint32_t u = 0;
|
uint32_t u = 0;
|
||||||
if (clixon_client_get_uint32(ch, &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;
|
goto done;
|
||||||
printf("%u\n", u); /* for test output */
|
printf("%u\n", u); /* for test output */
|
||||||
}
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
clixon_client_disconnect(ch);
|
clixon_client_disconnect(ch);
|
||||||
clixon_client_terminate(h);
|
clixon_client_terminate(h);
|
||||||
return 0;
|
printf("done\n"); /* for test output */
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<xx:rpc xmlns:xx=\"urn:ietf:params:xml:n
|
||||||
new "netconf lock/unlock"
|
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>]]>]]>$"
|
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"
|
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>"
|
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
|
# Negative
|
||||||
new "restconf get config on wrong port in netns:$netns"
|
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
|
if [ $RC -ne 0 ]; then
|
||||||
new "Kill restconf daemon"
|
new "Kill restconf daemon"
|
||||||
|
|
@ -192,4 +192,3 @@ new "endtest"
|
||||||
endtest
|
endtest
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ main(int argc,
|
||||||
else
|
else
|
||||||
if (clicon_rpc_connect_inet(h, sockpath, 4535, &s) < 0)
|
if (clicon_rpc_connect_inet(h, sockpath, 4535, &s) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc(s, s, msg, &retdata) < 0)
|
if (clicon_rpc(s, msg, &retdata) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
close(s);
|
close(s);
|
||||||
fprintf(stdout, "%s\n", retdata);
|
fprintf(stdout, "%s\n", retdata);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue