From 5822c1a72a263383699919a8b8a20d513b6d1c31 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 8 Mar 2023 21:14:38 +0100 Subject: [PATCH] * `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 --- CHANGELOG.md | 4 +++ README.md | 2 +- apps/backend/backend_client.c | 19 +++++++------- apps/backend/clixon_backend_client.h | 5 ++++ apps/cli/cli_common.c | 24 +++++++++--------- apps/cli/cli_main.c | 2 ++ apps/netconf/netconf_main.c | 2 ++ apps/netconf/netconf_rpc.c | 2 +- apps/restconf/restconf_main_native.c | 2 +- apps/restconf/restconf_stream_fcgi.c | 2 +- lib/clixon/clixon_netconf_lib.h | 1 + lib/clixon/clixon_proto.h | 2 +- lib/clixon/clixon_sig.h | 1 + lib/src/clixon_datastore.c | 2 ++ lib/src/clixon_log.c | 7 +----- lib/src/clixon_netconf_lib.c | 22 +++++++++++++++++ lib/src/clixon_path.c | 4 +-- lib/src/clixon_proto.c | 37 +++++++++++++++++----------- lib/src/clixon_proto_client.c | 35 +++++++++++++++----------- lib/src/clixon_sig.c | 31 +++++++++++++++++++---- lib/src/clixon_xml.c | 2 +- 21 files changed, 140 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc144603..a5cd8866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,11 +55,15 @@ Users may have to change how they access the system Developers may need to change their code * C-API + * `clicon_msg_rcv`: Added `intr` parameter for interrupting on `^C` (default 0) * Renamed include file: `clixon_backend_handle.h`to `clixon_backend_client.h` * `candidate_commit()`: validate_level (added in 6.1) marked obsolete ### Minor features +* Internal NETCONF (client <-> backend) + * Ensure message-id increments + * Separated rpc from notification socket in same session * Restconf: Added fallback mechanism for non-ALPN HTTPS * Set `CLICON_RESTCONF_NOALPN_DEFAULT` to `http/2` or `http/1.1` * For http/1 or http/2 only, that will be the default if no ALPN is set. diff --git a/README.md b/README.md index 6cc84b7e..7acb4426 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ -[![Build Status](https://github.com/clicon/clixon/actions/workflows/ci.yml/badge.svg)](https://github.com/clicon/clixon/actions/workflows/ci.yml) [![Documentation Status](https://readthedocs.org/projects/clixon-docs/badge/?version=latest)](https://clixon-docs.readthedocs.io/en/latest/?badge=latest) [![codecov](https://codecov.io/gh/clicon/clixon/branch/master/graph/badge.svg?token=qyc6ssg9E7)](https://codecov.io/gh/clicon/clixon) +[![Build Status](https://github.com/clicon/clixon/actions/workflows/ci.yml/badge.svg)](https://github.com/clicon/clixon/actions/workflows/ci.yml) [![Documentation Status](https://readthedocs.org/projects/clixon-docs/badge/?version=latest)](https://clixon-docs.readthedocs.io/en/latest/?badge=latest) Clixon is a YANG-based configuration manager, with interactive CLI, NETCONF and RESTCONF interfaces, an embedded database and transaction diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 1bafe4a0..b294c4c7 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -1554,14 +1554,6 @@ from_client_msg(clicon_handle h, goto done; goto reply; } - /* Sanity check: - * op_id from internal message can be out-of-sync from client's sessions-id for the following reasons: - * 1. Its a hello when the client starts with op_id=0 to get its proper id on hello reply - * 2. The backend has restarted and the client uses an old op_id - */ - if (op_id != 0 && ce->ce_id != op_id){ - clicon_debug(1, "%s Warning: incoming session-id:%u does not match socket ce_id:%u", __FUNCTION__, op_id, ce->ce_id); - } /* Check for empty frame (no mesaages), return empty message, not clear from RFC what to do */ if (xml_child_nr_type(xt, CX_ELMNT) == 0){ if (netconf_malformed_message(cbret, "Empty message in netconf rpc frame")< 0) @@ -1580,6 +1572,15 @@ from_client_msg(clicon_handle h, } rpcname = xml_name(x); rpcprefix = xml_prefix(x); + /* Sanity check: + * op_id from internal message can be out-of-sync from client's sessions-id for the following reasons: + * 1. Its a hello when the client starts with op_id=0 to get its proper id on hello reply + * 2. The backend has restarted and the client uses an old op_id + * 3. Its a create-subsciption message that uses a separate socket(=client) + */ + if (op_id != 0 && ce->ce_id != op_id && strcmp(rpcname, "create-subscription")){ + clicon_debug(1, "%s Warning: incoming session-id:%u does not match ce_id:%u on socket: %d", __FUNCTION__, op_id, ce->ce_id, ce->ce_s); + } /* Note that this validation is also made in xml_yang_validate_rpc, but not for hello */ if (xml2ns(x, rpcprefix, &namespace) < 0) @@ -1786,7 +1787,7 @@ from_client(int s, clicon_err(OE_NETCONF, EINVAL, "Internal error: s != ce->ce_s"); goto done; } - if (clicon_msg_rcv(ce->ce_s, &msg, &eof) < 0) + if (clicon_msg_rcv(ce->ce_s, 0, &msg, &eof) < 0) goto done; if (eof){ backend_client_rm(h, ce); diff --git a/apps/backend/clixon_backend_client.h b/apps/backend/clixon_backend_client.h index 3c189d85..04b3f7d4 100644 --- a/apps/backend/clixon_backend_client.h +++ b/apps/backend/clixon_backend_client.h @@ -48,6 +48,11 @@ /* Backend client entry. * Keep state about every connected client. * References from RFC 6022, ietf-netconf-monitoring.yang sessions container + * @note that there is a discrepancy here between a client and a session + * A session may have multiple client endpoints, most notably a regular + * client socket and a separate notification client socket. + * But they are the same session. + * But the clixon client-entry do not differentiate */ struct client_entry{ struct client_entry *ce_next; /* The clients linked list */ diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index f0b10e1a..8611e490 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -135,24 +135,26 @@ cli_notification_register(clicon_handle h, return retval; } -/* Signal functions, not exported to API */ +/* Signal functions + * This is for CLIgen to handle these signals, eg ^Ĉ means abort command, not program + */ void cli_signal_block(clicon_handle h) { - clicon_signal_block (SIGTSTP); - clicon_signal_block (SIGQUIT); - clicon_signal_block (SIGCHLD); - if (!clicon_quiet_mode(h)) - clicon_signal_block (SIGINT); + clicon_signal_block (SIGTSTP); + clicon_signal_block (SIGQUIT); + clicon_signal_block (SIGCHLD); + if (!clicon_quiet_mode(h)) + clicon_signal_block (SIGINT); } void cli_signal_unblock(clicon_handle h) { - clicon_signal_unblock (SIGTSTP); - clicon_signal_unblock (SIGQUIT); - clicon_signal_unblock (SIGCHLD); - clicon_signal_unblock (SIGINT); + clicon_signal_unblock (SIGTSTP); + clicon_signal_unblock (SIGQUIT); + clicon_signal_unblock (SIGCHLD); + clicon_signal_unblock (SIGINT); } /* @@ -1139,7 +1141,7 @@ cli_notification_cb(int s, int ret; /* get msg (this is the reason this function is called) */ - if (clicon_msg_rcv(s, &reply, &eof) < 0) + if (clicon_msg_rcv(s, 0, &reply, &eof) < 0) goto done; if (eof){ clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close"); diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 32bc1db7..0df7c3b1 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -167,6 +167,8 @@ cli_terminate(clicon_handle h) cvec *nsctx; cxobj *x; + if (clixon_exit_get() == 0) + clixon_exit_set(1); if (clicon_data_get(h, "session-transport", NULL) == 0) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index d09297a2..6b179061 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -686,6 +686,8 @@ netconf_terminate(clicon_handle h) cvec *nsctx; cxobj *x; + if (clixon_exit_get() == 0) + clixon_exit_set(1); /* Delete all plugins, and RPC callbacks */ clixon_plugin_module_exit(h); clicon_rpc_close_session(h); diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c index f6e0e10e..d11b9d2d 100644 --- a/apps/netconf/netconf_rpc.c +++ b/apps/netconf/netconf_rpc.c @@ -453,7 +453,7 @@ netconf_notification_cb(int s, clicon_debug(1, "%s", __FUNCTION__); /* get msg (this is the reason this function is called) */ - if (clicon_msg_rcv(s, &reply, &eof) < 0) + if (clicon_msg_rcv(s, 0, &reply, &eof) < 0) goto done; /* handle close from remote end: this will exit the client */ if (eof){ diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index 1f6f1004..85ee33e1 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -913,7 +913,7 @@ restconf_openssl_init(clicon_handle h, * - If no local config found, query backend for config and open sockets. * That is, EITHER local config OR read config from backend once * @param[in] h Clicon handle - * @param[in] inline_config XML restconf config, malloced (if retval = 1) + * @param[in] inline_config If set, restconf conf is given by -R command-line * @param[out] xrestconf XML restconf config, malloced (if retval = 1) * @retval 1 OK (and xrestconf set) * @retval 0 Fail - no config diff --git a/apps/restconf/restconf_stream_fcgi.c b/apps/restconf/restconf_stream_fcgi.c index 449ebffa..764a2675 100644 --- a/apps/restconf/restconf_stream_fcgi.c +++ b/apps/restconf/restconf_stream_fcgi.c @@ -213,7 +213,7 @@ restconf_stream_cb(int s, clicon_debug(1, "%s", __FUNCTION__); /* get msg (this is the reason this function is called) */ - if (clicon_msg_rcv(s, &reply, &eof) < 0){ + if (clicon_msg_rcv(s, 0, &reply, &eof) < 0){ clicon_debug(1, "%s msg_rcv error", __FUNCTION__); goto done; } diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h index 1ec03cf8..7415a040 100644 --- a/lib/clixon/clixon_netconf_lib.h +++ b/lib/clixon/clixon_netconf_lib.h @@ -207,6 +207,7 @@ int clixon_netconf_error_fn(const char *fn, const int line, cxobj *xerr, const c int clixon_netconf_internal_error(cxobj *xerr, char *msg, char *arg); int netconf_parse_uint32(char *name, char *valstr, char *defaultstr, uint32_t defaultval, cbuf *cbret, uint32_t *value); int netconf_parse_uint32_xml(char *name, char *valstr, char *defaultstr, uint32_t defaultval, cxobj **xerr, uint32_t *value); +int netconf_message_id_next(clicon_handle h); int netconf_framing_preamble(netconf_framing_type framing, cbuf *cb); int netconf_framing_postamble(netconf_framing_type framing, cbuf *cb); int netconf_output(int s, cbuf *xf, char *msg); diff --git a/lib/clixon/clixon_proto.h b/lib/clixon/clixon_proto.h index 076b6021..c05a32e8 100644 --- a/lib/clixon/clixon_proto.h +++ b/lib/clixon/clixon_proto.h @@ -80,7 +80,7 @@ int clicon_msg_send(int s, struct clicon_msg *msg); int clicon_msg_send1(int s, cbuf *cb); -int clicon_msg_rcv(int s, struct clicon_msg **msg, int *eof); +int clicon_msg_rcv(int s, int intr, struct clicon_msg **msg, int *eof); int clicon_msg_rcv1(int s, cbuf *cb, int *eof); diff --git a/lib/clixon/clixon_sig.h b/lib/clixon/clixon_sig.h index e9fac691..f2760d93 100644 --- a/lib/clixon/clixon_sig.h +++ b/lib/clixon/clixon_sig.h @@ -47,6 +47,7 @@ typedef void (*sigfn_t)(int); * Prototypes */ int set_signal(int signo, void (*handler)(int), void (**oldhandler)(int)); +int set_signal_flags(int signo, int flags, void (*handler)(int), void (**oldhandler)(int)); int clixon_signal_save(sigset_t *sigset, struct sigaction sigaction_vec[32]); int clixon_signal_restore(sigset_t *sigset, struct sigaction sigaction_vec[32]); void clicon_signal_block(int); diff --git a/lib/src/clixon_datastore.c b/lib/src/clixon_datastore.c index abe663cb..d1d85a0d 100644 --- a/lib/src/clixon_datastore.c +++ b/lib/src/clixon_datastore.c @@ -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, diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 9933a3d9..77877f70 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -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 diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 8a426f8f..7f1a4d95 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -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 diff --git a/lib/src/clixon_path.c b/lib/src/clixon_path.c index afae5ad7..60c4b5cb 100644 --- a/lib/src/clixon_path.c +++ b/lib/src/clixon_path.c @@ -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? */ diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index e961e5b9..37541e42 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -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; diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 9348a6db..18a6916d 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -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, ">