* clicon_msg_rcv: Added intr parameter for interrupting on ^C (default 0)

* Internal NETCONF (client <-> backend)
  * Ensure message-id increments
  * Separated rpc from notification socket in same session
* Removed coverage icon from homepage since it stopped working some time ago
This commit is contained in:
Olof hagsand 2023-03-08 21:14:38 +01:00
parent 453e97ef6b
commit 5822c1a72a
21 changed files with 140 additions and 68 deletions

View file

@ -504,6 +504,8 @@ xmldb_create(clicon_handle h,
* Utility function.
* @param[in] h Clixon handle
* @param[in] db Symbolic database name, eg "candidate", "running"
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_db_reset(clicon_handle h,

View file

@ -367,12 +367,7 @@ clicon_debug_get(void)
* print message if level >= dbglevel.
* The message is sent to clicon_log. EIther to syslog, stderr or both, depending on
* clicon_log_init() setting
* The dbgdebug level strategy is a mask of the following masks:
* 1: Basic debug message, espcially initialization
* 2: Input and output packets, read datastore
* 4: Details: traces, parse trees, etc
* 8: Extra detailed logs, temporary logs
* @param[in] dbglevel Debug level 0: No debug, 1-7 combined of the CLIXON_DBG_ flags above
* @param[in] dbglevel Mask of CLIXON_DBG_DEFAULT and other masks
* @param[in] format Message to print as argv.
* @see clicon_debug_xml Specialization for XML tree
* @see CLIXON_DBG_DEFAULT and other flags

View file

@ -2063,6 +2063,28 @@ netconf_parse_uint32_xml(char *name,
goto done;
}
/*! Get next netconf rpc message-id
*
* @param[in] h Clixon handle
* @retval msgid Next message id
*/
int
netconf_message_id_next(clicon_handle h)
{
int msgid;
if ((msgid=clicon_option_int(h, "netconf-message-id")) < 0){
clicon_option_str_set(h, "netconf-message-id", NETCONF_MESSAGE_ID_DEFAULT);
msgid = clicon_option_int(h, "netconf-message-id");
}
else {
msgid++;
msgid %= 0x7ffffff; /* Wrap at some number */
clicon_option_int_set(h, "netconf-message-id", msgid);
}
return msgid;
}
/*! Add netconf xml postamble of message. I.e, xml after the body of the message.
*
* @param[in] framing Netconf framing

View file

@ -679,7 +679,7 @@ api_path2xpath_cvv(cvec *api_path,
/* api-path: prefix points to module */
if (nodeid_split(nodeid, &prefix, &name) < 0)
goto done;
clicon_debug(1, "%s [%d] cvname: %s:%s",
clicon_debug(CLIXON_DBG_DETAIL, "%s [%d] cvname: %s:%s",
__FUNCTION__, i, prefix?prefix:"", name);
/* top-node must have prefix */
if (i == offset && prefix == NULL){
@ -713,7 +713,7 @@ api_path2xpath_cvv(cvec *api_path,
*/
if (xml_nsctx_get_prefix(nsc, namespace, &xprefix) == 0){
xprefix = yang_find_myprefix(y);
clicon_debug(1, "%s prefix not found add it %s", __FUNCTION__, xprefix);
clicon_debug(CLIXON_DBG_DETAIL, "%s prefix not found add it %s", __FUNCTION__, xprefix);
/* not found, add it to nsc
* XXX: do we always have to add it? It could be default?
*/

View file

@ -273,7 +273,7 @@ atomicio(ssize_t (*fn) (int, void *, size_t),
switch (res) {
case -1:
if (errno == EINTR){
if (!_atomicio_sig)
if (_atomicio_sig == 0)
continue;
}
else if (errno == EAGAIN)
@ -377,6 +377,7 @@ clicon_msg_send(int s,
* Now, ^C will interrupt the whole process, and this may not be what you want.
*
* @param[in] s socket (unix or inet) to communicate with backend
* @param[in] intr If set, make a ^C cause an error
* @param[out] msg CLICON msg data reply structure. Free with free()
* @param[out] eof Set if eof encountered
* Note: caller must ensure that s is closed if eof is set after call.
@ -384,6 +385,7 @@ clicon_msg_send(int s,
*/
int
clicon_msg_rcv(int s,
int intr,
struct clicon_msg **msg,
int *eof)
{
@ -396,11 +398,15 @@ clicon_msg_rcv(int s,
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
*eof = 0;
if (0)
set_signal(SIGINT, atomicio_sig_handler, &oldhandler);
if (intr){
clicon_signal_unblock(SIGINT);
set_signal_flags(SIGINT, 0, atomicio_sig_handler, &oldhandler);
}
if ((hlen = atomicio(read, s, &hdr, sizeof(hdr))) < 0){
clicon_err(OE_CFG, errno, "atomicio");
if (intr && _atomicio_sig)
;
else
clicon_err(OE_CFG, errno, "atomicio");
goto done;
}
msg_hex(CLIXON_DBG_EXTRA, (char*)&hdr, hlen, __FUNCTION__);
@ -413,14 +419,13 @@ clicon_msg_rcv(int s,
goto done;
}
mlen = ntohl(hdr.op_len);
clicon_debug(16, "op-len:%u op-id:%u",
clicon_debug(CLIXON_DBG_EXTRA, "op-len:%u op-id:%u",
mlen, ntohl(hdr.op_id));
clicon_debug(CLIXON_DBG_DETAIL, "%s: rcv msg len=%d",
__FUNCTION__, mlen);
if (mlen <= sizeof(hdr)){
clicon_err(OE_PROTO, 0, "op_len:%u too short", mlen);
*eof = 1;
assert(0);
goto ok;
}
if ((*msg = (struct clicon_msg *)malloc(mlen+1)) == NULL){
@ -449,8 +454,10 @@ clicon_msg_rcv(int s,
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (0)
if (intr){
set_signal(SIGINT, oldhandler, NULL);
clicon_signal_block(SIGINT);
}
return retval;
}
@ -515,7 +522,7 @@ clicon_msg_rcv1(int s,
clicon_debug(CLIXON_DBG_MSG, "Recv: %s", cbuf_get(cb));
retval = 0;
done:
clicon_debug(1, "%s done", __FUNCTION__);
clicon_debug(CLIXON_DBG_DETAIL, "%s done", __FUNCTION__);
return retval;
}
@ -564,7 +571,7 @@ clicon_rpc_connect_unix(clicon_handle h,
int s = -1;
struct stat sb = {0,};
clicon_debug(1, "Send msg on %s", sockpath);
clicon_debug(CLIXON_DBG_DETAIL, "Send msg on %s", sockpath);
if (sock0 == NULL){
clicon_err(OE_NETCONF, EINVAL, "sock0 expected");
goto done;
@ -607,7 +614,7 @@ clicon_rpc_connect_inet(clicon_handle h,
int s = -1;
struct sockaddr_in addr;
clicon_debug(1, "Send msg to %s:%hu", dst, port);
clicon_debug(CLIXON_DBG_DETAIL, "Send msg to %s:%hu", dst, port);
if (sock0 == NULL){
clicon_err(OE_NETCONF, EINVAL, "sock0 expected");
goto done;
@ -662,7 +669,7 @@ clicon_rpc(int sock,
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (clicon_msg_send(sock, msg) < 0)
goto done;
if (clicon_msg_rcv(sock, &reply, eof) < 0)
if (clicon_msg_rcv(sock, 0, &reply, eof) < 0)
goto done;
if (*eof)
goto ok;
@ -701,7 +708,7 @@ clicon_rpc1(int sock,
{
int retval = -1;
clicon_debug(1, "%s", __FUNCTION__);
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (netconf_framing_preamble(NETCONF_SSH_CHUNKED, msg) < 0)
goto done;
if (netconf_framing_postamble(NETCONF_SSH_CHUNKED, msg) < 0)
@ -712,7 +719,7 @@ clicon_rpc1(int sock,
goto done;
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -803,7 +810,7 @@ send_msg_notify_xml(clicon_handle h,
goto done;
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;

View file

@ -139,16 +139,19 @@ clicon_rpc_connect(clicon_handle h,
/*! Connect to backend or use cached socket and send RPC
*
* @param[in] h Clixon handle
* @param[in] msg Encoded message
* @param[out] xret Returned data as netconf xml tree.
* @param[out] eof Set if eof encountered
* @retval 0 OK
* @retval -1 Error
* @param[in] h Clixon handle
* @param[in] msg Encoded message
* @param[in] cache Use cached (client) socket, otherwise generate new socket
* @param[out] retdate Returned data as string
* @param[out] eof Set if eof encountered
* @param[out] sp Returned socket
* @retval 0 OK
* @retval -1 Error
*/
static int
clicon_rpc_msg_once(clicon_handle h,
struct clicon_msg *msg,
int cache,
char **retdata,
int *eof,
int *sp)
@ -156,11 +159,15 @@ clicon_rpc_msg_once(clicon_handle h,
int retval = -1;
int s;
if ((s = clicon_client_socket_get(h)) < 0){
if (clicon_rpc_connect(h, &s) < 0)
goto done;
clicon_client_socket_set(h, s);
if (cache){
if ((s = clicon_client_socket_get(h)) < 0){
if (clicon_rpc_connect(h, &s) < 0)
goto done;
clicon_client_socket_set(h, s);
}
}
else if (clicon_rpc_connect(h, &s) < 0)
goto done;
if (clicon_rpc(s, msg, retdata, eof) < 0){
/* 2. check socket shutdown AFTER rpc */
close(s);
@ -203,7 +210,7 @@ clicon_rpc_msg(clicon_handle h,
assert(strstr(msg->op_body, "username")!=NULL); /* XXX */
#endif
/* Create a socket and connect to it, either UNIX, IPv4 or IPv6 per config options */
if (clicon_rpc_msg_once(h, msg, &retdata, &eof, &s) < 0)
if (clicon_rpc_msg_once(h, msg, 1, &retdata, &eof, &s) < 0)
goto done;
if (eof){
/* 2. check socket shutdown AFTER rpc */
@ -212,7 +219,7 @@ clicon_rpc_msg(clicon_handle h,
clicon_client_socket_set(h, -1);
#ifdef PROTO_RESTART_RECONNECT
if (!clixon_exit_get()) { /* May be part of termination */
if (clicon_rpc_msg_once(h, msg, &retdata, &eof, NULL) < 0)
if (clicon_rpc_msg_once(h, msg, 1, &retdata, &eof, NULL) < 0)
goto done;
if (eof){
close(s);
@ -286,7 +293,7 @@ clicon_rpc_msg_persistent(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_msg_once(h, msg, &retdata, &eof, &s) < 0)
if (clicon_rpc_msg_once(h, msg, 0, &retdata, &eof, &s) < 0)
goto done;
if (eof){
/* 2. check socket shutdown AFTER rpc */
@ -976,7 +983,7 @@ clicon_rpc_get(clicon_handle h,
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, " message-id=\"%d\"", netconf_message_id_next(h));
cprintf(cb, "><get");
/* Clixon extension, content=all,config, or nonconfig */
if ((int)content != -1)

View file

@ -65,19 +65,40 @@ int
set_signal(int signo,
void (*handler)(int),
void (**oldhandler)(int))
{
return set_signal_flags(signo,
#if defined(HAVE_SIGACTION)
SA_RESTART,
#else
0,
#endif
handler, oldhandler);
}
/*! Set a signal handler, but without SA_RESTART
* @param[in] signo Signal number
* @param[in] flags Flags (to sigaction)
* @param[in] handler Function to call when signal occurs
* @param[out] oldhandler Pointer to old handler
*/
int
set_signal_flags(int signo,
int flags,
void (*handler)(int),
void (**oldhandler)(int))
{
#if defined(HAVE_SIGACTION)
struct sigaction sold, snew;
snew.sa_handler = handler;
sigemptyset(&snew.sa_mask);
snew.sa_flags = SA_RESTART;
if (sigaction(signo, &snew, &sold) < 0){
snew.sa_flags = flags;
if (sigaction(signo, &snew, &sold) < 0){
clicon_err(OE_UNIX, errno, "sigaction");
return -1;
}
if (oldhandler)
*oldhandler = sold.sa_handler;
}
if (oldhandler)
*oldhandler = sold.sa_handler;
return 0;
#elif defined(HAVE_SIGVEC)
assert(0);

View file

@ -2432,7 +2432,7 @@ clicon_log_xml(int level,
/*! Specialization of clicon_debug with xml tree
*
* @param[in] dbglevel
* @param[in] dbglevel Mask of CLIXON_DBG_DEFAULT and other masks
* @param[in] x XML tree that is logged without prettyprint
* @param[in] format Message to print as argv.
* @see clicon_log_xml For syslog