C-style update: Unified comment, retvals in order, remove trailing spaces

Changed function name for `clicon_debug` functions
This commit is contained in:
Olof hagsand 2023-10-22 18:04:47 +02:00
parent 6e314dd96f
commit 62348fc9c7
204 changed files with 6047 additions and 4904 deletions

View file

@ -45,6 +45,14 @@
## 6.5.0
Expected: December 2023
### C/CLI-API changes on existing features
Developers may need to change their code
* Changed function name for `clicon_debug` functions. You need to rename as follows:
* clicon_debug() -> clixon_debug()
* clicon_debug_init() -> clixon_debug_init()
* clicon_debug_get() -> clixon_debug_get()
### Corrected Bugs
* Fixed: [Does clixon cli support autocompletion for leafrefs pointed to another module?](https://github.com/clicon/clixon/issues/455)

View file

@ -104,8 +104,8 @@ ce_event_cb(clicon_handle h,
void *arg)
{
struct client_entry *ce = (struct client_entry *)arg;
clicon_debug(1, "%s op:%d", __FUNCTION__, op);
clixon_debug(CLIXON_DBG_DEFAULT, "%s op:%d", __FUNCTION__, op);
switch (op){
case 1:
/* Risk of recursion here */
@ -140,7 +140,7 @@ ce_client_string(struct client_entry *ce,
int retval = -1;
cbuf *cb = NULL;
char *id = NULL;
if (ce == NULL || cbp == NULL){
clicon_err(OE_UNIX, EINVAL, "ce or cbp is NULL");
goto done;
@ -273,7 +273,7 @@ backend_monitoring_state_get(clicon_handle h,
goto fail;
retval = 1;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
@ -293,7 +293,7 @@ backend_monitoring_state_get(clicon_handle h,
* @see backend_client_delete for actual deallocation of client entry struct
*/
int
backend_client_rm(clicon_handle h,
backend_client_rm(clicon_handle h,
struct client_entry *ce)
{
struct client_entry *c;
@ -311,10 +311,10 @@ backend_client_rm(clicon_handle h,
if (if_feature(yspec, "ietf-netconf", "confirmed-commit")) {
if (confirmed_commit_state_get(h) == EPHEMERAL) {
/* See if this client is the origin */
clicon_debug(1, "session_id: %u, confirmed_commit.session_id: %u", ce->ce_id, confirmed_commit_session_id_get(h));
clixon_debug(CLIXON_DBG_DEFAULT, "session_id: %u, confirmed_commit.session_id: %u", ce->ce_id, confirmed_commit_session_id_get(h));
if (myid == confirmed_commit_session_id_get(h)) {
clicon_debug(1, "ok, rolling back");
clixon_debug(CLIXON_DBG_DEFAULT, "ok, rolling back");
clicon_log(LOG_NOTICE, "a client with an active ephemeral confirmed-commit has disconnected; rolling back");
/* do_rollback errors are logged internally and there is no client to report errors to, so errors are
@ -326,7 +326,7 @@ backend_client_rm(clicon_handle h,
}
}
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* for all streams: XXX better to do it top-level? */
stream_ss_delete_all(h, ce_event_cb, (void*)ce);
c0 = backend_client_list(h);
@ -367,8 +367,8 @@ clixon_stats_datastore_get(clicon_handle h,
uint64_t nr = 0;
size_t sz = 0;
cxobj *xn = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, dbname);
clixon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, dbname);
/* This is the db cache */
if ((xt = xmldb_cache_get(h, dbname)) == NULL){
/* Trigger cache if no exist (trick to ensure cache is present) */
@ -409,7 +409,7 @@ clixon_stats_module_get(clicon_handle h,
uint64_t nr = 0;
size_t sz = 0;
cxobj *xn = NULL;
if (ys == NULL)
return 0;
if (yang_stats(ys, &nr, &sz) < 0)
@ -439,7 +439,7 @@ clixon_stats_module_get(clicon_handle h,
* However, what really should be done is to apply the change to the datastore and then
* validate, if error, discard to previous state.
* But this could discard other previous changes to candidate.
*/
*/
static int
from_client_edit_config(clicon_handle h,
cxobj *xn,
@ -480,7 +480,7 @@ from_client_edit_config(clicon_handle h,
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
/* Check if target locked by other client */
iddb = xmldb_islocked(h, target);
if (iddb && myid != iddb){
@ -645,22 +645,21 @@ from_client_edit_config(clicon_handle h,
xml_free(xret);
if (cbx)
cbuf_free(cbx);
clicon_debug(1, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
clixon_debug(CLIXON_DBG_DEFAULT, "%s done cbret:%s", __FUNCTION__, cbuf_get(cbret));
return retval;
} /* from_client_edit_config */
/*! Create or replace an entire config with another complete config db
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
* NACM: If source running and target startup --> only exec permission
* else:
* else:
* - omit data nodes to which the client does not have read access
* - access denied if user lacks create/delete/update
*/
@ -679,7 +678,7 @@ from_client_copy_config(clicon_handle h,
uint32_t myid = ce->ce_id;
cbuf *cbx = NULL; /* Assist cbuf */
cbuf *cbmsg = NULL;
if ((source = netconf_db_find(xe, "source")) == NULL){
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
goto done;
@ -688,7 +687,7 @@ from_client_copy_config(clicon_handle h,
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
if ((target = netconf_db_find(xe, "target")) == NULL){
if (netconf_missing_element(cbret, "protocol", "target", NULL) < 0)
goto done;
@ -727,10 +726,10 @@ from_client_copy_config(clicon_handle h,
/*! Delete a configuration datastore.
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -738,7 +737,7 @@ static int
from_client_delete_config(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *arg,
void *regarg)
{
int retval = -1;
@ -759,7 +758,7 @@ from_client_delete_config(clicon_handle h,
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
/* Check if target locked by other client */
iddb = xmldb_islocked(h, target);
if (iddb && myid != iddb){
@ -801,12 +800,12 @@ from_client_delete_config(clicon_handle h,
}
/*! Lock the configuration system of a device
*
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -814,7 +813,7 @@ static int
from_client_lock(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *arg,
void *regarg)
{
int retval = -1;
@ -838,7 +837,7 @@ from_client_lock(clicon_handle h,
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
/*
* A lock MUST not be granted if either of the following conditions is true:
* 1) A lock is already held by any NETCONF session or another entity.
@ -889,11 +888,11 @@ from_client_lock(clicon_handle h,
/*! Release a configuration lock previously obtained with the 'lock' operation
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -919,9 +918,9 @@ from_client_unlock(clicon_handle h,
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
iddb = xmldb_islocked(h, db);
/*
/*
* An unlock operation will not succeed if any of the following
* conditions are true:
* 1) the specified lock is not currently active
@ -944,7 +943,7 @@ from_client_unlock(clicon_handle h,
else{
xmldb_unlock(h, db);
/* user callback */
if (clixon_plugin_lockdb_all(h, db, 0, id) < 0)
if (clixon_plugin_lockdb_all(h, db, 0, id) < 0)
goto done;
if (cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE) < 0)
goto done;
@ -959,7 +958,7 @@ from_client_unlock(clicon_handle h,
/*! Request graceful termination of a NETCONF session.
*
* @param[in] h Clixon handle
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
@ -971,7 +970,7 @@ static int
from_client_close_session(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *arg,
void *regarg)
{
struct client_entry *ce = (struct client_entry *)arg;
@ -986,11 +985,11 @@ from_client_close_session(clicon_handle h,
/*! Internal message: Force the termination of a NETCONF session.
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -1009,7 +1008,7 @@ from_client_kill_session(clicon_handle h,
cxobj *x;
int ret;
char *reason = NULL;
if ((x = xml_find(xe, "session-id")) == NULL ||
(str = xml_find_value(x, "body")) == NULL){
if (netconf_missing_element(cbret, "protocol", "session-id", NULL) < 0)
@ -1029,7 +1028,7 @@ from_client_kill_session(clicon_handle h,
if (xmldb_islocked(h, db) == id){
xmldb_unlock(h, db);
/* user callback */
if (clixon_plugin_lockdb_all(h, db, 0, id) < 0)
if (clixon_plugin_lockdb_all(h, db, 0, id) < 0)
goto done;
}
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
@ -1043,11 +1042,11 @@ from_client_kill_session(clicon_handle h,
/*! Create a notification subscription
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
* @see RFC5277 2.1
@ -1063,7 +1062,7 @@ static int
from_client_create_subscription(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *arg,
void *regarg)
{
int retval = -1;
@ -1078,7 +1077,7 @@ from_client_create_subscription(clicon_handle h,
struct timeval start;
struct timeval stop;
cvec *nsc = NULL;
/* XXX should use prefix cf edit_config */
if ((nsc = xml_nsctx_init(NULL, EVENT_RFC5277_NAMESPACE)) == NULL)
goto done;
@ -1089,7 +1088,7 @@ from_client_create_subscription(clicon_handle h,
str2time(stoptime, &stop) < 0){
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
goto done;
goto ok;
goto ok;
}
}
if ((x = xpath_first(xe, nsc, "//startTime")) != NULL){
@ -1097,8 +1096,8 @@ from_client_create_subscription(clicon_handle h,
str2time(starttime, &start) < 0){
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
goto done;
goto ok;
}
goto ok;
}
}
if ((xfilter = xpath_first(xe, nsc, "//filter")) != NULL){
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
@ -1122,13 +1121,13 @@ from_client_create_subscription(clicon_handle h,
starttime?&start:NULL, stoptime?&stop:NULL,
ce_event_cb, (void*)ce) < 0)
goto done;
/* Replay of this stream to specific subscription according to start and
/* Replay of this stream to specific subscription according to start and
* stop (if present).
* RFC 5277: If <startTime> is not present, this is not a replay
* subscription.
* Schedule the replay to occur right after this RPC completes, eg "now"
*/
if (starttime){
if (starttime){
if (stream_replay_trigger(h, stream, ce_event_cb, (void*)ce) < 0)
goto done;
}
@ -1143,7 +1142,7 @@ from_client_create_subscription(clicon_handle h,
/*! Retrieve a schema from the NETCONF server.
*
* @param[in] h Clixon handle
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
@ -1156,7 +1155,7 @@ static int
from_client_get_schema(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *arg,
void *regarg)
{
int retval = -1;
@ -1171,7 +1170,7 @@ from_client_get_schema(clicon_handle h,
yang_stmt *yrev;
cbuf *cbyang = NULL;
cbuf *cbmsg = NULL;
const char *filename;
const char *filename;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec");
@ -1221,7 +1220,7 @@ from_client_get_schema(clicon_handle h,
if ((cbmsg = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
if (version)
cprintf(cbmsg, "No schema matching: %s@%s", identifier, version);
else
@ -1234,7 +1233,7 @@ from_client_get_schema(clicon_handle h,
if ((cbmsg = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
cprintf(cbmsg, "Format not supported: %s", format);
if (netconf_invalid_value(cbret, "protocol", cbuf_get(cbmsg)) < 0)
goto done;
@ -1264,11 +1263,11 @@ from_client_get_schema(clicon_handle h,
return retval;
}
/*! Set debug level.
/*! Set debug level.
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
@ -1284,7 +1283,7 @@ from_client_debug(clicon_handle h,
int retval = -1;
uint32_t level;
char *valstr;
if ((valstr = xml_find_body(xe, "level")) == NULL){
if (netconf_missing_element(cbret, "application", "level", NULL) < 0)
goto done;
@ -1292,9 +1291,9 @@ from_client_debug(clicon_handle h,
}
level = atoi(valstr);
clicon_debug_init(level, NULL); /* 0: dont debug, 1:debug */
clixon_debug_init(level, NULL); /* 0: dont debug, 1:debug */
setlogmask(LOG_UPTO(level?LOG_DEBUG:LOG_INFO)); /* for syslog */
clicon_log(LOG_NOTICE, "%s debug:%d", __FUNCTION__, clicon_debug_get());
clicon_log(LOG_NOTICE, "%s debug:%d", __FUNCTION__, clixon_debug_get());
cprintf(cbret, "<rpc-reply xmlns=\"%s\"><ok/></rpc-reply>", NETCONF_BASE_NAMESPACE);
ok:
retval = 0;
@ -1304,11 +1303,11 @@ from_client_debug(clicon_handle h,
/*! Check liveness of backend daemon, just send a reply
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -1325,11 +1324,11 @@ from_client_ping(clicon_handle h,
/*! Check liveness of backend daemon, just send a reply
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -1348,7 +1347,7 @@ from_client_stats(clicon_handle h,
yang_stmt *yspec;
yang_stmt *ymodext;
cxobj *xt = NULL;
if ((str = xml_find_body(xe, "modules")) != NULL)
modules = strcmp(str, "true") == 0;
yspec = clicon_dbspec_yang(h);
@ -1378,7 +1377,7 @@ from_client_stats(clicon_handle h,
goto done;
if (modules){
ym = NULL;
while ((ym = yn_each(yspec, ym)) != NULL) {
while ((ym = yn_each(yspec, ym)) != NULL) {
cprintf(cbret, "<module><name>%s</name>", yang_argument_get(ym));
if (clixon_stats_module_get(h, ym, cbret) < 0)
goto done;
@ -1418,11 +1417,11 @@ from_client_stats(clicon_handle h,
/*! Request restart of specific plugins
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -1440,8 +1439,8 @@ from_client_restart_plugin(clicon_handle h,
int i;
clixon_plugin_t *cp;
int ret;
if (xpath_vec(xe, NULL, "plugin", &vec, &veclen) < 0)
if (xpath_vec(xe, NULL, "plugin", &vec, &veclen) < 0)
goto done;
for (i=0; i<veclen; i++){
name = xml_body(vec[i]);
@ -1466,11 +1465,11 @@ from_client_restart_plugin(clicon_handle h,
/*! Control a specific process or daemon: start/stop, etc
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*/
@ -1486,7 +1485,7 @@ from_client_process_control(clicon_handle h,
char *name = NULL;
char *opstr = NULL;
proc_operation op = PROC_OP_NONE;
if ((x = xml_find_type(xe, NULL, "name", CX_ELMNT)) != NULL)
name = xml_body(x);
if ((x = xml_find_type(xe, NULL, "operation", CX_ELMNT)) != NULL){
@ -1557,7 +1556,7 @@ from_client_hello(clicon_handle h,
*/
static int
from_client_msg(clicon_handle h,
struct client_entry *ce,
struct client_entry *ce,
struct clicon_msg *msg)
{
int retval = -1;
@ -1581,9 +1580,9 @@ from_client_msg(clicon_handle h,
char *namespace = NULL;
int nr = 0;
cbuf *cbce = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
yspec = clicon_dbspec_yang(h);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
yspec = clicon_dbspec_yang(h);
/* Return netconf message. Should be filled in by the dispatch(sub) functions
* as wither rpc-error or by positive response.
*/
@ -1629,7 +1628,7 @@ from_client_msg(clicon_handle h,
* 3. Its a create-subscription 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);
clixon_debug(CLIXON_DBG_DEFAULT, "%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
*/
@ -1707,7 +1706,7 @@ from_client_msg(clicon_handle h,
goto done;
}
module = yang_argument_get(ymod);
clicon_debug(CLIXON_DBG_DEFAULT, "%s module:%s rpc:%s ce_id:%u s:%d", __FUNCTION__, module,
clixon_debug(CLIXON_DBG_DEFAULT, "%s module:%s rpc:%s ce_id:%u s:%d", __FUNCTION__, module,
rpc, ce->ce_id, ce->ce_s);
/* Pre-NACM access step */
xnacm = NULL;
@ -1773,7 +1772,7 @@ from_client_msg(clicon_handle h,
if (cbuf_len(cbret) == 0)
if (netconf_operation_failed(cbret, "application", clicon_errno?clicon_err_reason:"unknown")< 0)
goto done;
// XXX clicon_debug(CLIXON_DBG_MSG, "Reply:%s", cbuf_get(cbret));
// XXX clixon_debug(CLIXON_DBG_MSG, "Reply:%s", cbuf_get(cbret));
/* XXX problem here is that cbret has not been parsed so may contain
parse errors */
if (ce_client_string(ce, &cbce) < 0)
@ -1797,8 +1796,8 @@ from_client_msg(clicon_handle h,
}
// ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
done:
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (xnacm){
xml_free(xnacm);
if (clicon_nacm_cache_set(h, NULL) < 0)
@ -1813,10 +1812,10 @@ from_client_msg(clicon_handle h,
if (cbret)
cbuf_free(cbret);
/* Sanity: log if clicon_err() is not called ! */
if (retval < 0 && clicon_errno < 0)
if (retval < 0 && clicon_errno < 0)
clicon_log(LOG_NOTICE, "%s: Internal error: No clicon_err call on RPC error (message: %s)",
__FUNCTION__, rpc?rpc:"");
// clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
// clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;// -1 here terminates backend
}
@ -1829,7 +1828,7 @@ from_client_msg(clicon_handle h,
* propagated back to client.
*/
int
from_client(int s,
from_client(int s,
void* arg)
{
int retval = -1;
@ -1839,7 +1838,7 @@ from_client(int s,
int eof = 0;
cbuf *cbce = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (s != ce->ce_s){
clicon_err(OE_NETCONF, EINVAL, "Internal error: s != ce->ce_s");
goto done;
@ -1849,7 +1848,7 @@ from_client(int s,
if (clicon_msg_rcv(ce->ce_s, cbuf_get(cbce), 0, &msg, &eof) < 0)
goto done;
if (eof){
backend_client_rm(h, ce);
backend_client_rm(h, ce);
netconf_monitoring_counter_inc(h, "dropped-sessions");
}
else
@ -1857,7 +1856,7 @@ from_client(int s,
goto done;
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval=%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval=%d", __FUNCTION__, retval);
if (cbce)
cbuf_free(cbce);
if (msg)

View file

@ -39,7 +39,7 @@
/*
* Prototypes
*/
*/
int backend_monitoring_state_get(clicon_handle h, yang_stmt *yspec, char *xpath, cvec *nsc, cxobj **xret, cxobj **xerr);
int backend_client_rm(clicon_handle h, struct client_entry *ce);
int from_client(int fd, void *arg);

View file

@ -102,7 +102,7 @@ generic_validate(clicon_handle h,
cbuf *cb = NULL;
/* All entries */
if ((ret = xml_yang_validate_all_top(h, td->td_target, xret)) < 0)
if ((ret = xml_yang_validate_all_top(h, td->td_target, xret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -135,10 +135,11 @@ generic_validate(clicon_handle h,
}
/*! Common startup validation
*
* Get db, upgrade it w potential transformed XML, populate it w yang spec,
* sort it, validate it by triggering a transaction
* and call application callback validations.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db The startup database. The wanted backend state
* @param[in] td Transaction data
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
@ -157,7 +158,7 @@ generic_validate(clicon_handle h,
* @see validate_common for incoming validate/commit
*/
static int
startup_common(clicon_handle h,
startup_common(clicon_handle h,
char *db,
transaction_data_t *td,
cbuf *cbret)
@ -177,7 +178,7 @@ startup_common(clicon_handle h,
if (clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
if ((msdiff = modstate_diff_new()) == NULL)
goto done;
clicon_debug(1, "Reading initial config from %s", db);
clixon_debug(CLIXON_DBG_DEFAULT, "Reading initial config from %s", db);
/* Get the startup datastore WITHOUT binding to YANG, sorting and default setting.
* It is done below, later in this function
*/
@ -189,7 +190,7 @@ startup_common(clicon_handle h,
if (clicon_quit_upgrade_get(h) == 1){
xml_print(stderr, xerr);
clicon_err(OE_XML, 0, "invalid configuration before upgrade");
exit(0); /* This is fairly abrupt , but need to avoid side-effects of rewinding
exit(0); /* This is fairly abrupt , but need to avoid side-effects of rewinding
* See similar clause below
*/
}
@ -202,7 +203,7 @@ startup_common(clicon_handle h,
if (xmldb_get0(h, db, YB_NONE, NULL, "/", 0, 0, &xt, msdiff, &xerr) < 0)
goto done;
}
clicon_debug_xml(CLIXON_DBG_DETAIL, xt, "startup");
clixon_debug_xml(CLIXON_DBG_DETAIL, xt, "startup");
if (msdiff && msdiff->md_status == 0){ // Possibly check for CLICON_XMLDB_MODSTATE
clicon_log(LOG_WARNING, "Modstate expected in startup datastore but not found\n"
"This may indicate that the datastore is not initialized corrrectly, such as copy/pasted.\n"
@ -212,7 +213,7 @@ startup_common(clicon_handle h,
clicon_err(OE_YANG, 0, "Yang spec not set");
goto done;
}
clicon_debug(1, "Reading startup config done");
clixon_debug(CLIXON_DBG_DEFAULT, "Reading startup config done");
/* Clear flags xpath for get */
xml_apply0(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
(void*)(XML_FLAG_MARK|XML_FLAG_CHANGE));
@ -253,7 +254,7 @@ startup_common(clicon_handle h,
stack. Alternative is to make a separate function stack for this. */
}
/* If empty skip. Note upgrading can add children, so it may be empty before that. */
if (xml_child_nr(xt) == 0){
if (xml_child_nr(xt) == 0){
td->td_target = xt;
xt = NULL;
goto ok;
@ -264,7 +265,7 @@ startup_common(clicon_handle h,
if (ret == 0){
if (clixon_xml2cbuf(cbret, xret, 0, 0, NULL, -1, 0) < 0)
goto done;
goto fail;
goto fail;
}
/* After upgrade check no state data */
if ((ret = xml_non_config_data(xt, &xret)) < 0)
@ -272,7 +273,7 @@ startup_common(clicon_handle h,
if (ret == 0){
if (clixon_xml2cbuf(cbret, xret, 0, 0, NULL, -1, 0) < 0)
goto done;
goto fail;
goto fail;
}
/* Sort xml */
if (xml_sort_recurse(xt) < 0)
@ -283,7 +284,7 @@ startup_common(clicon_handle h,
/* Apply default values (removed in clear function) */
if (xml_default_recurse(xt, 0) < 0)
goto done;
/* Handcraft transition with with only add tree */
td->td_target = xt;
xt = NULL;
@ -291,7 +292,7 @@ startup_common(clicon_handle h,
while ((x = xml_child_each(td->td_target, x, CX_ELMNT)) != NULL){
xml_flag_set(x, XML_FLAG_ADD); /* Also down */
xml_apply(x, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_ADD);
if (cxvec_append(x, &td->td_avec, &td->td_alen) < 0)
if (cxvec_append(x, &td->td_avec, &td->td_alen) < 0)
goto done;
}
@ -301,7 +302,7 @@ startup_common(clicon_handle h,
/* 5. Make generic validation on all new or changed data.
Note this is only call that uses 3-values */
clicon_debug(1, "Validating startup %s", db);
clixon_debug(CLIXON_DBG_DEFAULT, "Validating startup %s", db);
if ((ret = generic_validate(h, yspec, td, &xret)) < 0)
goto done;
if (ret == 0){
@ -328,14 +329,14 @@ startup_common(clicon_handle h,
if (msdiff)
modstate_diff_free(msdiff);
return retval;
fail:
fail:
retval = 0;
goto done;
}
/*! Read startup db, check upgrades and validate it, return upgraded XML
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db The startup database. The wanted backend state
* @param[out] xtr (Potentially) transformed XML
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
@ -344,7 +345,7 @@ startup_common(clicon_handle h,
* @retval -1 Error - or validation failed (but cbret not set)
*/
int
startup_validate(clicon_handle h,
startup_validate(clicon_handle h,
char *db,
cxobj **xtr,
cbuf *cbret)
@ -369,7 +370,7 @@ startup_validate(clicon_handle h,
if (xmldb_get0_clear(h, td->td_target) < 0)
goto done;
if (xtr){
*xtr = td->td_target;
*xtr = td->td_target;
td->td_target = NULL;
}
retval = 1;
@ -386,7 +387,7 @@ startup_validate(clicon_handle h,
/*! Read startup db, check upgrades and commit it
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db The startup database. The wanted backend state
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
* @retval 1 Validation OK
@ -395,7 +396,7 @@ startup_validate(clicon_handle h,
* Only called from startup_mode_startup
*/
int
startup_commit(clicon_handle h,
startup_commit(clicon_handle h,
char *db,
cbuf *cbret)
{
@ -426,7 +427,7 @@ startup_commit(clicon_handle h,
/* [Delete and] create running db */
if (xmldb_exists(h, "running") == 1){
if (xmldb_delete(h, "running") != 0 && errno != ENOENT)
if (xmldb_delete(h, "running") != 0 && errno != ENOENT)
goto done;;
}
if (xmldb_create(h, "running") < 0)
@ -463,9 +464,10 @@ startup_commit(clicon_handle h,
}
/*! Validate a candidate db and comnpare to running
*
* Get both source and dest datastore, validate target, compute diffs
* and call application callback validations.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db The (candidate) database. The wanted backend state
* @param[in] td Transaction data
* @param[out] xret Error XML tree, if retval is 0. Free with xml_free after use
@ -477,7 +479,7 @@ startup_commit(clicon_handle h,
* @see startup_common for startup scenario
*/
static int
validate_common(clicon_handle h,
validate_common(clicon_handle h,
char *db,
transaction_data_t *td,
cxobj **xret)
@ -487,11 +489,11 @@ validate_common(clicon_handle h,
int i;
cxobj *xn;
int ret;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
}
/* This is the state we are going to */
if ((ret = xmldb_get0(h, db, YB_MODULE, NULL, "/", 0, 0, &td->td_target, NULL, xret)) < 0)
goto done;
@ -500,7 +502,7 @@ validate_common(clicon_handle h,
/* Clear flags xpath for get */
xml_apply0(td->td_target, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
(void*)(XML_FLAG_MARK|XML_FLAG_CHANGE));
/* 2. Parse xml trees
/* 2. Parse xml trees
* This is the state we are going from */
if ((ret = xmldb_get0(h, "running", YB_MODULE, NULL, "/", 0, 0, &td->td_src, NULL, xret)) < 0)
goto done;
@ -520,7 +522,7 @@ validate_common(clicon_handle h,
&td->td_tcvec, /* changed: wanted values */
&td->td_clen) < 0)
goto done;
if (clicon_debug_get() & CLIXON_DBG_DETAIL)
if (clixon_debug_get() & CLIXON_DBG_DETAIL)
transaction_dbg(h, CLIXON_DBG_DETAIL, td, __FUNCTION__);
/* Mark as changed in tree */
for (i=0; i<td->td_dlen; i++){ /* Also down */
@ -571,7 +573,7 @@ validate_common(clicon_handle h,
/*! Start a validate transaction
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db A candidate database, typically "candidate" but not necessarily so
* @param[out] cbret CLIgen buffer w error stmt if retval = 0
* @retval 1 Validation OK
@ -579,7 +581,7 @@ validate_common(clicon_handle h,
* @retval -1 Error - or validation failed
*/
int
candidate_validate(clicon_handle h,
candidate_validate(clicon_handle h,
char *db,
cbuf *cbret)
{
@ -587,8 +589,8 @@ candidate_validate(clicon_handle h,
transaction_data_t *td = NULL;
cxobj *xret = NULL;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (db == NULL || cbret == NULL){
clicon_err(OE_CFG, EINVAL, "db or cbret is NULL");
goto done;
@ -647,7 +649,7 @@ candidate_validate(clicon_handle h,
* The code reverts changes if the commit fails. But if the revert
* fails, we just ignore the errors and proceed. Maybe we should
* do something more drastic?
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc> (or NULL)
* @param[in] db A candidate database, not necessarily "candidate"
* @param[in] myid Client id of triggering incoming message (or 0)
@ -658,7 +660,7 @@ candidate_validate(clicon_handle h,
* @retval -1 Error - or validation failed
*/
int
candidate_commit(clicon_handle h,
candidate_commit(clicon_handle h,
cxobj *xe,
char *db,
uint32_t myid,
@ -713,7 +715,7 @@ candidate_commit(clicon_handle h,
/* After commit, make a post-commit call (sure that all plugins have committed) */
if (plugin_transaction_commit_done_all(h, td) < 0)
goto done;
/* Clear cached trees from default values and marking */
if (xmldb_get0_clear(h, td->td_target) < 0)
goto done;
@ -738,7 +740,6 @@ candidate_commit(clicon_handle h,
/* 9. Call plugin transaction end callbacks */
plugin_transaction_end_all(h, td);
retval = 1;
done:
/* In case of failure (or error), call plugin transaction termination callbacks */
@ -759,11 +760,11 @@ candidate_commit(clicon_handle h,
/*! Commit the candidate configuration as the device's new current configuration
*
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
* @note NACM: The server MUST determine the exact nodes in the running
@ -815,13 +816,13 @@ from_client_commit(clicon_handle h,
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
if (netconf_in_use(cbret, "protocol", "Operation failed, lock is already held") < 0)
goto done;
goto ok;
}
if ((ret = candidate_commit(h, xe, "candidate", myid, 0, cbret)) < 0){ /* Assume validation fail, nofatal */
clicon_debug(1, "Commit candidate failed");
clixon_debug(CLIXON_DBG_DEFAULT, "Commit candidate failed");
if (ret < 0)
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
@ -839,13 +840,12 @@ from_client_commit(clicon_handle h,
/*! Revert the candidate configuration to the current running configuration.
*
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK. This may indicate both ok and err msg back to client
* @retval 0 OK
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK. This may indicate both ok and err msg back to client
* @retval -1 Error
* NACM: No datastore permissions are needed.
*/
@ -861,14 +861,14 @@ from_client_discard_changes(clicon_handle h,
uint32_t myid = ce->ce_id;
uint32_t iddb;
cbuf *cbx = NULL; /* Assist cbuf */
/* Check if target locked by other client */
iddb = xmldb_islocked(h, "candidate");
if (iddb && myid != iddb){
if ((cbx = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
}
cprintf(cbx, "<session-id>%u</session-id>", iddb);
if (netconf_lock_denied(cbret, cbuf_get(cbx), "Operation failed, lock is already held") < 0)
goto done;
@ -890,11 +890,12 @@ from_client_discard_changes(clicon_handle h,
}
/*! Validates the contents of the specified configuration.
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK. This may indicate both ok and err msg back to client
* (eg invalid)
* @retval -1 Error
@ -910,7 +911,7 @@ from_client_validate(clicon_handle h,
int ret;
char *db;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((db = netconf_db_find(xe, "source")) == NULL){
if (netconf_missing_element(cbret, "protocol", "source", NULL) < 0)
goto done;
@ -927,6 +928,7 @@ from_client_validate(clicon_handle h,
} /* from_client_validate */
/*! Restart specific backend plugins without full backend restart
*
* Note, depending on plugin callbacks, there may be other dependencies which may make this
* difficult in the general case.
*/
@ -945,7 +947,7 @@ from_client_restart_one(clicon_handle h,
int i;
cxobj *xn;
void *wh = NULL;
yspec = clicon_dbspec_yang(h);
if (xmldb_db_reset(h, db) < 0)
goto done;
@ -955,7 +957,7 @@ from_client_restart_one(clicon_handle h,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if ((retval = resetfn(h, db)) < 0) {
clicon_debug(1, "plugin_start() failed");
clixon_debug(CLIXON_DBG_DEFAULT, "plugin_start() failed");
goto done;
}
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -1049,7 +1051,7 @@ from_client_restart_one(clicon_handle h,
}
/*! Reset running and start in failsafe mode. If no failsafe then quit.
*
*
* param[in] h Clixon handle
* param[in] phase Debug string
Typically done when startup status is not OK so

View file

@ -105,6 +105,7 @@ confirmed_commit_init(clicon_handle h)
}
/*! If confirm commit persist-id exists, free it
*
* @param[in] h Clixon handle
* @retval 0 OK
*/
@ -112,7 +113,7 @@ int
confirmed_commit_free(clicon_handle h)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
if (cc != NULL){
if (cc->cc_persist_id != NULL)
@ -130,7 +131,7 @@ enum confirmed_commit_state
confirmed_commit_state_get(clicon_handle h)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
return cc->cc_state;
}
@ -140,7 +141,7 @@ confirmed_commit_state_set(clicon_handle h,
enum confirmed_commit_state state)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
cc->cc_state = state;
return 0;
@ -150,7 +151,7 @@ char *
confirmed_commit_persist_id_get(clicon_handle h)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
return cc->cc_persist_id;
}
@ -160,7 +161,7 @@ confirmed_commit_persist_id_set(clicon_handle h,
char *persist_id)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
if (cc->cc_persist_id)
free(cc->cc_persist_id);
@ -179,7 +180,7 @@ uint32_t
confirmed_commit_session_id_get(clicon_handle h)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
return cc->cc_session_id;
}
@ -189,7 +190,7 @@ confirmed_commit_session_id_set(clicon_handle h,
uint32_t session_id)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
cc->cc_session_id = session_id;
return 0;
@ -201,7 +202,7 @@ confirmed_commit_fn_arg_get(clicon_handle h,
void **arg)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
*fn = cc->cc_fn;
*arg = cc->cc_arg;
@ -214,7 +215,7 @@ confirmed_commit_fn_arg_set(clicon_handle h,
void *arg)
{
struct confirmed_commit *cc = NULL;
clicon_ptr_get(h, "confirmed-commit-struct", (void**)&cc);
cc->cc_fn = fn;
cc->cc_arg = arg;
@ -222,6 +223,7 @@ confirmed_commit_fn_arg_set(clicon_handle h,
}
/*! Return if confirmed tag found
*
* @param[in] xe Commit rpc xml
* @retval 1 Confirmed tag exists
* @retval 0 Confirmed tag does not exist
@ -233,6 +235,7 @@ xe_confirmed(cxobj *xe)
}
/*! Return if persist exists and its string value field
*
* @param[in] xe Commit rpc xml
* @param[out] str Pointer to persist
* @retval 1 Persist field exists
@ -274,6 +277,7 @@ xe_persist_id(cxobj *xe,
}
/*! Return timeout
*
* @param[in] xe Commit rpc xml
* @retval sec Timeout in seconds, can be 0 if no timeout exists or is zero
*/
@ -282,7 +286,7 @@ xe_timeout(cxobj *xe)
{
cxobj *xml;
char *str;
if ((xml = xml_find_type(xe, NULL, "confirm-timeout", CX_ELMNT)) != NULL &&
(str = xml_body(xml)) != NULL)
return strtoul(str, NULL, 10);
@ -293,7 +297,7 @@ xe_timeout(cxobj *xe)
*
* @param[in] h Clixon handle
* @retval 0 Rollback event successfully cancelled
* @retval -1 No Rollback event was found
* @retval -1 No Rollback event was found
*/
int
cancel_rollback_event(clicon_handle h)
@ -317,7 +321,7 @@ cancel_rollback_event(clicon_handle h)
* @param[in] fd a dummy argument per the event callback semantics
* @param[in] arg a void pointer to a clicon_handle
* @retval 0 the rollback was successful
* @retval -1 the rollback failed
* @retval -1 the rollback failed
* @see do_rollback()
*/
static int
@ -337,7 +341,7 @@ rollback_fn(int fd,
* @param[in] timeout a uint32 representing the number of seconds before the rollback event should fire
*
* @retval 0 Rollback event successfully scheduled
* @retval -1 Rollback event was not scheduled
* @retval -1 Rollback event was not scheduled
*/
static int
schedule_rollback_event(clicon_handle h,
@ -373,6 +377,7 @@ schedule_rollback_event(clicon_handle h,
}
/*! Cancel a confirming commit by removing rollback, and free state
*
* @param[in] h
* @param[out] cbret
* @retval 0 OK
@ -401,12 +406,12 @@ cancel_confirmed_commit(clicon_handle h)
* without a <persist> value, OR
* 2) be presented with a <persist-id> value that matches the <persist> value accompanying the prior confirmed-commit
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[in] myid current client session-id
* @retval 1 The confirming-commit is valid
* @retval 0 The confirming-commit is not valid
* @retval -1 Error
* @retval -1 Error
*/
static int
check_valid_confirming_commit(clicon_handle h,
@ -452,7 +457,7 @@ check_valid_confirming_commit(clicon_handle h,
"not issued on the same session as the confirmed-commit");
goto invalid;
default:
clicon_debug(1, "commit-confirmed state !? %d", confirmed_commit_state_get(h));
clixon_debug(CLIXON_DBG_DEFAULT, "commit-confirmed state !? %d", confirmed_commit_state_get(h));
goto invalid;
}
retval = 1; // valid
@ -471,11 +476,11 @@ check_valid_confirming_commit(clicon_handle h,
* In the second phase, the action taken is to handle both confirming- and confirmed-commit by creating the
* rollback database as required, then deleting it once the sequence is complete.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xe Commit rpc xml or NULL
* @param[in] myid Current session-id, only valid > 0 if call is made as a result of an incoming message
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* @note There are some calls to this function where myid is 0 (which is invalid). It is unclear if such calls
* actually occur, and if so, if they are correctly handled. The calls are from do_rollback() and load_failsafe()
*/
@ -622,9 +627,9 @@ handle_confirmed_commit(clicon_handle h,
* 2. from_client_cancel_commit() (invoked either by netconf client, or CLI)
* 3. rollback_fn() (invoked by expiration of the rollback event timer)
*
* @param[in] h Clicon handle
* @retval -1 Error
* @param[in] h Clixon handle
* @retval 0 Success
* @retval -1 Error
* @see backend_client_rm()
* @see from_client_cancel_commit()
* @see rollback_fn()
@ -696,12 +701,13 @@ do_rollback(clicon_handle h,
}
/*! Cancel an ongoing confirmed commit.
*
* If the confirmed commit is persistent, the parameter 'persist-id' must be
* given, and it must match the value of the 'persist' parameter.
* If the confirmed-commit is ephemeral, the 'persist-id' must not be given and both the confirmed-commit and the
* cancel-commit must originate from the same session.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
@ -777,7 +783,8 @@ from_client_cancel_commit(clicon_handle h,
}
/*! Incoming commit handler for confirmed commit
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[in] myid Client-id
* @param[out] cbret Return xml tree

View file

@ -72,12 +72,15 @@
#include "backend_handle.h"
#include "backend_get.h"
/*!
/*! restrconf get capabilities
*
* Maybe should be in the restconf client instead of backend?
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in] xpath Xpath selection, not used but may be to filter early
* @param[out] xrs XML restconf-state node
* @retval 0 OK
* @retval -1 Error
* @see netconf_hello_server
* @see rfc8040 Sections 9.1
*/
@ -114,7 +117,8 @@ restconf_client_get_capabilities(clicon_handle h,
}
/*! Get streams state according to RFC 8040 or RFC5277 common function
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in] xpath Xpath selection, not used but may be to filter early
* @param[in] module Name of yang module
@ -176,7 +180,8 @@ client_get_streams(clicon_handle h,
}
/*! Get system state-data, including streams and plugins
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xpath XPath selection, may be used to filter early
* @param[in] nsc XML Namespace context for xpath
* @param[in] wdef With-defaults parameter, see RFC 6243
@ -213,7 +218,7 @@ get_statedata(clicon_handle h,
cbuf *cb = NULL;
cxobj *xerr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done;
@ -368,7 +373,7 @@ get_statedata(clicon_handle h,
} /* switch wdef */
retval = 1; /* OK */
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (xerr)
xml_free(xerr);
if (x1)
@ -390,7 +395,7 @@ get_statedata(clicon_handle h,
* and we need to re-add it.
* Note original xpath
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in] xret Result XML tree
* @param[in] xvec xpath lookup result on xret
@ -438,7 +443,7 @@ filter_xpath_again(clicon_handle h,
/*! Help function for NACM access and return message
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xret Result XML tree
* @param[in] xvec xpath lookup result on xret
* @param[in] xlen length of xvec
@ -520,7 +525,7 @@ element2value(clicon_handle h,
/*! Extract offset and limit from get/list-pagination
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] offset Number of entries in the working result-set that should be skipped
* @param[out] limit Limits the number of entries returned from the working result-set
@ -552,7 +557,7 @@ list_pagination_hdr(clicon_handle h,
*
* It is specialized enough to have its own function. Specifically, extra attributes as well
* as the list-paginaiton API
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] ce Client entry, for locking
* @param[in] xe Request: <rpc><xn></rpc>
* @param[in] content Get config/state/both
@ -764,7 +769,7 @@ get_list_pagination(clicon_handle h,
if ((ret = xml_bind_yang(h, xret, YB_MODULE, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
clicon_debug_xml(1, xret, "Yang bind pagination state");
clixon_debug_xml(1, xret, "Yang bind pagination state");
if (clixon_netconf_internal_error(xerr,
". Internal error, state callback returned invalid XML",
NULL) < 0)
@ -821,7 +826,7 @@ get_list_pagination(clicon_handle h,
/*! Common get/get-config code for retrieving configuration and state information.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] ce Client entry, for locking
* @param[in] xe Request: <rpc><xn></rpc>
* @param[in] content Get config/state/both
@ -867,7 +872,7 @@ get_common(clicon_handle h,
char *wdefstr;
wdef = WITHDEFAULTS_EXPLICIT;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
username = clicon_username_get(h);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec9");
@ -1013,7 +1018,7 @@ get_common(clicon_handle h,
(ret = xml_yang_validate_add(h, xret, &xerr)) < 0)
goto done;
if (ret == 0){
clicon_debug_xml(1, xret, "VALIDATE_STATE");
clixon_debug_xml(1, xret, "VALIDATE_STATE");
if (clixon_netconf_internal_error(xerr,
". Internal error, state callback returned invalid XML",
NULL) < 0)
@ -1044,7 +1049,7 @@ get_common(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (xvec)
free(xvec);
if (xret)
@ -1067,12 +1072,12 @@ get_common(clicon_handle h,
}
/*! Retrieve all or part of a specified configuration.
*
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
*
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
* @see from_client_get
@ -1099,11 +1104,11 @@ from_client_get_config(clicon_handle h,
/*! Retrieve running configuration and device state information.
*
* @param[in] h Clicon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] h Clixon handle
* @param[in] xe Request: <rpc><xn></rpc>
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
* @param[in] arg client-entry
* @param[in] regarg User argument given at rpc_callback_register()
* @param[in] regarg User argument given at rpc_callback_register()
* @retval 0 OK
* @retval -1 Error
*
@ -1113,13 +1118,13 @@ int
from_client_get(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *arg,
void *regarg)
{
netconf_content content = CONTENT_ALL;
char *attr;
struct client_entry *ce = (struct client_entry *)arg;
/* Clixon extensions: content */
if ((attr = xml_find_value(xe, "content")) != NULL)
content = netconf_content_str2int(attr);

View file

@ -39,7 +39,7 @@
/*
* Prototypes
*/
*/
int from_client_get_config(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
int from_client_get(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg);
int from_client_get_pageable_list(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg); /* XXX */

View file

@ -84,6 +84,7 @@
#define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log"
/*! Clean and close all state of backend (but dont exit).
*
* Cannot use h after this
* @param[in] h Clixon handle
*/
@ -99,7 +100,7 @@ backend_terminate(clicon_handle h)
int ss;
cvec *nsctx;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((ss = clicon_socket_get(h)) != -1)
close(ss);
/* Disconnect datastore */
@ -142,7 +143,7 @@ backend_terminate(clicon_handle h)
unlink(sockpath);
backend_handle_exit(h); /* Also deletes streams. Cannot use h after this. */
clixon_event_exit();
clicon_debug(1, "%s done", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s done", __FUNCTION__);
clixon_err_exit();
clicon_log_exit();
return 0;
@ -163,19 +164,21 @@ backend_sig_term(int arg)
clixon_exit_set(1); /* checked in clixon_event_loop() */
}
/*! wait for killed child
/*! Wait for killed child
*
* primary use in case restconf daemon forked using process-control API
* This may cause EINTR in eg select() in clixon_event_loop() which will be ignored
*/
static void
backend_sig_child(int arg)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clicon_sig_child_set(1);
}
/*! Create backend server socket and register callback
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval s Server socket file descriptor (see socket(2))
* @retval -1 Error
*/
@ -278,7 +281,7 @@ xmldb_drop_priv(clicon_handle h,
* - uid is currently 0 (started as root)
* - CLICON_BACKEND_USER is set
* - CLICON_BACKEND_PRIVILEGES is not "none"
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] gid Group id (assume already known)
* @retval 0 OK
* @retval -1 Error
@ -425,7 +428,7 @@ backend_timer_setup(int fd,
struct timeval t;
struct timeval t1 = {10, 0};
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
gettimeofday(&now, NULL);
backend_client_print(h, stderr);
@ -588,7 +591,7 @@ main(int argc,
* double syslogs until fork below.
*/
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(dbg, NULL);
clixon_debug_init(dbg, NULL);
yang_init(h);
/* Find and read configfile */
@ -1082,7 +1085,7 @@ main(int argc,
clicon_session_id_set(h, 1);
#if 0 /* debug */
/* Enable this to get prints of datastore and session status */
if (0 && clicon_debug_get() &&
if (clixon_debug_get() &&
backend_timer_setup(0, h) < 0)
goto done;
#endif

View file

@ -68,7 +68,7 @@
*
* The system 'state' should be the same as the contents of running_db
* @param[in] cp Plugin handle
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of datastore
* @retval 0 OK
* @retval -1 Error
@ -89,7 +89,7 @@ clixon_plugin_reset_one(clixon_plugin_t *cp,
if (fn(h, db) < 0) {
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
@ -101,7 +101,7 @@ clixon_plugin_reset_one(clixon_plugin_t *cp,
done:
return retval;
}
/*! Call all plugins reset callbacks
*
* The system 'state' should be the same as the contents of running_db
@ -114,10 +114,10 @@ int
clixon_plugin_reset_all(clicon_handle h,
char *db)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
int retval = -1;
clixon_plugin_t *cp = NULL;
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Loop through all plugins, call callbacks in each */
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_reset_one(cp, h, db) < 0)
@ -169,7 +169,7 @@ clixon_plugin_pre_daemon_one(clixon_plugin_t *cp,
* This point in time is after "start" and before
* before daemonization/fork,
* It is not called if backend is started in daemon mode.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
@ -179,7 +179,7 @@ clixon_plugin_pre_daemon_all(clicon_handle h)
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Loop through all plugins, call callbacks in each */
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_pre_daemon_one(cp, h) < 0)
@ -202,7 +202,7 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp,
clicon_handle h)
{
int retval = -1;
plgdaemon_t *fn; /* Daemonize plugin callback function */
plgdaemon_t *fn; /* Daemonize plugin callback function */
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_daemon) != NULL){
@ -212,7 +212,7 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp,
if (fn(h) < 0) {
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Daemon callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
@ -224,14 +224,14 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp,
done:
return retval;
}
/*! Call all plugins "post-" daemonize callbacks
*
*
* This point in time is after "start" and after "pre-daemon" and
* after daemonization/fork, ie when
* daemon is in the background but before dropped privileges.
* In case of foreground mode (-F) it is still called but no fork has occured.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* @note Also called for non-background mode
@ -241,8 +241,8 @@ clixon_plugin_daemon_all(clicon_handle h)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Loop through all plugins, call callbacks in each */
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_daemon_one(cp, h) < 0)
@ -289,7 +289,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
plgstatedata_t *fn; /* Plugin statedata fn */
cxobj *x = NULL;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){
if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
goto done;
@ -299,7 +299,7 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp,
if (fn(h, nsc, xpath, x) < 0){
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, clixon_plugin_name_get(cp));
goto fail; /* Dont quit here on user callbacks */
@ -344,10 +344,10 @@ clixon_plugin_statedata_all(clicon_handle h,
int ret;
cxobj *x = NULL;
clixon_plugin_t *cp = NULL;
cbuf *cberr = NULL;
cbuf *cberr = NULL;
cxobj *xerr = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if ((ret = clixon_plugin_statedata_one(cp, h, nsc, xpath, &x)) < 0)
goto done;
@ -373,7 +373,7 @@ clixon_plugin_statedata_all(clicon_handle h,
x = NULL;
continue;
}
clicon_debug_xml(CLIXON_DBG_DETAIL, x, "%s %s STATE:", __FUNCTION__, clixon_plugin_name_get(cp));
clixon_debug_xml(CLIXON_DBG_DETAIL, x, "%s %s STATE:", __FUNCTION__, clixon_plugin_name_get(cp));
/* XXX: ret == 0 invalid yang binding should be handled as internal error */
if ((ret = xml_bind_yang(h, x, YB_MODULE, yspec, &xerr)) < 0)
goto done;
@ -436,13 +436,13 @@ clixon_plugin_lockdb_one(clixon_plugin_t *cp,
int retval = -1;
plglockdb_t *fn; /* Plugin statedata fn */
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (fn(h, db, lock, id) < 0)
goto done;
goto done;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
}
@ -470,12 +470,12 @@ clixon_plugin_lockdb_all(clicon_handle h,
{
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_lockdb_one(cp, h, db, lock, id) < 0)
goto done;
}
}
retval = 0;
done:
return retval;
@ -485,6 +485,8 @@ clixon_plugin_lockdb_all(clicon_handle h,
*
* @param[in] h Clixon handle
* @param[in] xpath Registered XPath using canonical prefixes
* @retval 1 OK
* @retval -1 Error
*/
int
clixon_pagination_cb_call(clicon_handle h,
@ -505,17 +507,19 @@ clixon_pagination_cb_call(clicon_handle h,
clicon_ptr_get(h, "pagination-entries", (void**)&htable);
if (htable && dispatcher_call_handlers(htable, h, xpath, &pd) < 0)
goto done;
retval = 1;
retval = 1; // XXX 0?
done:
return retval;
}
/*! Register a state data callback
*
/*! Register a state data callback
*
* @param[in] h Clixon handle
* @param[in] fn Callback
* @param[in] xpath Registered XPath using canonical prefixes
* @param[in] arg Domain-specific argument to send to callback
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_pagination_cb_register(clicon_handle h,
@ -526,7 +530,7 @@ clixon_pagination_cb_register(clicon_handle h,
int retval = -1;
dispatcher_definition x = {xpath, fn, arg};
dispatcher_entry_t *htable = NULL;
clicon_ptr_get(h, "pagination-entries", (void**)&htable);
if (dispatcher_register_handler(&htable, &x) < 0){
clicon_err(OE_PLUGIN, errno, "dispatcher");
@ -547,7 +551,7 @@ int
clixon_pagination_free(clicon_handle h)
{
dispatcher_entry_t *htable = NULL;
clicon_ptr_get(h, "pagination-entries", (void**)&htable);
if (htable)
dispatcher_free(htable);
@ -579,7 +583,7 @@ transaction_new(void)
*
* @param[in] td Transaction data will be deallocated after the call
*/
int
int
transaction_free(transaction_data_t *td)
{
if (td->td_src)
@ -608,13 +612,13 @@ transaction_free(transaction_data_t *td)
*/
int
plugin_transaction_begin_one(clixon_plugin_t *cp,
clicon_handle h,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_trans_begin) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -623,7 +627,7 @@ plugin_transaction_begin_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
}
@ -639,19 +643,19 @@ plugin_transaction_begin_one(clixon_plugin_t *cp,
/*! Call transaction_begin() in all plugins before a validate/commit.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
*/
int
plugin_transaction_begin_all(clicon_handle h,
plugin_transaction_begin_all(clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (plugin_transaction_begin_one(cp, h, td) < 0)
goto done;
@ -670,8 +674,8 @@ plugin_transaction_begin_all(clicon_handle h,
* @retval -1 Error
*/
int
plugin_transaction_validate_one(clixon_plugin_t *cp,
clicon_handle h,
plugin_transaction_validate_one(clixon_plugin_t *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
@ -686,7 +690,7 @@ plugin_transaction_validate_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
@ -701,13 +705,13 @@ plugin_transaction_validate_one(clixon_plugin_t *cp,
/*! Call transaction_validate callbacks in all backend plugins
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK. Validation succeeded in all plugins
* @retval -1 Error: one of the plugin callbacks returned validation fail
*/
int
plugin_transaction_validate_all(clicon_handle h,
plugin_transaction_validate_all(clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
@ -732,14 +736,14 @@ plugin_transaction_validate_all(clicon_handle h,
* @retval -1 Error
*/
int
plugin_transaction_complete_one(clixon_plugin_t *cp,
clicon_handle h,
plugin_transaction_complete_one(clixon_plugin_t *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_trans_complete) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -748,7 +752,7 @@ plugin_transaction_complete_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
}
@ -762,7 +766,7 @@ plugin_transaction_complete_one(clixon_plugin_t *cp,
/*! Call transaction_complete() in all plugins after validation (before commit)
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
@ -770,7 +774,7 @@ plugin_transaction_complete_one(clixon_plugin_t *cp,
* @note Rename to transaction_complete?
*/
int
plugin_transaction_complete_all(clicon_handle h,
plugin_transaction_complete_all(clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
@ -796,21 +800,21 @@ plugin_transaction_complete_all(clicon_handle h,
* plugin 2, then the revert will be made in plugins 1 and 0.
*/
static int
plugin_transaction_revert_all(clicon_handle h,
plugin_transaction_revert_all(clicon_handle h,
transaction_data_t *td,
int nr)
{
int retval = 0;
clixon_plugin_t *cp = NULL;
trans_cb_t *fn;
while ((cp = clixon_plugin_each_revert(h, cp, nr)) != NULL) {
if ((fn = clixon_plugin_api_get(cp)->ca_trans_revert) == NULL)
continue;
if ((retval = fn(h, (transaction_data)td)) < 0){
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_revert callback failed",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_revert callback failed",
__FUNCTION__, clixon_plugin_name_get(cp));
break;
break;
}
}
return retval; /* ignore errors */
@ -827,13 +831,13 @@ plugin_transaction_revert_all(clicon_handle h,
*/
int
plugin_transaction_commit_one(clixon_plugin_t *cp,
clicon_handle h,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -842,7 +846,7 @@ plugin_transaction_commit_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
}
@ -856,7 +860,7 @@ plugin_transaction_commit_one(clixon_plugin_t *cp,
/*! Call transaction_commit callbacks in all backend plugins
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
@ -865,18 +869,18 @@ plugin_transaction_commit_one(clixon_plugin_t *cp,
* and in reverse order.
*/
int
plugin_transaction_commit_all(clicon_handle h,
plugin_transaction_commit_all(clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
int i=0;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
i++;
if (plugin_transaction_commit_one(cp, h, td) < 0){
/* Make an effort to revert transaction */
plugin_transaction_revert_all(h, td, i-1);
plugin_transaction_revert_all(h, td, i-1);
goto done;
}
}
@ -894,14 +898,14 @@ plugin_transaction_commit_all(clicon_handle h,
* @retval -1 Error
*/
int
plugin_transaction_commit_done_one(clixon_plugin_t *cp,
clicon_handle h,
plugin_transaction_commit_done_one(clixon_plugin_t *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit_done) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -910,7 +914,7 @@ plugin_transaction_commit_done_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
}
@ -924,14 +928,14 @@ plugin_transaction_commit_done_one(clixon_plugin_t *cp,
/*! Call transaction_commit_done callbacks in all backend plugins
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error: one of the plugin callbacks returned error
* @note no revert is done
*/
int
plugin_transaction_commit_done_all(clicon_handle h,
plugin_transaction_commit_done_all(clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
@ -955,14 +959,14 @@ plugin_transaction_commit_done_all(clicon_handle h,
* @retval -1 Error
*/
int
plugin_transaction_end_one(clixon_plugin_t *cp,
clicon_handle h,
plugin_transaction_end_one(clixon_plugin_t *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_trans_end) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -971,7 +975,7 @@ plugin_transaction_end_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
}
@ -985,7 +989,7 @@ plugin_transaction_end_one(clixon_plugin_t *cp,
/*! Call transaction_end() in all plugins after a successful commit.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error
@ -997,7 +1001,7 @@ plugin_transaction_end_all(clicon_handle h,
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (plugin_transaction_end_one(cp, h, td) < 0)
goto done;
@ -1008,14 +1012,14 @@ plugin_transaction_end_all(clicon_handle h,
}
int
plugin_transaction_abort_one(clixon_plugin_t *cp,
clicon_handle h,
plugin_transaction_abort_one(clixon_plugin_t *cp,
clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
trans_cb_t *fn;
void *wh = NULL;
if ((fn = clixon_plugin_api_get(cp)->ca_trans_abort) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
@ -1024,7 +1028,7 @@ plugin_transaction_abort_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, clixon_plugin_name_get(cp), __FUNCTION__) < 0)
goto done;
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error",
__FUNCTION__, clixon_plugin_name_get(cp));
goto done;
}
@ -1038,19 +1042,19 @@ plugin_transaction_abort_one(clixon_plugin_t *cp,
/*! Call transaction_abort() in all plugins after a failed validation/commit.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] td Transaction data
* @retval 0 OK
* @retval -1 Error
*/
int
plugin_transaction_abort_all(clicon_handle h,
plugin_transaction_abort_all(clicon_handle h,
transaction_data_t *td)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (plugin_transaction_abort_one(cp, h, td) < 0)
; /* dont abort on error */

View file

@ -70,6 +70,8 @@
* is started.
* @param[in] h Clixon backend
* @param[in] xt XML target
* @retval 0 OK
* @retval -1 Error
*/
static int
restconf_pseudo_set_log(clicon_handle h,
@ -78,8 +80,8 @@ restconf_pseudo_set_log(clicon_handle h,
int retval = -1;
char **argv;
int argc;
int i;
char *log = NULL;
int i;
char *log = NULL;
char *dbg = NULL;
cxobj *xb;
@ -138,6 +140,8 @@ restconf_pseudo_set_log(clicon_handle h,
* and insert it as a optimization to reading it from the backend.
* @param[in] h Clixon backend
* @param[in] xt XML target
* @retval 0 OK
* @retval -1 Error
*/
static int
restconf_pseudo_set_inline(clicon_handle h,
@ -146,11 +150,11 @@ restconf_pseudo_set_inline(clicon_handle h,
int retval = -1;
char **argv;
int argc;
int i;
int i;
cxobj *xrestconf;
cbuf *cb = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_process_argv_get(h, RESTCONF_PROCESS, &argv, &argc) < 0)
goto done;
if ((xrestconf = xpath_first(xt, NULL, "restconf")) != NULL)
@ -170,7 +174,7 @@ restconf_pseudo_set_inline(clicon_handle h,
clicon_err(OE_XML, errno, "stdup");
goto done;
}
clicon_debug(1, "%s str:%s", __FUNCTION__, str);
clixon_debug(CLIXON_DBG_DEFAULT, "%s str:%s", __FUNCTION__, str);
if (argv[i+1])
free(argv[i+1]);
argv[i+1] = str;
@ -186,6 +190,7 @@ restconf_pseudo_set_inline(clicon_handle h,
}
/*! Process rpc callback function
*
* - if RPC op is start, if enable is true, start the service, if false, error or ignore it
* - if RPC op is stop, stop the service
* These rules give that if RPC op is start and enable is false -> change op to none
@ -197,14 +202,14 @@ restconf_rpc_wrapper(clicon_handle h,
{
int retval = -1;
cxobj *xt = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
switch (*operation){
case PROC_OP_STOP:
/* if RPC op is stop, stop the service */
break;
case PROC_OP_START:
/* RPC op is start & enable is true, then start the service,
/* RPC op is start & enable is true, then start the service,
& enable is false, error or ignore it */
if (xmldb_get(h, "running", NULL, "/restconf", &xt) < 0)
goto done;
@ -235,7 +240,8 @@ restconf_rpc_wrapper(clicon_handle h,
}
/*! Enable process-control of restconf daemon, ie start/stop restconf by registering restconf process
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @note Could also look in clixon-restconf and start process if enable is true, but that needs to
* be in start callback using a pseudo plugin.
* - Debug flag inheritance only works if backend is started with debug. If debug is set later
@ -277,24 +283,24 @@ restconf_pseudo_process_control(clicon_handle h)
cprintf(cb, "%s/clixon_restconf", dir0);
pgm = cbuf_get(cb);
if (stat(pgm, &fstat) == 0){ /* Sanity check: program exists */
clicon_debug(1, "Found %s", pgm);
clixon_debug(CLIXON_DBG_DEFAULT, "Found %s", pgm);
found++;
}
else
clicon_debug(1, "Not found: %s", pgm);
clixon_debug(CLIXON_DBG_DEFAULT, "Not found: %s", pgm);
}
if (!found &&
(dir1 = CLIXON_CONFIG_SBINDIR) != NULL){
cbuf_reset(cb);
cprintf(cb, "%s/clixon_restconf", dir1);
pgm = cbuf_get(cb);
clicon_debug(1, "Looking for %s", pgm);
clixon_debug(CLIXON_DBG_DEFAULT, "Looking for %s", pgm);
if (stat(pgm, &fstat) == 0){ /* Sanity check: program exists */
clicon_debug(1, "Found %s", pgm);
clixon_debug(CLIXON_DBG_DEFAULT, "Found %s", pgm);
found++;
}
else
clicon_debug(1, "Not found: %s", pgm);
clixon_debug(CLIXON_DBG_DEFAULT, "Not found: %s", pgm);
}
if (!found){
clicon_err(OE_RESTCONF, 0, "clixon_restconf not found in neither CLICON_RESTCONF_INSTALLDIR(%s) nor CLIXON_CONFIG_SBINDIR(%s). Try overriding with CLICON_RESTCONF_INSTALLDIR",
@ -343,7 +349,7 @@ restconf_pseudo_process_validate(clicon_handle h,
int retval = -1;
cxobj *xtarget;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
xtarget = transaction_target(td);
/* If ssl-enable is true and (at least a) socket has ssl,
* then server-cert-path and server-key-path must exist */
@ -374,8 +380,8 @@ restconf_pseudo_process_commit(clicon_handle h,
cxobj *xsource;
cxobj *cx;
int enabled = 0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
xtarget = transaction_target(td);
xsource = transaction_src(td);
if (xpath_first(xtarget, NULL, "/restconf[enable='true']") != NULL)
@ -425,13 +431,16 @@ restconf_pseudo_process_commit(clicon_handle h,
}
/*! Register start/stop restconf RPC and create pseudo-plugin to monitor enable flag
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
int
backend_plugin_restconf_register(clicon_handle h,
yang_stmt *yspec)
{
int retval = -1;
int retval = -1;
clixon_plugin_t *cp = NULL;
if (clixon_pseudo_plugin(h, "restconf pseudo plugin", &cp) < 0)

View file

@ -78,7 +78,7 @@
/*! Open an INET stream socket and bind it to a file descriptor
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] dst IPv4 address (see inet_pton(3))
* @retval s Socket file descriptor (see socket(2))
* @retval -1 Error
@ -111,7 +111,7 @@ config_socket_init_ipv4(clicon_handle h,
clicon_err(OE_UNIX, errno, "bind");
goto err;
}
clicon_debug(1, "Listen on server socket at %s:%hu", dst, port);
clixon_debug(CLIXON_DBG_DEFAULT, "Listen on server socket at %s:%hu", dst, port);
if (listen(s, 5) < 0){
clicon_err(OE_UNIX, errno, "listen");
goto err;
@ -126,7 +126,7 @@ config_socket_init_ipv4(clicon_handle h,
*
* The socket is accessed via CLICON_SOCK option, has 770 permissions
* and group according to CLICON_SOCK_GROUP option.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] sock Unix file-system path
* @retval s Socket file descriptor (see socket(2))
* @retval -1 Error
@ -154,7 +154,7 @@ config_socket_init_unix(clicon_handle h,
if (group_name2gid(config_group, &gid) < 0)
return -1;
#if 0
if (gid == 0)
if (gid == 0)
clicon_log(LOG_WARNING, "%s: No such group: %s", __FUNCTION__, config_group);
#endif
/* create unix socket */
@ -169,16 +169,16 @@ config_socket_init_unix(clicon_handle h,
old_mask = umask(S_IRWXO | S_IXGRP | S_IXUSR);
if (bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
clicon_err(OE_UNIX, errno, "bind");
umask(old_mask);
umask(old_mask);
goto err;
}
umask(old_mask);
umask(old_mask);
/* change socket path file group */
if (lchown(sock, -1, gid) < 0){
clicon_err(OE_UNIX, errno, "lchown(%s, %s)", sock, config_group);
goto err;
}
clicon_debug(1, "Listen on server socket at %s", addr.sun_path);
clixon_debug(CLIXON_DBG_DEFAULT, "Listen on server socket at %s", addr.sun_path);
if (listen(s, 5) < 0){
clicon_err(OE_UNIX, errno, "listen");
goto err;
@ -190,8 +190,8 @@ config_socket_init_unix(clicon_handle h,
}
/*! Open backend socket, the one clients send requests to, either ip or unix
*
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval s Socket file descriptor (see socket(2))
* @retval -1 Error
*/
@ -220,12 +220,15 @@ backend_socket_init(clicon_handle h)
}
/*! Accept new socket client
*
* @param[in] fd Socket (unix or ip)
* @param[in] arg typecast clicon_handle
* @retval 0 OK
* @retval -1 Error
*/
int
backend_accept_client(int fd,
void *arg)
void *arg)
{
int retval = -1;
clicon_handle h = (clicon_handle)arg;
@ -242,7 +245,7 @@ backend_accept_client(int fd,
uid_t guid;
#endif
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
len = sizeof(from);
if ((s = accept(fd, &from, &len)) < 0){
clicon_err(OE_UNIX, errno, "accept");
@ -251,7 +254,7 @@ backend_accept_client(int fd,
if ((ce = backend_client_add(h, &from)) == NULL)
goto done;
/*
/*
* Get credentials of connected peer - only for unix socket
*/
switch (from.sa_family){
@ -281,7 +284,7 @@ backend_accept_client(int fd,
name = NULL;
}
break;
case AF_INET:
case AF_INET:
break;
case AF_INET6:
default:

View file

@ -41,7 +41,7 @@
/*
* Prototypes
*/
*/
int backend_socket_init(clicon_handle h);
int backend_accept_client(int fd, void *arg);

View file

@ -85,7 +85,7 @@ db_merge(clicon_handle h,
{
int retval = -1;
cxobj *xt = NULL;
/* Get data as xml from db1 */
if (xmldb_get0(h, (char*)db1, YB_MODULE, NULL, NULL, 1, WITHDEFAULTS_EXPLICIT, &xt, NULL, NULL) < 0)
goto done;
@ -138,7 +138,7 @@ startup_mode_startup(clicon_handle h,
int ret = 0;
int rollback_exists;
yang_stmt *yspec = clicon_dbspec_yang(h);
if (strcmp(db, "running")==0){
clicon_err(OE_FATAL, 0, "Invalid startup db: %s", db);
goto done;
@ -273,8 +273,6 @@ load_extraxml(clicon_handle h,
* @retval 1 OK
* @retval 0 Validation failed
* @retval -1 Error
running -----------------+----+------>
reset loadfile / merge
@ -289,14 +287,14 @@ startup_extraxml(clicon_handle h,
int retval = -1;
char *tmp_db = "tmp";
int ret;
cxobj *xt0 = NULL;
cxobj *xt = NULL;
cxobj *xt0 = NULL;
cxobj *xt = NULL;
/* Clear tmp db */
if (xmldb_db_reset(h, tmp_db) < 0)
goto done;
/* Application may define extra xml in its reset function */
if (clixon_plugin_reset_all(h, tmp_db) < 0)
if (clixon_plugin_reset_all(h, tmp_db) < 0)
goto done;
/* Extra XML can also be added via file */
if (file){
@ -306,7 +304,7 @@ startup_extraxml(clicon_handle h,
if (ret == 0)
goto fail;
}
/*
/*
* Check if tmp db is empty.
* It should be empty if extra-xml is null and reset plugins did nothing
* then skip validation.
@ -325,7 +323,7 @@ startup_extraxml(clicon_handle h,
goto done;
if (ret == 0)
goto fail;
if (xt==NULL || xml_child_nr(xt)==0)
if (xt==NULL || xml_child_nr(xt)==0)
goto ok;
/* Merge tmp into running (no commit) */
if ((ret = db_merge(h, tmp_db, "running", cbret)) < 0)
@ -338,7 +336,7 @@ startup_extraxml(clicon_handle h,
if (xt0)
xml_free(xt0);
xmldb_get0_free(h, &xt);
if (xmldb_delete(h, tmp_db) != 0 && errno != ENOENT)
if (xmldb_delete(h, tmp_db) != 0 && errno != ENOENT)
return -1;
return retval;
fail:
@ -360,10 +358,10 @@ startup_module_state(clicon_handle h,
int retval = -1;
cxobj *x = NULL;
int ret;
if (!clicon_option_bool(h, "CLICON_XMLDB_MODSTATE"))
goto ok;
/* Set up cache
/* Set up cache
* Now, access brief module cache with clicon_modst_cache_get(h, 1) */
if ((ret = yang_modules_state_get(h, yspec, NULL, NULL, 1, &x)) < 0)
goto done;

View file

@ -41,7 +41,7 @@
/*
* Prototypes
*/
*/
int startup_mode_startup(clicon_handle h, char *db, cbuf *cbret);
int startup_extraxml(clicon_handle h, char *file, cbuf *cbret);
int startup_module_state(clicon_handle h, yang_stmt *yspec);

View file

@ -78,6 +78,7 @@
* entries in the struct below.
*/
/*! Backend specific handle added to header CLICON handle
*
* This file should only contain access functions for the _specific_
* entries in the struct below.
* @note The top part must be equivalent to struct clicon_handle in clixon_handle.c
@ -89,7 +90,7 @@ struct backend_handle {
clicon_hash_t *bh_data; /* internal clicon data (HDR) */
clicon_hash_t *ch_db_elmnt; /* xml datastore element cache data */
event_stream_t *bh_stream; /* notification streams, see clixon_stream.[ch] */
/* ------ end of common handle ------ */
struct client_entry *bh_ce_list; /* The client list */
int bh_ce_nr; /* Number of clients, just increment */
@ -104,7 +105,8 @@ backend_handle_init(void)
}
/*! Deallocates a backend handle, including all client structs
* @Note: handle 'h' cannot be used in calls after this
*
* @note: handle 'h' cannot be used in calls after this
* @see backend_client_rm
*/
int
@ -125,13 +127,14 @@ backend_handle_exit(clicon_handle h)
}
/*! Add new client, typically frontend such as cli, netconf, restconf
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] addr Address of client
* @retval ce Client entry
* @retval NULL Error
*/
struct client_entry *
backend_client_add(clicon_handle h,
backend_client_add(clicon_handle h,
struct sockaddr *addr)
{
struct backend_handle *bh = handle(h);
@ -158,7 +161,8 @@ backend_client_add(clicon_handle h,
}
/*! Return client list
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval ce_list Client entry list (all sessions)
*/
struct client_entry *
@ -170,7 +174,8 @@ backend_client_list(clicon_handle h)
}
/*! Actually remove client from client list
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] ce Client handle
* @see backend_client_rm which is more high-level
*/
@ -201,7 +206,8 @@ backend_client_delete(clicon_handle h,
}
/*! Debug print backend clients
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] f UNIX output stream
*/
int

View file

@ -43,6 +43,7 @@
*/
/*! Transaction data describing a system transition from a src to target state
*
* Clixon internal, presented as void* to app's callback in the 'transaction_data'
* type in clicon_backend_api.h
* The struct contains source and target XML tree (e.g. candidate/running)
@ -68,6 +69,7 @@ typedef struct {
} transaction_data_t;
/*! Pagination userdata
*
* Pagination can use a lock/transaction mechanism
* If locking is not used, the plugin cannot expect more pagination calls, and no state or
* caching should be used
@ -104,7 +106,7 @@ int clixon_plugin_lockdb_all(clicon_handle h, char *db, int lock, int id);
int clixon_pagination_cb_register(clicon_handle h, handler_function fn, char *path, void *arg);
int clixon_pagination_cb_call(clicon_handle h, char *xpath, int locked,
uint32_t offset, uint32_t limit,
uint32_t offset, uint32_t limit,
cxobj *xstate);
int clixon_pagination_free(clicon_handle h);

View file

@ -69,6 +69,7 @@
* would give running in source and 'a' and candidate in 'target'.
*/
/*! Get transaction id
*
* @param[in] td transaction_data
* @retval id transaction id
*/
@ -79,6 +80,7 @@ transaction_id(transaction_data td)
}
/*! Get plugin/application specific callback argument
*
* @param[in] td transaction_data
* @retval arg callback argument
*/
@ -89,6 +91,7 @@ transaction_arg(transaction_data td)
}
/*! Set plugin/application specific callback argument
*
* @param[in] td transaction_data
* @param[in] arg callback argument
*/
@ -101,6 +104,7 @@ transaction_arg_set(transaction_data td,
}
/*! Get source database xml tree
*
* @param[in] td transaction_data
* @retval src source xml tree containing original state
*/
@ -111,6 +115,7 @@ transaction_src(transaction_data td)
}
/*! Get target database xml tree
*
* @param[in] td transaction_data
* @retval xml target xml tree containing wanted state
*/
@ -121,6 +126,7 @@ transaction_target(transaction_data td)
}
/*! Get delete xml vector, ie vector of xml nodes that are deleted src->target
*
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
*/
@ -131,6 +137,7 @@ transaction_dvec(transaction_data td)
}
/*! Get length of delete xml vector
*
* @param[in] td transaction_data
* @retval len Length of vector of xml nodes
* @see transaction_dvec
@ -142,6 +149,7 @@ transaction_dlen(transaction_data td)
}
/*! Get add xml vector, ie vector of xml nodes that are added src->target
*
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
*/
@ -152,6 +160,7 @@ transaction_avec(transaction_data td)
}
/*! Get length of add xml vector
*
* @param[in] td transaction_data
* @retval len Length of vector of xml nodes
* @see transaction_avec
@ -163,6 +172,7 @@ transaction_alen(transaction_data td)
}
/*! Get source changed xml vector, ie vector of xml nodes that changed
*
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
* These are only nodes of type LEAF.
@ -177,6 +187,7 @@ transaction_scvec(transaction_data td)
}
/*! Get target changed xml vector, ie vector of xml nodes that changed
*
* @param[in] td transaction_data
* @retval vec Vector of xml nodes
* These are only nodes of type LEAF.
@ -191,6 +202,7 @@ transaction_tcvec(transaction_data td)
}
/*! Get length of changed xml vector
*
* @param[in] td transaction_data
* @retval len Length of vector of xml nodes
* This is the length of both the src change vector and the target change vector
@ -211,8 +223,8 @@ int
transaction_print(FILE *f,
transaction_data th)
{
cxobj *xn;
int i;
cxobj *xn;
int i;
transaction_data_t *td;
td = (transaction_data_t *)th;
@ -267,7 +279,7 @@ transaction_dbg(clicon_handle h,
goto done;
}
if (i)
clicon_debug(dbglevel, "%s %" PRIu64 " %s del: %s",
clixon_debug(dbglevel, "%s %" PRIu64 " %s del: %s",
__FUNCTION__, td->td_id, msg, cbuf_get(cb));
cbuf_reset(cb);
for (i=0; i<td->td_alen; i++){
@ -276,7 +288,7 @@ transaction_dbg(clicon_handle h,
goto done;
}
if (i)
clicon_debug(dbglevel, "%s %" PRIu64 " %s add: %s",
clixon_debug(dbglevel, "%s %" PRIu64 " %s add: %s",
__FUNCTION__, td->td_id, msg, cbuf_get(cb));
cbuf_reset(cb);
for (i=0; i<td->td_clen; i++){
@ -290,7 +302,7 @@ transaction_dbg(clicon_handle h,
goto done;
}
if (i)
clicon_debug(dbglevel, "%s %" PRIu64 " %s change: %s",
clixon_debug(dbglevel, "%s %" PRIu64 " %s change: %s",
__FUNCTION__, td->td_id, msg, cbuf_get(cb));
done:
if (cb)
@ -299,7 +311,6 @@ transaction_dbg(clicon_handle h,
}
/*! Log a transaction
*
*/
int
transaction_log(clicon_handle h,

View file

@ -69,9 +69,9 @@ int transaction_log(clicon_handle h, transaction_data th, int level, const char
/* Pagination callbacks
* @see pagination_data_t internal structure
*/
uint32_t pagination_offset(pagination_data pd);
uint32_t pagination_limit(pagination_data pd);
int pagination_locked(pagination_data pd);
cxobj *pagination_xstate(pagination_data pd);
uint32_t pagination_offset(pagination_data pd);
uint32_t pagination_limit(pagination_data pd);
int pagination_locked(pagination_data pd);
cxobj *pagination_xstate(pagination_data pd);
#endif /* _CLIXON_BACKEND_TRANSACTION_H_ */

View file

@ -86,7 +86,7 @@ co2apipath(cg_obj *co)
cg_callback *cb;
cvec *cvv;
cg_var *cv;
if (co == NULL)
return NULL;
if ((cb = co->co_callbacks) == NULL)
@ -121,7 +121,7 @@ cli_auto_edit(clicon_handle h,
char *api_path_fmt; /* xml key format */
char *api_path = NULL;
char *treename;
pt_head *ph;
pt_head *ph;
cg_obj *co;
cg_obj *coorig;
cvec *cvv2 = NULL; /* cvv2 = cvv0 + cvv1 */
@ -137,7 +137,7 @@ cli_auto_edit(clicon_handle h,
str = cv_string_get(cvec_i(argv, argc++));
if (str && strncmp(str, "mtpoint:", strlen("mtpoint:")) == 0){
mtpoint = str + strlen("mtpoint:");
clicon_debug(1, "%s mtpoint:%s", __FUNCTION__, mtpoint);
clixon_debug(CLIXON_DBG_DEFAULT, "%s mtpoint:%s", __FUNCTION__, mtpoint);
treename = cv_string_get(cvec_i(argv, argc++));
}
else
@ -181,7 +181,7 @@ cli_auto_edit(clicon_handle h,
char *mtpoint2;
if ((mtpoint2 = strdup(mtpoint)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
goto done;
}
if (clicon_data_set(h, "cli-edit-mtpoint", mtpoint2) < 0)
goto done;
@ -205,9 +205,12 @@ cli_auto_edit(clicon_handle h,
}
/*! CLI callback: Working point tree up to parent
*
* @param[in] h CLICON handle
* @param[in] cvv Vector of variables from CLIgen command-line
* @param[in] argv Vector of user-supplied keywords
* @retval 0 OK
* @retval -1 Error
* Format of argv:
* <treename> Name of generated cligen parse-tree, eg "datamodel"
*/
@ -231,7 +234,7 @@ cli_auto_up(clicon_handle h,
int j;
size_t len;
cvec *cvv_filter = NULL;
if (cvec_len(argv) != 1){
clicon_err(OE_PLUGIN, EINVAL, "Usage: %s(<treename>)", __FUNCTION__);
goto done;
@ -283,7 +286,7 @@ cli_auto_up(clicon_handle h,
cvv1 = cvec_new(0);
for (i=0; i<cvec_len(cvv0)-j; i++){
cv = cvec_i(cvv0, i);
cvec_append_var(cvv1, cv);
cvec_append_var(cvv1, cv);
}
/* get api-path and xpath */
if (api_path_fmt2api_path(api_path_fmt1, cvv1, &api_path, NULL) < 0)
@ -300,9 +303,12 @@ cli_auto_up(clicon_handle h,
}
/*! CLI callback: Working point tree reset to top level
*
* @param[in] h CLICON handle
* @param[in] cvv Vector of variables from CLIgen command-line
* @param[in] argv Vector of user-supplied keywords
* @retval 0 OK
* @retval -1 Error
* Format of argv:
* <treename> Name of generated cligen parse-tree, eg "datamodel"
*/
@ -315,7 +321,7 @@ cli_auto_top(clicon_handle h,
cg_var *cv;
char *treename;
pt_head *ph;
cv = cvec_i(argv, 0);
treename = cv_string_get(cv);
if ((ph = cligen_ph_find(cli_cligen(h), treename)) == NULL){
@ -333,20 +339,23 @@ cli_auto_top(clicon_handle h,
}
/*! CLI callback: set auto db item
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
* @retval 0 OK
* @retval -1 Error
* Format of argv:
* <api-path-fmt> Generated
*/
int
int
cli_auto_set(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
cvec *cvv2 = NULL;
cvv2 = cvec_append(clicon_data_cvec_get(h, "cli-edit-cvv"), cvv);
if (cli_dbxml(h, cvv2, argv, OP_REPLACE, NULL) < 0)
goto done;
@ -358,18 +367,21 @@ cli_auto_set(clicon_handle h,
}
/*! Merge datastore xml entry
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
* @retval 0 OK
* @retval -1 Error
*/
int
int
cli_auto_merge(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
cvec *cvv2 = NULL;
cvv2 = cvec_append(clicon_data_cvec_get(h, "cli-edit-cvv"), cvv);
if (cli_dbxml(h, cvv2, argv, OP_MERGE, NULL) < 0)
goto done;
@ -381,18 +393,21 @@ cli_auto_merge(clicon_handle h,
}
/*! Create datastore xml entry
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
* @retval 0 OK
* @retval -1 Error
*/
int
int
cli_auto_create(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
int retval = -1;
cvec *cvv2 = NULL;
cvv2 = cvec_append(clicon_data_cvec_get(h, "cli-edit-cvv"), cvv);
if (cli_dbxml(h, cvv2, argv, OP_CREATE, NULL) < 0)
goto done;
@ -404,18 +419,21 @@ cli_auto_create(clicon_handle h,
}
/*! Delete datastore xml
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
* @retval 0 OK
* @retval -1 Error
*/
int
int
cli_auto_del(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
cvec *cvv2 = NULL;
cvv2 = cvec_append(clicon_data_cvec_get(h, "cli-edit-cvv"), cvv);
if (cli_dbxml(h, cvv2, argv, OP_REMOVE, NULL) < 0)
goto done;
@ -438,7 +456,6 @@ struct findpt_arg{
* @param[in] arg Argument, cast to application-specific info
* @retval 1 OK and return (abort iteration)
* @retval 0 OK and continue
* @retval -1 Error: break and return
*/
static int
cli_auto_findpt(cg_obj *co,
@ -456,9 +473,12 @@ cli_auto_findpt(cg_obj *co,
}
/*! Enter edit mode
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv Vector of args to function in command.
* @retval 0 OK
* @retval -1 Error
* Format of argv:
* <api_path_fmt> Generated API PATH FORMAT (print-like for variables)
* <vars>* List of static variables that can be used as values for api_path_fmt
@ -471,7 +491,7 @@ cli_auto_findpt(cg_obj *co,
* api_path: /a/b=42,99/c
* @see cli_auto_edit
*/
int
int
cli_auto_sub_enter(clicon_handle h,
cvec *cvv,
cvec *argv)
@ -486,7 +506,7 @@ cli_auto_sub_enter(clicon_handle h,
cg_var *cv = NULL;
pt_head *ph;
struct findpt_arg fa = {0,};
if (cvec_len(argv) < 2){
clicon_err(OE_PLUGIN, EINVAL, "Usage: %s(<tree> <api_path_fmt> (,vars)*)", __FUNCTION__);
goto done;
@ -506,7 +526,7 @@ cli_auto_sub_enter(clicon_handle h,
* argv, but this can be done differently
*/
/* Create a cvv with variables to add to api-path */
if ((cvv1 = cvec_new(0)) == NULL){
if ((cvv1 = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}

View file

@ -106,8 +106,8 @@ autocli_listkw_int2str(int listkw)
* @param[in] h Clixon handle
* @param[in] modname Name of YANG module, or NULL for ANY module (eg default)
* @param[out] enablep Include this module in autocli
* @retval -1 Error
* @retval 0 OK, and enablep set
* @retval -1 Error
*/
int
autocli_module(clicon_handle h,
@ -171,7 +171,7 @@ autocli_module(clicon_handle h,
}
ok:
*enablep = enable;
retval = 0;
retval = 0;
done:
return retval;
}
@ -190,7 +190,7 @@ autocli_compress_extension(yang_stmt *ys,
char *ns = NULL;
int exist = 0;
int ret;
if (nodeid_split(body, &prefix, &id) < 0)
goto done;
if (prefix != NULL){
@ -228,9 +228,8 @@ autocli_compress_extension(yang_stmt *ys,
*
* @param[in] h Clixon handle
* @param[out] compress
* @retval -1 Error
* @retval 0 OK, and compress set
* @retval -1 Error
* Canonical examples:
The config and state containers are "compressed" out of the schema.
+ op=COMPRESS
@ -261,7 +260,7 @@ autocli_compress(clicon_handle h,
char *keywstr;
int match = 0;
char *body;
if (compress == NULL){
clicon_err(OE_YANG, EINVAL, "Argument is NULL");
goto done;
@ -346,8 +345,8 @@ autocli_compress(clicon_handle h,
* Currently only returns list-keyword-default, could be extended to rules
* @param[in] h Clixon handle
* @param[out] completion Completion enabled
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
autocli_completion(clicon_handle h,
@ -359,7 +358,7 @@ autocli_completion(clicon_handle h,
char *reason = NULL;
int ret;
cxobj *xautocli;
if (completion == NULL){
clicon_err(OE_YANG, EINVAL, "Argument is NULL");
goto done;
@ -377,7 +376,7 @@ autocli_completion(clicon_handle h,
goto done;
}
*completion = val;
retval = 0;
retval = 0;
done:
if (reason)
free(reason);
@ -389,8 +388,8 @@ autocli_completion(clicon_handle h,
* When false replaces uses with grouping, when true use tree reference
* @param[in] h Clixon handle
* @param[out] treeref grouping using treerefs enabled
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
autocli_grouping_treeref(clicon_handle h,
@ -402,7 +401,7 @@ autocli_grouping_treeref(clicon_handle h,
char *reason = NULL;
int ret;
cxobj *xautocli;
if (treeref == NULL){
clicon_err(OE_YANG, EINVAL, "Argument is NULL");
goto done;
@ -420,7 +419,7 @@ autocli_grouping_treeref(clicon_handle h,
goto done;
}
*treeref = val;
retval = 0;
retval = 0;
done:
if (reason)
free(reason);
@ -432,8 +431,8 @@ autocli_grouping_treeref(clicon_handle h,
* Currently only returns list-keyword-default, could be extended to rules
* @param[in] h Clixon handle
* @param[out] listkw List keyword setting
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
autocli_list_keyword(clicon_handle h,
@ -442,7 +441,7 @@ autocli_list_keyword(clicon_handle h,
int retval = -1;
char *str;
cxobj *xautocli = NULL;
if (listkw == NULL){
clicon_err(OE_YANG, EINVAL, "Argument is NULL");
goto done;
@ -456,7 +455,7 @@ autocli_list_keyword(clicon_handle h,
goto done;
}
*listkw = autocli_listkw_str2int(str);
retval = 0;
retval = 0;
done:
return retval;
}
@ -465,8 +464,8 @@ autocli_list_keyword(clicon_handle h,
*
* @param[in] h Clixon handle
* @param[out] treeref_state If true, generate CLI from state
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
autocli_treeref_state(clicon_handle h,
@ -478,7 +477,7 @@ autocli_treeref_state(clicon_handle h,
char *reason = NULL;
int ret;
cxobj *xautocli;
if (treeref_state == NULL){
clicon_err(OE_YANG, EINVAL, "Argument is NULL");
goto done;
@ -496,7 +495,7 @@ autocli_treeref_state(clicon_handle h,
goto done;
}
*treeref_state = val;
retval = 0;
retval = 0;
done:
if (reason)
free(reason);
@ -508,8 +507,8 @@ autocli_treeref_state(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] keyw YANG keyword
* @param[out] flag If 0 keyw is not a part of default edit-mode, if 1 it is.
* @retval -1 Error
* @retval 0 OK, see result in keyw
* @retval -1 Error
* @note keyw is a sub/superset of RFC 6020, see clixon-autocli.yang on which are defined
*/
int
@ -524,7 +523,7 @@ autocli_edit_mode(clicon_handle h,
int nvec;
char *v;
int i;
if (flag == NULL){
clicon_err(OE_YANG, EINVAL, "Argument is NULL");
goto done;
@ -547,7 +546,7 @@ autocli_edit_mode(clicon_handle h,
break;
}
}
retval = 0;
retval = 0;
done:
if (vec)
free(vec);

File diff suppressed because it is too large Load diff

View file

@ -122,8 +122,8 @@ You can see which CLISPEC it generates via clixon_cli -D 2:
* @note XXX only fraction_digits handled,should also have mincv, maxcv, pattern
*/
static int
cli_expand_var_generate(clicon_handle h,
yang_stmt *ys,
cli_expand_var_generate(clicon_handle h,
yang_stmt *ys,
const char *cvtypestr,
int options,
uint8_t fraction_digits,
@ -135,12 +135,12 @@ cli_expand_var_generate(clicon_handle h,
int extvalue = 0;
yang_stmt *yspec;
cg_var *cv = NULL;
if ((yspec = ys_spec(ys)) != NULL)
cv = yang_cv_get(yspec);
if (yang_extension_value(ys, "hide", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0)
goto done;
if (extvalue || yang_find(ys, Y_STATUS, "deprecated") != NULL)
if (extvalue || yang_find(ys, Y_STATUS, "deprecated") != NULL)
goto hide;
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
goto done;
@ -167,15 +167,18 @@ cli_expand_var_generate(clicon_handle h,
}
/*! Create callback with api_path format string as argument
*
* @param[in] h Clixon handle
* @param[in] ys yang_stmt of the node at hand
* @param[out] cb The string where the result format string is inserted.
* @retval 0 OK
* @retval -1 Error
* @see cli_dbxml This is where the xmlkeyfmt string is used
* @see pt_callback_reference in CLIgen where the actual callback overwrites the template
*/
static int
cli_callback_generate(clicon_handle h,
yang_stmt *ys,
cli_callback_generate(clicon_handle h,
yang_stmt *ys,
cbuf *cb)
{
int retval = -1;
@ -200,6 +203,7 @@ cli_callback_generate(clicon_handle h,
}
/*! Print cligen help string as ("<helpstring>")
*
* @param[in] cb CLIgen buf holding generated CLIspec
* @param[in] helptext Help text
*/
@ -243,10 +247,13 @@ yang2cli_print_alias(cbuf *cb,
}
/*! Generate identityref statements for CLI variables
*
* @param[in] ys Yang statement
* @param[in] ytype Resolved yang type.
* @param[in] helptext CLI help text
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
* @see yang2cli_var_sub Its sub-function
*/
static int
@ -267,7 +274,7 @@ yang2cli_var_identityref(yang_stmt *ys,
yang_stmt *ymod;
yang_stmt *yprefix;
yang_stmt *yspec;
if ((ybaseref = yang_find(ytype, Y_BASE, NULL)) == NULL)
goto ok;
if ((ybaseid = yang_find_identity(ytype, yang_argument_get(ybaseref))) == NULL)
@ -316,10 +323,13 @@ yang2cli_var_identityref(yang_stmt *ys,
}
/*! Generate range check statements for CLI variables
*
* @param[in] ys Yang statement
* @param[in] options Flags field of optional values, eg YANG_OPTIONS_RANGE
* @param[in] cvv Cvec with array of range_min/range_max cv:s (if YANG_OPTIONS_RANGE is set in options)
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
* @see yang2cli_var_sub which is the main function
* In yang ranges are given as range 1 or range 1 .. 16, encoded in a cvv
* 0 : range_min = x
@ -349,7 +359,7 @@ yang2cli_var_range(yang_stmt *ys,
int i;
cg_var *cv1; /* lower limit */
cg_var *cv2; /* upper limit */
/* Loop through range_min and range_min..range_max */
i = 0;
while (i<cvec_len(cvv)){
@ -376,9 +386,12 @@ yang2cli_var_range(yang_stmt *ys,
}
/*! Generate CLI code for Yang variable pattern statement
*
* @param[in] h Clixon handle
* @param[in] patterns Cvec of regexp patterns
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
* @see cv_validate_pattern for netconf validate code
* @note for cligen, need to escape " -> \"
*/
@ -387,14 +400,14 @@ yang2cli_var_pattern(clicon_handle h,
cvec *patterns,
cbuf *cb)
{
int retval = -1;
int retval = -1;
enum regexp_mode mode;
cg_var *cvp;
char *pattern;
int invert;
char *posix = NULL;
int i;
cg_var *cvp;
char *pattern;
int invert;
char *posix = NULL;
int i;
mode = clicon_yang_regexp(h);
cvp = NULL; /* Loop over compiled regexps */
while ((cvp = cvec_each(patterns, cvp)) != NULL){
@ -439,6 +452,7 @@ static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
yang_stmt *ytype, char *helptext, cbuf *cb);
/*! Generate CLI code for Yang leaf state ment to CLIgen variable of specific type
*
* Check for completion (of already existent values), ranges (eg range[min:max]) and
* patterns, (eg regexp:"[0.9]*").
* @param[in] h Clixon handle
@ -451,11 +465,13 @@ static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
* @param[in] patterns Cvec of regexp patterns
* @param[in] fraction for decimal64, how many digits after period
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
* @see yang_type_resolve for options and other arguments
*/
static int
yang2cli_var_sub(clicon_handle h,
yang_stmt *ys,
yang_stmt *ys,
yang_stmt *ytype, /* resolved type */
char *helptext,
enum cv_type cvtype,
@ -481,7 +497,6 @@ yang2cli_var_sub(clicon_handle h,
}
type = ytype?yang_argument_get(ytype):NULL;
cvtypestr = cv_type2str(cvtype);
if (type && strcmp(type, "identityref") == 0)
cprintf(cb, "(");
cprintf(cb, "<%s:%s", yang_argument_get(ys), cvtypestr);
@ -533,17 +548,20 @@ yang2cli_var_sub(clicon_handle h,
}
/*! Resolve a single Yang union and generate code
*
* Part of generating CLI code for Yang leaf statement to CLIgen variable
* @param[in] h Clixon handle
* @param[in] ys Yang statement (caller of type)
* @param[in] origtype Name of original type in the call
* @param[in] ytsub Yang type invocation, a sub-type of a resolved union type
* @param[in] cb Buffer where cligen code is written
* @param[in] h Clixon handle
* @param[in] ys Yang statement (caller of type)
* @param[in] origtype Name of original type in the call
* @param[in] ytsub Yang type invocation, a sub-type of a resolved union type
* @param[in] cb Buffer where cligen code is written
* @param[in] helptext CLI help text
* @retval 0 OK
* @retval -1 Error
*/
static int
yang2cli_var_union_one(clicon_handle h,
yang_stmt *ys,
yang_stmt *ys,
char *origtype,
yang_stmt *ytsub,
char *helptext,
@ -581,7 +599,7 @@ yang2cli_var_union_one(clicon_handle h,
else {
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
goto done;
if ((retval = yang2cli_var_sub(h, ys, ytype, helptext, cvtype,
if ((retval = yang2cli_var_sub(h, ys, ytype, helptext, cvtype,
options, cvv, patterns, fraction_digits, cb)) < 0)
goto done;
}
@ -593,17 +611,20 @@ yang2cli_var_union_one(clicon_handle h,
}
/*! Loop over all sub-types of a Yang union
*
* Part of generating CLI code for Yang leaf statement to CLIgen variable
* @param[in] h Clixon handle
* @param[in] ys Yang statement (caller)
* @param[in] h Clixon handle
* @param[in] ys Yang statement (caller)
* @param[in] origtype Name of original type in the call
* @param[in] ytype Yang resolved type (a union in this case)
* @param[in] helptext CLI help text
* @param[out] cb Buffer where cligen code is written
* @param[in] ytype Yang resolved type (a union in this case)
* @param[in] helptext CLI help text
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
*/
static int
yang2cli_var_union(clicon_handle h,
yang_stmt *ys,
yang_stmt *ys,
char *origtype,
yang_stmt *ytype,
char *helptext,
@ -633,7 +654,7 @@ yang2cli_var_union(clicon_handle h,
static int
yang2cli_var_leafref(clicon_handle h,
yang_stmt *ys,
yang_stmt *ys,
yang_stmt *yrestype,
char *helptext,
enum cv_type cvtype,
@ -669,11 +690,11 @@ yang2cli_var_leafref(clicon_handle h,
if (completionp && regular_value)
cprintf(cb, "(");
if (regular_value)
if (yang2cli_var_sub(h, ys, yrestype, helptext, cvtype,
if (yang2cli_var_sub(h, ys, yrestype, helptext, cvtype,
options, cvv, patterns, fraction_digits, cb) < 0)
goto done;
if (completionp){
if ((ret = cli_expand_var_generate(h, ys, cvtypestr,
if ((ret = cli_expand_var_generate(h, ys, cvtypestr,
options, fraction_digits, regular_value,
cb)) < 0)
goto done;
@ -688,11 +709,14 @@ yang2cli_var_leafref(clicon_handle h,
}
/*! Generate CLI code for Yang leaf statement to CLIgen variable
*
* @param[in] h Clixon handle
* @param[in] ys Yang statement of original leaf
* @param[in] yreferred Yang statement of referred node for type (leafref)
* @param[in] helptext CLI help text
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
*
* Make a type lookup and complete a cligen variable expression such as <a:string>.
* One complication is yang union, that needs a recursion since it consists of
@ -707,7 +731,7 @@ yang2cli_var_leafref(clicon_handle h,
static int
yang2cli_var(clicon_handle h,
yang_stmt *ys,
yang_stmt *yreferred,
yang_stmt *yreferred,
char *helptext,
cbuf *cb)
{
@ -723,12 +747,12 @@ yang2cli_var(clicon_handle h,
int options = 0;
int completionp;
int ret;
if ((patterns = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
if (yang_type_get(yreferred, &origtype, &yrestype,
if (yang_type_get(yreferred, &origtype, &yrestype,
&options, &cvv, patterns, NULL, &fraction_digits) < 0)
goto done;
restype = yang_argument_get(yrestype);
@ -739,7 +763,7 @@ yang2cli_var(clicon_handle h,
cvtypestr = cv_type2str(cvtype);
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
if (strcmp(restype, "union") == 0){
if (strcmp(restype, "union") == 0){
/* Union: loop over resolved type's sub-types (can also be recursive unions) */
cprintf(cb, "(");
if (yang2cli_var_union(h, ys, origtype, yrestype, helptext, cb) < 0)
@ -747,7 +771,7 @@ yang2cli_var(clicon_handle h,
if (autocli_completion(h, &completionp) < 0)
goto done;
if (completionp){
if ((ret = cli_expand_var_generate(h, ys, cvtypestr,
if ((ret = cli_expand_var_generate(h, ys, cvtypestr,
options, fraction_digits, 1, cb)) < 0)
goto done;
if (ret == 1)
@ -770,15 +794,15 @@ yang2cli_var(clicon_handle h,
}
if (yang_path_arg(yreferred, path_arg, &yref) < 0)
goto done;
if (yref == NULL){
if (yref == NULL){
/* Give up: use yreferred
*/
if (yang2cli_var_leafref(h, ys, yrestype, helptext, cvtype, options,
if (yang2cli_var_leafref(h, ys, yrestype, helptext, cvtype, options,
cvv, patterns, fraction_digits, cb) < 0)
goto done;
}
else {
if (yreferred == yref){
if (yreferred == yref){
clicon_err(OE_YANG, 0, "Referred YANG node for leafref path %s points to self", path_arg);
goto done;
}
@ -803,26 +827,29 @@ yang2cli_var(clicon_handle h,
}
/*! Generate CLI code for Yang leaf statement
*
* @param[in] h Clixon handle
* @param[in] ys Yang statement
* @param[in] level Indentation level
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not
* @param[in] key_leaf 0: ordinary leaf, 1:prekey, 2: lastkey
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
* Some complexity in callback, key_leaf and extralevel logic.
* If extralevel -> add extra { } level
* + if callbacks add: cb();{}
*/
static int
yang2cli_leaf(clicon_handle h,
yang_stmt *ys,
yang2cli_leaf(clicon_handle h,
yang_stmt *ys,
int level,
int callback,
int key_leaf,
cbuf *cb)
{
yang_stmt *yd; /* description */
int retval = -1;
yang_stmt *yd; /* description */
char *helptext = NULL;
char *s;
autocli_listkw_t listkw;
@ -841,7 +868,7 @@ yang2cli_leaf(clicon_handle h,
}
cprintf(cb, "%*s", level*3, "");
/* Called a second time in yang2cli_var, room for optimization */
if (yang_type_get(ys, NULL, &yrestype,
if (yang_type_get(ys, NULL, &yrestype,
NULL, NULL, NULL, NULL, NULL) < 0)
goto done;
if (key_leaf == 0 && strcmp(yang_argument_get(yrestype), "empty") != 0)
@ -905,27 +932,30 @@ yang2cli_leaf(clicon_handle h,
}
/*! Generate CLI code for Yang container statement
*
* @param[in] h Clixon handle
* @param[in] ys Yang statement
* @param[in] level Indentation level
* @param[out] cb Buffer where cligen code is written
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
*/
static int
yang2cli_container(clicon_handle h,
yang_stmt *ys,
yang2cli_container(clicon_handle h,
yang_stmt *ys,
int level,
cbuf *cb)
{
int retval = -1;
yang_stmt *yc;
yang_stmt *yd;
int retval = -1;
char *helptext = NULL;
char *s;
int compress = 0;
yang_stmt *ymod = NULL;
int extvalue = 0;
int ret;
if (ys_real_module(ys, &ymod) < 0)
goto done;
/* If non-presence container && HIDE mode && only child is
@ -964,7 +994,7 @@ yang2cli_container(clicon_handle h,
}
}
yc = NULL;
while ((yc = yn_each(ys, yc)) != NULL)
while ((yc = yn_each(ys, yc)) != NULL)
if (yang2cli_stmt(h, yc, level+1, cb) < 0)
goto done;
if (!compress)
@ -977,24 +1007,27 @@ yang2cli_container(clicon_handle h,
}
/*! Generate CLI code for Yang list statement
*
* @param[in] h Clixon handle
* @param[in] ys Yang statement
* @param[in] level Indentation level
* @param[out] cb Buffer where cligen code is written
* @retval 0 OK
* @retval -1 Error
*/
static int
yang2cli_list(clicon_handle h,
yang_stmt *ys,
yang_stmt *ys,
int level,
cbuf *cb)
{
int retval = -1;
yang_stmt *yc;
yang_stmt *yd;
yang_stmt *yleaf;
cg_var *cvi;
char *keyname;
cvec *cvk = NULL; /* vector of index keys */
int retval = -1;
char *helptext = NULL;
char *s;
int last_key = 0;
@ -1023,7 +1056,7 @@ yang2cli_list(clicon_handle h,
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if ((yleaf = yang_find(ys, Y_LEAF, keyname)) == NULL){
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
yang_argument_get(ys), keyname);
goto done;
}
@ -1066,7 +1099,7 @@ yang2cli_list(clicon_handle h,
}
cprintf(cb, "%*s}\n", level*3, "");
/* Close with } for each key */
while (keynr--)
while (keynr--)
cprintf(cb, "%*s}\n", level*3, "");
retval = 0;
done:
@ -1081,18 +1114,20 @@ yang2cli_list(clicon_handle h,
* @param[in] ys Yang statement
* @param[in] level Indentation level
* @param[out] cb Buffer where cligen code is written
@example
* @retval 0 OK
* @retval -1 Error
* @code
choice interface-type {
container ethernet { ... }
container fddi { ... }
}
@example.end
@Note Removes 'meta-syntax' from cli syntax. They are not shown when xml is
* @code.end
@note Removes 'meta-syntax' from cli syntax. They are not shown when xml is
translated to cli. and therefore input-syntax != output syntax. Which is bad
*/
static int
yang2cli_choice(clicon_handle h,
yang_stmt *ys,
yang2cli_choice(clicon_handle h,
yang_stmt *ys,
int level,
cbuf *cb)
{
@ -1206,6 +1241,7 @@ yang2cli_uses(clicon_handle h,
}
/*! Generate CLI code for Yang statement
*
* @param[in] h Clixon handle
* @param[in] ys Yang statement
* @param[in] level Indentation level
@ -1214,9 +1250,9 @@ yang2cli_uses(clicon_handle h,
* @retval -1 Error
*/
static int
yang2cli_stmt(clicon_handle h,
yang_stmt *ys,
int level,
yang2cli_stmt(clicon_handle h,
yang_stmt *ys,
int level,
cbuf *cb)
{
int retval = -1;
@ -1230,11 +1266,11 @@ yang2cli_stmt(clicon_handle h,
goto done;
}
if (yang_find(ys, Y_STATUS, "obsolete") != NULL){
clicon_debug(4, "%s obsolete: %s %s, skipped", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
clixon_debug(CLIXON_DBG_DETAIL, "%s obsolete: %s %s, skipped", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
goto ok;
}
if (yang_find(ys, Y_STATUS, "deprecated") != NULL){
clicon_debug(4, "%s deprecated: %s %s", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
clixon_debug(CLIXON_DBG_DETAIL, "%s deprecated: %s %s", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
}
/* Check if autocli skip */
if (yang_extension_value(ys, "skip", CLIXON_AUTOCLI_NS, &extvalue, NULL) < 0)
@ -1252,7 +1288,7 @@ yang2cli_stmt(clicon_handle h,
#ifdef AUTOCLI_GROUPING_TOPLEVEL_SKIP
cornercase = yang_keyword_get(yang_parent_get(ys)) == Y_MODULE || yang_keyword_get(yang_parent_get(ys)) == Y_SUBMODULE;
#endif
if (yang_keyword_get(ys) != Y_USES && yang_flag_get(ys, YANG_FLAG_GROUPING)
if (yang_keyword_get(ys) != Y_USES && yang_flag_get(ys, YANG_FLAG_GROUPING)
&& !cornercase
)
goto ok;
@ -1301,6 +1337,7 @@ yang2cli_stmt(clicon_handle h,
}
/*! Add cv with name to cvec
*
* @param[in] cvv Either existing or NULL
* @param[in] name Name of cv to add
* @retval cvv Either same as in cvv parameter or new
@ -1310,7 +1347,7 @@ cvec_add_name(cvec *cvv,
char *name)
{
cg_var *cv= NULL;
if (cvv == NULL &&
(cvv = cvec_new(0)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
@ -1382,7 +1419,7 @@ yang2cli_post(clicon_handle h,
char *name;
cg_var *cv = NULL;
int j=0;
cv = NULL;
while ((cv = cvec_each(cop->co_cvec, cv)) != NULL){
name = cv_name_get(cv);
@ -1480,7 +1517,7 @@ yang2cli_post(clicon_handle h,
* XXX merge with yang2cli_yspec
*/
static int
yang2cli_grouping(clicon_handle h,
yang2cli_grouping(clicon_handle h,
yang_stmt *ys,
char *treename)
{
@ -1495,7 +1532,7 @@ yang2cli_grouping(clicon_handle h,
cg_obj *co;
int config;
int i;
if ((pt0 = pt_new()) == NULL){
clicon_err(OE_UNIX, errno, "pt_new");
goto done;
@ -1506,11 +1543,11 @@ yang2cli_grouping(clicon_handle h,
}
/* Traverse YANG, loop through all modules and generate CLI, inline of yang2cli_stmt */
if (yang_find(ys, Y_STATUS, "obsolete") != NULL){
clicon_debug(4, "%s obsolete: %s %s, skipped", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
clixon_debug(CLIXON_DBG_DETAIL, "%s obsolete: %s %s, skipped", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
goto empty;
}
if (yang_find(ys, Y_STATUS, "deprecated") != NULL){
clicon_debug(4, "%s deprecated: %s %s", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
clixon_debug(CLIXON_DBG_DETAIL, "%s deprecated: %s %s", __FUNCTION__, yang_argument_get(ys), yang_argument_get(ys_module(ys)));
}
/* Only produce autocli for YANG non-config only if autocli-treeref-state is true */
if (autocli_treeref_state(h, &treeref_state) < 0)
@ -1539,12 +1576,12 @@ yang2cli_grouping(clicon_handle h,
fprintf(stderr, "%s\n", cbuf_get(cb));
goto done;
}
clicon_debug(CLIXON_DBG_DEFAULT, "%s Generated auto-cli for grouping:%s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s Generated auto-cli for grouping:%s",
__FUNCTION__, yang_argument_get(ys));
/* Add prefix: assume new are appended */
for (i=0; i<pt_len_get(pt); i++){
if ((co = pt_vec_i_get(pt, i)) != NULL){
clicon_debug(CLIXON_DBG_DEFAULT, "%s command: %s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s command: %s",
__FUNCTION__, co->co_command);
co_prefix_set(co, prefix);
}
@ -1562,7 +1599,7 @@ yang2cli_grouping(clicon_handle h,
clicon_log(LOG_NOTICE, "%s: Top-level cli-spec %s:\n%s",
__FUNCTION__, treename, cbuf_get(cb));
else
clicon_debug(CLIXON_DBG_DETAIL, "%s: Top-level cli-spec %s:\n%s",
clixon_debug(CLIXON_DBG_DETAIL, "%s: Top-level cli-spec %s:\n%s",
__FUNCTION__, treename, cbuf_get(cb));
if (cligen_parsetree_merge(pt0, NULL, pt) < 0){
clicon_err(OE_YANG, errno, "cligen_parsetree_merge");
@ -1614,7 +1651,7 @@ yang2cli_grouping(clicon_handle h,
* @note Tie-break of same top-level symbol: prefix is NYI
*/
int
yang2cli_yspec(clicon_handle h,
yang2cli_yspec(clicon_handle h,
yang_stmt *yspec,
char *treename)
{
@ -1629,7 +1666,7 @@ yang2cli_yspec(clicon_handle h,
cg_obj *co;
int i;
int config;
if ((pt0 = pt_new()) == NULL){
clicon_err(OE_UNIX, errno, "pt_new");
goto done;
@ -1669,12 +1706,12 @@ yang2cli_yspec(clicon_handle h,
fprintf(stderr, "%s\n", cbuf_get(cb));
goto done;
}
clicon_debug(CLIXON_DBG_DEFAULT, "%s Generated auto-cli for module:%s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s Generated auto-cli for module:%s",
__FUNCTION__, yang_argument_get(ymod));
/* Add prefix: assume new are appended */
for (i=0; i<pt_len_get(pt); i++){
if ((co = pt_vec_i_get(pt, i)) != NULL){
clicon_debug(CLIXON_DBG_DEFAULT, "%s command: %s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s command: %s",
__FUNCTION__, co->co_command);
co_prefix_set(co, prefix);
}
@ -1693,7 +1730,7 @@ yang2cli_yspec(clicon_handle h,
clicon_log(LOG_NOTICE, "%s: Top-level cli-spec %s:\n%s",
__FUNCTION__, treename, cbuf_get(cb));
else
clicon_debug(CLIXON_DBG_DETAIL, "%s: Top-level cli-spec %s:\n%s",
clixon_debug(CLIXON_DBG_DETAIL, "%s: Top-level cli-spec %s:\n%s",
__FUNCTION__, treename, cbuf_get(cb));
if (cligen_parsetree_merge(pt0, NULL, pt) < 0){
clicon_err(OE_YANG, errno, "cligen_parsetree_merge");

View file

@ -72,7 +72,8 @@
#define handle(h) (assert(clicon_handle_check(h)==0),(struct cli_handle *)(h))
#define cligen(h) (handle(h)->cl_cligen)
/*! CLI specific handle added to header CLICON handle
/*! CLI specific handle added to header Clixon handle
*
* This file should only contain access functions for the _specific_
* entries in the struct below.
* @note The top part must be equivalent to struct clicon_handle in clixon_handle.c
@ -115,6 +116,8 @@ cli_handle_init(void)
}
/*! Free clicon handle
*
* @param[in] h Clixon handle
*/
int
cli_handle_exit(clicon_handle h)
@ -130,7 +133,10 @@ cli_handle_exit(clicon_handle h)
* cli-specific handle access functions
*----------------------------------------------------------*/
/*! Return clicon handle */
/*! Return clicon handle
*
* @param[in] h Clixon handle
*/
cligen_handle
cli_cligen(clicon_handle h)
{
@ -156,8 +162,9 @@ cli_susp_hook(clicon_handle h,
cligen_handle ch = cligen(h);
/* This assume first arg of fn can be treated as void* */
return cligen_susp_hook(ch, fn);
return cligen_susp_hook(ch, fn);
}
int
cli_interrupt_hook(clicon_handle h,
cligen_interrupt_cb_t *fn)
@ -165,7 +172,7 @@ cli_interrupt_hook(clicon_handle h,
cligen_handle ch = cligen(h);
/* This assume first arg of fn can be treated as void* */
return cligen_interrupt_hook(ch, fn);
return cligen_interrupt_hook(ch, fn);
}
int

View file

@ -76,8 +76,11 @@
#define CLI_OPTS "+hD:f:E:l:C:F:1a:u:d:m:qp:GLy:c:U:o:"
/*! Check if there is a CLI history file and if so dump the CLI histiry to it
*
* Just log if file does not exist or is not readable
* @param[in] h CLICON handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
static int
cli_history_load(clicon_handle h)
@ -121,8 +124,11 @@ cli_history_load(clicon_handle h)
}
/*! Start CLI history and load from file
*
* Just log if file does not exist or is not readable
* @param[in] h CLICON handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
static int
cli_history_save(clicon_handle h)
@ -157,6 +163,7 @@ cli_history_save(clicon_handle h)
}
/*! Clean and close all state of cli process (but dont exit).
*
* Cannot use h after this
* @param[in] h Clixon handle
*/
@ -170,7 +177,7 @@ cli_terminate(clicon_handle h)
if (clixon_exit_get() == 0)
clixon_exit_set(1);
if (clicon_data_get(h, "session-transport", NULL) == 0)
clicon_rpc_close_session(h);
clicon_rpc_close_session(h);
if ((yspec = clicon_dbspec_yang(h)) != NULL)
ys_free(yspec);
if ((yspec = clicon_config_yang(h)) != NULL)
@ -195,11 +202,11 @@ cli_terminate(clicon_handle h)
}
/*! Unlink pidfile and quit
*/
*/
static void
cli_sig_term(int arg)
{
clicon_log(LOG_NOTICE, "%s: %u Terminated (killed by sig %d)",
clicon_log(LOG_NOTICE, "%s: %u Terminated (killed by sig %d)",
__PROGRAM__, getpid(), arg);
exit(1);
}
@ -226,7 +233,8 @@ cli_signal_init (clicon_handle h)
}
/*! Interactive CLI command loop
* @param[in] h CLICON handle
*
* @param[in] h Clixon handle
* @retval 0
* @retval -1
* @see cligen_loop
@ -269,6 +277,7 @@ cli_interactive(clicon_handle h)
}
/*! Create pre-5.5 tree-refs for backward compatibility
*
* should probably be moved to clispec default
*/
static int
@ -382,8 +391,8 @@ autocli_start(clicon_handle h)
int retval = -1;
yang_stmt *yspec;
int enable = 0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* There is no single "enable-autocli" flag,
* but set
* <module-default>false</module-default>
@ -394,7 +403,7 @@ autocli_start(clicon_handle h)
if (autocli_module(h, NULL, &enable) < 0)
goto done;
if (!enable){
clicon_debug(1, "%s Autocli not enabled (clixon-autocli)", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Autocli not enabled (clixon-autocli)", __FUNCTION__);
goto ok;
}
/* Init yang2cli */
@ -404,7 +413,7 @@ autocli_start(clicon_handle h)
/* The actual generating call from yang to clispec for the complete yang spec, @basemodel */
if (yang2cli_yspec(h, yspec, AUTOCLI_TREENAME) < 0)
goto done;
/* XXX Create pre-5.5 tree-refs for backward compatibility */
/* XXX Create pre-5.5 tree-refs for backward compatibility */
if (autocli_trees_default(h) < 0)
goto done;
ok:
@ -469,7 +478,7 @@ usage(clicon_handle h,
fprintf(stderr, "usage:%s [options] [commands] [-- extra-options]\n"
"where commands is a CLI command\n"
"and extra-options are app-dependent and passed to the plugin init function\n"
"and extra-options are app-dependent and passed to the plugin init function\n"
"where options are\n"
"\t-h \t\tHelp\n"
"\t-D <level> \tDebug level\n"
@ -525,7 +534,7 @@ main(int argc,
int nr;
int config_dump;
enum format_enum config_dump_format = FORMAT_XML;
/* Defaults */
once = 0;
config_dump = 0;
@ -533,7 +542,7 @@ main(int argc,
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Initiate CLICON handle. CLIgen is also initialized */
/* Initiate Clixon handle. CLIgen is also initialized */
if ((h = cli_handle_init()) == NULL)
goto done;
@ -549,7 +558,7 @@ main(int argc,
cligen_comment_set(cli_cligen(h), '#'); /* Default to handle #! clicon_cli scripts */
cligen_lexicalorder_set(cli_cligen(h), 1);
/*
* First-step command-line options for help, debug, config-file and log,
*/
@ -588,11 +597,11 @@ main(int argc,
goto done;
break;
}
/*
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(dbg, NULL);
clixon_debug_init(dbg, NULL);
yang_init(h);
/* Find, read and parse configfile */
@ -601,7 +610,7 @@ main(int argc,
usage(h, argv[0]);
goto done;
}
/* Now rest of options */
/* Now rest of options */
opterr = 0;
optind = 1;
while ((c = getopt(argc, argv, CLI_OPTS)) != -1){
@ -698,7 +707,7 @@ main(int argc,
/* Defer: Wait to the last minute to print help message */
if (help)
usage(h, argv[0]);
/* Split remaining argv/argc into <cmd> and <extra-options> */
if (options_split(h, argv0, argc, argv, &restarg) < 0)
goto done;
@ -713,7 +722,7 @@ main(int argc,
nr = clicon_option_int(h, "CLICON_CLI_LINES_DEFAULT");
cligen_terminal_rows_set(cli_cligen(h), nr);
}
if (clicon_yang_regexp(h) == REGEXP_LIBXML2){
#ifdef HAVE_LIBXML2
/* Enable XSD libxml2 regex engine */
@ -732,7 +741,7 @@ main(int argc,
if ((nr = clicon_option_int(h, "CLICON_LOG_STRING_LIMIT")) != 0)
clicon_log_string_limit_set(nr);
/* Setup signal handlers */
if (cli_signal_init(h) < 0)
goto done;
@ -757,7 +766,7 @@ main(int argc,
goto done;
}
#endif
/* Add (hardcoded) netconf features in case ietf-netconf loaded here
* Otherwise it is loaded in netconf_module_load below
*/
@ -772,7 +781,7 @@ main(int argc,
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL){
@ -802,7 +811,6 @@ main(int argc,
/* Add netconf yang spec, used as internal protocol */
if (netconf_module_load(h) < 0)
goto done;
/* Here all modules are loaded
* Compute and set canonical namespace context
*/
@ -868,7 +876,7 @@ main(int argc,
clicon_option_dump(h, 1);
cligen_line_scrolling_set(cli_cligen(h), clicon_option_int(h,"CLICON_CLI_LINESCROLLING"));
/*! Start CLI history and load from file */
/* Start CLI history and load from file */
if (cli_history_load(h) < 0)
goto done;
/* Experimental utf8 mode */
@ -893,7 +901,7 @@ main(int argc,
if (evalresult < 0)
goto done;
}
/* Go into event-loop unless -1 command-line */
if (!once){
retval = cli_interactive(h);

View file

@ -92,7 +92,7 @@ pipe_arg_fn(clicon_handle h,
struct stat fstat;
char **argv = NULL;
int i;
if (cmd == NULL || strlen(cmd) == 0){
clicon_err(OE_PLUGIN, EINVAL, "cmd '%s' NULL or empty", cmd);
goto done;
@ -123,7 +123,7 @@ pipe_arg_fn(clicon_handle h,
/* Grep pipe output function
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv String vector of options. Format: <option> <value>
* @note Any vertical bar (|] in the patterns field is quoted for OR function
@ -182,9 +182,11 @@ pipe_grep_fn(clicon_handle h,
/*! wc pipe output function
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv String vector of options. Format: <option> <value>
* @retval 0 OK
* @retval -1 Error
*/
int
pipe_wc_fn(clicon_handle h,
@ -195,7 +197,7 @@ pipe_wc_fn(clicon_handle h,
cg_var *cv;
char *str;
char *option = NULL;
if (cvec_len(argv) != 1){
clicon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected: <NUM>", cvec_len(argv));
goto done;
@ -211,9 +213,11 @@ pipe_wc_fn(clicon_handle h,
/*! wc pipe output function
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv String vector of options. Format: <option> <value>
* @retval 0 OK
* @retval -1 Error
*/
int
pipe_tail_fn(clicon_handle h,
@ -252,12 +256,14 @@ pipe_tail_fn(clicon_handle h,
/*! Output pipe translate from xml to other format: json,text,
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv String vector of show options, format:
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum), default: xml
* <pretty> true|false: pretty-print or not
* <prepend> CLI prefix: prepend before cli syntax output
* @retval 0 OK
* @retval -1 Error
* @see cli_show_auto_devs
*/
int
@ -350,7 +356,7 @@ output_fn(cligen_handle handle,
cvec *argv)
{
cg_var *cv;
cv = NULL;
while ((cv = cvec_each(argv, cv)) != NULL){
cligen_output(stdout, "%s\n", cv_string_get(cv));

View file

@ -81,8 +81,10 @@
/*! Generate CLIgen parse tree for syntax mode
*
* @param[in] h Clicon handle
* @param[in] m Syntax mode struct
* @param[in] h Clixon handle
* @param[in] m Syntax mode struct
* @retval 0 OK
* @retval -1 Error
*/
static int
gen_parse_tree(clicon_handle h,
@ -92,7 +94,7 @@ gen_parse_tree(clicon_handle h,
{
int retval = -1;
pt_head *ph;
if ((ph = cligen_ph_add(cli_cligen(h), name)) == NULL)
goto done;
if (cligen_ph_parsetree_set(ph, pt) < 0)
@ -123,12 +125,12 @@ gen_parse_tree(clicon_handle h,
* @note the returned function is not type-checked which may result in segv at runtime
*/
void *
clixon_str2fn(char *name,
void *handle,
clixon_str2fn(char *name,
void *handle,
char **error)
{
void *fn = NULL;
/* Reset error */
*error = NULL;
/* Special check for auto-cli. If the virtual callback is used, it should be overwritten later
@ -160,16 +162,14 @@ clixon_str2fn(char *name,
* signal an error. However, just checking the function pointer for NULL
* should work in most cases, although it's not 100% correct.
*/
return NULL;
return NULL;
}
/*! Set output pipe flag in all callbacks
*
* @param[in] co CLIgen parse-tree object
* @param[in] arg Argument, cast to application-specific info
* @retval 1 OK and return (abort iteration)
* @retval 0 OK and continue
* @retval -1 Error: break and return
* @retval 0 OK
*/
static int
cli_mark_output_pipes(cg_obj *co,
@ -193,6 +193,8 @@ cli_mark_output_pipes(cg_obj *co,
* @param[in] dir Name of dir, or NULL
* @param[out] ptall Universal CLIgen parse tree: apply to all modes
* @param[out] modes Keep track of all modes
* @retval 0 OK
* @retval -1 Error
* @see clixon_plugins_load Where .so plugin code has been loaded prior to this
*/
static int
@ -202,10 +204,10 @@ clispec_load_file(clicon_handle h,
parse_tree *ptall,
cvec *modes)
{
int retval = -1;
void *handle = NULL; /* Handle to plugin .so module */
char *mode = NULL; /* Name of syntax mode to append new syntax */
parse_tree *pt = NULL;
int retval = -1;
FILE *f;
char filepath[MAXPATHLEN];
cvec *cvv = NULL;
@ -265,8 +267,8 @@ clispec_load_file(clicon_handle h,
if ((cp = clixon_plugin_find(h, plgnam)) != NULL)
handle = clixon_plugin_handle_get(cp);
if (handle == NULL){
clicon_err(OE_PLUGIN, 0, "CLICON_PLUGIN set to '%s' in %s but plugin %s.so not found in %s",
plgnam, filename, plgnam,
clicon_err(OE_PLUGIN, 0, "CLICON_PLUGIN set to '%s' in %s but plugin %s.so not found in %s",
plgnam, filename, plgnam,
clicon_cli_dir(h));
goto done;
}
@ -281,27 +283,27 @@ clispec_load_file(clicon_handle h,
}
/* Resolve callback names to function pointers. */
if (cligen_callbackv_str2fn(pt, (cgv_str2fn_t*)clixon_str2fn, handle) < 0){
clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)",
if (cligen_callbackv_str2fn(pt, (cgv_str2fn_t*)clixon_str2fn, handle) < 0){
clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)",
filename, plgnam, plgnam);
goto done;
}
if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, handle) < 0)
if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, handle) < 0)
goto done;
/* Variable translation functions */
if (cligen_translate_str2fn(pt, (translate_str2fn_t*)clixon_str2fn, handle) < 0)
if (cligen_translate_str2fn(pt, (translate_str2fn_t*)clixon_str2fn, handle) < 0)
goto done;
/* Make sure we have a syntax mode specified */
if (mode == NULL || strlen(mode) < 1) { /* may be null if not given in file */
mode = clicon_cli_mode(h);
if (mode == NULL || strlen(mode) < 1) { /* may be null if not given in file */
if (mode == NULL || strlen(mode) < 1) { /* may be null if not given in file */
clicon_err(OE_PLUGIN, 0, "No syntax mode specified in %s", filepath);
goto done;
}
}
/* Find all modes in CLICON_MODE string: where to append the pt syntax tree */
if ((vec = clicon_strsep(mode, ":", &nvec)) == NULL)
if ((vec = clicon_strsep(mode, ":", &nvec)) == NULL)
goto done;
if (nvec == 1 && strcmp(vec[0], "*") == 0){
@ -369,7 +371,9 @@ done:
*
* CLI .so plugins have been loaded: syntax table in place.
* Now load cligen syntax files and create cligen pt trees.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* XXX The parsetree loading needs a rewrite for multiple parse-trees
*/
int
@ -413,7 +417,7 @@ clispec_load(clicon_handle h)
goto done;
/* Load the syntax parse trees into cli_syntax stx structure */
for (i = 0; i < ndp; i++) {
clicon_debug(CLIXON_DBG_DEFAULT, "Loading clispec syntax: '%s/%s'",
clixon_debug(CLIXON_DBG_DEFAULT, "Loading clispec syntax: '%s/%s'",
clispec_dir, dp[i].d_name);
if (clispec_load_file(h, dp[i].d_name, clispec_dir, ptall, modes) < 0)
goto done;
@ -461,7 +465,8 @@ done:
}
/*! Free resources in plugin
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
int
cli_plugin_finish(clicon_handle h)
@ -470,13 +475,14 @@ cli_plugin_finish(clicon_handle h)
}
/*! Help function to print a meaningful error string.
*
* Sometimes the libraries specify an error string, if so print that.
* Otherwise just print 'command error'.
* But do not print it if error is already logged in eg clicon_err() using STDERR logging
* See eg https://github.com/clicon/clixon/issues/325
* @param[in] f File handler to write error to.
*/
int
int
cli_handler_err(FILE *f)
{
if (clicon_errno){
@ -494,6 +500,7 @@ cli_handler_err(FILE *f)
}
/*! Given a command string, parse and if match single command, eval it.
*
* Parse and evaluate the string according to
* the syntax parse tree of the syntax mode specified by *mode.
* If there is no match in the tree for the command, the parse hook
@ -501,19 +508,19 @@ cli_handler_err(FILE *f)
* match is found in another mode, the mode variable is updated to point at
* the new mode string.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] cmd Command string
* @param[in,out] modenamep Pointer to the mode string pointer
* @param[out] result CLIgen match result, < 0: errors, >=0 number of matches
* @param[out] evalres Evaluation result if result=1
* @retval 0 OK
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_parse(clicon_handle h,
char *cmd,
char **modenamep,
cligen_result *result,
clicon_parse(clicon_handle h,
char *cmd,
char **modenamep,
cligen_result *result,
int *evalres)
{
int retval = -1;
@ -526,7 +533,7 @@ clicon_parse(clicon_handle h,
char *reason = NULL;
cligen_handle ch;
pt_head *ph;
ch = cli_cligen(h);
if (clicon_get_logflags()&CLICON_LOG_STDOUT)
f = stdout;
@ -546,10 +553,10 @@ clicon_parse(clicon_handle h,
if (cliread_parse(ch, cmd, pt, &match_obj, &cvv, result, &reason) < 0)
goto done;
/* Debug command and result code */
clicon_debug(1, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd);
clixon_debug(CLIXON_DBG_DEFAULT, "%s result:%d command: \"%s\"", __FUNCTION__, *result, cmd);
switch (*result) {
case CG_EOF: /* eof */
case CG_ERROR:
case CG_ERROR:
fprintf(f, "CLI parse error: %s\n", cmd); // In practice never happens
break;
case CG_NOMATCH: /* no match */
@ -561,7 +568,7 @@ clicon_parse(clicon_handle h,
cli_set_syntax_mode(h, modename);
}
cli_output_reset();
if (!cligen_exiting(ch)) {
if (!cligen_exiting(ch)) {
clicon_err_reset();
if ((ret = cligen_eval(ch, match_obj, cvv)) < 0) {
cli_handler_err(stdout);
@ -596,6 +603,7 @@ done:
}
/*! Return a malloced expanded prompt string from printf-like format
*
* @param[in] h Clixon handle
* @param[in] fmt Format string, using %H, %
* @retval prompt Malloced string, free after use
@ -654,7 +662,7 @@ cli_prompt_get(clicon_handle h,
else
cprintf(cb, "/");
break;
case 'w': /* Full Working edit path */
case 'w': /* Full Working edit path */
if (clicon_data_get(h, "cli-edit-mode", &path) == 0 &&
strlen(path))
cprintf(cb, "%s", path);
@ -676,7 +684,7 @@ cli_prompt_get(clicon_handle h,
cprintf(cb, "%c", *s);
}
}
else
else
cprintf(cb, "%c", *s);
s++;
}
@ -693,7 +701,7 @@ cli_prompt_get(clicon_handle h,
/*! Read command from CLIgen's cliread() using current syntax mode.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] ph Parse-tree head
* @param[out] stringp Pointer to command buffer or NULL on EOF
* @retval 1 OK
@ -756,7 +764,8 @@ clicon_cliread(clicon_handle h,
*/
/*! Set syntax mode mode for existing current plugin group.
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval 1 OK
* @retval 0 Not found / error
*/
@ -774,13 +783,14 @@ cli_set_syntax_mode(clicon_handle h,
}
/*! Get syntax mode name
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
char *
cli_syntax_mode(clicon_handle h)
{
pt_head *ph;
if ((ph = cligen_pt_head_active_get(cli_cligen(h))) == NULL)
return NULL;
return cligen_ph_name_get(ph);

View file

@ -182,7 +182,7 @@ xpath_append(cbuf *cb0,
free(prefix);
if (id)
free(id);
free(vec);
free(vec);
return retval;
}
@ -201,13 +201,15 @@ xpath_append(cbuf *cb0,
* [<mt-point>] Optional YANG path-arg/xpath from mount-point
* @param[out] commands vector of function pointers to callback functions
* @param[out] helptxt vector of pointers to helptexts
* @retval 0 OK
* @retval -1 Error
* @see cli_expand_var_generate where api_path_fmt + mt-point are generated
*/
int
expand_dbvar(void *h,
char *name,
cvec *cvv,
cvec *argv,
expand_dbvar(void *h,
char *name,
cvec *cvv,
cvec *argv,
cvec *commands,
cvec *helptexts)
{
@ -246,7 +248,7 @@ expand_dbvar(void *h,
char *str;
int grouping_treeref;
cvec *callback_cvv;
if (argv == NULL || (cvec_len(argv) != 2 && cvec_len(argv) != 3)){
clicon_err(OE_PLUGIN, EINVAL, "requires arguments: <db> <apipathfmt> [<mountpt>]");
goto done;
@ -263,7 +265,7 @@ expand_dbvar(void *h,
if (strcmp(dbstr, "running") != 0 &&
strcmp(dbstr, "candidate") != 0 &&
strcmp(dbstr, "startup") != 0){
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
goto done;
}
if ((cv = cvec_i(argv, 1)) == NULL){
@ -273,18 +275,18 @@ expand_dbvar(void *h,
if (autocli_grouping_treeref(h, &grouping_treeref) < 0)
goto done;
if ((api_path_fmt_cb = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if (grouping_treeref &&
(callback_cvv = cligen_callback_arguments_get(cli_cligen(h))) != NULL){
/* Concatenate callback arguments to a singel prepend string */
if (cvec_concat_cb(callback_cvv, api_path_fmt_cb) < 0)
goto done;
goto done;
}
cprintf(api_path_fmt_cb, "%s", cv_string_get(cv));
api_path_fmt = cbuf_get(api_path_fmt_cb);
if (cvec_len(argv) > 2){
if (cvec_len(argv) > 2){
cv = cvec_i(argv, 2);
str = cv_string_get(cv);
if (strncmp(str, "mtpoint:", strlen("mtpoint:")) != 0){
@ -379,13 +381,13 @@ expand_dbvar(void *h,
goto done;
}
/* Get configuration based on cbxpath */
if (clicon_rpc_get_config(h, NULL, dbstr, cbuf_get(cbxpath), nsc, NULL, &xt) < 0)
if (clicon_rpc_get_config(h, NULL, dbstr, cbuf_get(cbxpath), nsc, NULL, &xt) < 0)
goto done;
if ((xe = xpath_first(xt, NULL, "/rpc-error")) != NULL){
clixon_netconf_error(xe, "Get configuration", NULL);
goto ok;
goto ok;
}
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, cbuf_get(cbxpath)) < 0)
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, cbuf_get(cbxpath)) < 0)
goto done;
/* Loop for inserting into commands cvec.
* Detect duplicates: for ordered-by system assume list is ordered, so you need
@ -446,15 +448,22 @@ expand_dbvar(void *h,
xml_free(xtop);
if (xt)
xml_free(xt);
if (xpath)
if (xpath)
free(xpath);
return retval;
}
/*! CLI callback show yang spec. If arg given matches yang argument string */
/*! CLI callback show yang spec. If arg given matches yang argument string
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of command variables
* @param[in] argv
* @retval 0 OK
* @retval -1 Error
*/
int
show_yang(clicon_handle h,
cvec *cvv,
show_yang(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
@ -462,7 +471,7 @@ show_yang(clicon_handle h,
char *str = NULL;
yang_stmt *yspec;
yspec = clicon_dbspec_yang(h);
yspec = clicon_dbspec_yang(h);
if (cvec_len(argv) > 0){
if ((str = cv_string_get(cvec_i(argv, 0))) != NULL &&
(yn = yang_find(yspec, 0, str)) != NULL)
@ -495,6 +504,8 @@ show_yang(clicon_handle h,
* @param[in] fromroot If 0, display config from node of XPATH, if 1 display from root
* @param[in] nsc Namespace mapping for xpath
* @param[in] skiptop If set, do not show object itself, only its children
* @retval 0 OK
* @retval -1 Error
*/
int
cli_show_common(clicon_handle h,
@ -511,7 +522,7 @@ cli_show_common(clicon_handle h,
int skiptop
)
{
int retval = -1;
int retval = -1;
cxobj *xt = NULL;
cxobj *xerr;
cxobj **vec = NULL;
@ -542,19 +553,19 @@ cli_show_common(clicon_handle h,
if (purge_tagged_nodes(xt, IETF_NETCONF_WITH_DEFAULTS_ATTR_NAMESPACE, "default", "true",
strcmp(extdefault, "report-all-tagged-strip")
) < 0)
goto done;
goto done;
/* Remove empty containers */
if (xml_defaults_nopresence(xt, 2) < 0)
goto done;
}
if (fromroot)
xpath="/";
if (xpath_vec(xt, nsc, "%s", &vec, &veclen, xpath) < 0)
if (xpath_vec(xt, nsc, "%s", &vec, &veclen, xpath) < 0)
goto done;
if (veclen){
/* Special case LIST */
if (format == FORMAT_JSON){
switch (format){
switch (format){
case FORMAT_JSON:
if (xml2json_vec(stdout, vec, veclen, pretty, cligen_output, skiptop) < 0)
goto done;
@ -619,7 +630,7 @@ done:
* @retval 0 OK
* @retval -1 Error
*/
int
int
cli_show_option_format(cvec *argv,
int argc,
enum format_enum *format)
@ -645,7 +656,7 @@ cli_show_option_format(cvec *argv,
* @retval 0 OK
* @retval -1 Error
*/
int
int
cli_show_option_bool(cvec *argv,
int argc,
int *result
@ -685,7 +696,7 @@ cli_show_option_bool(cvec *argv,
* @retval 0 OK
* @retval -1 Error
*/
int
int
cli_show_option_withdefault(cvec *argv,
int argc,
char **withdefault,
@ -722,7 +733,7 @@ cli_show_option_withdefault(cvec *argv,
/*! Generic show configuration callback
*
* Does not need to be used with the autocli as cli_show_auto does
* @param[in] h CLICON handle
* @param[in] h Clixon handle
* @param[in] cvv Vector of variables from CLIgen command-line
* @param[in] argv String vector of show options, format:
* <dbname> Name of datastore, such as "running"
@ -735,6 +746,8 @@ cli_show_option_withdefault(cvec *argv,
* <default> Retrieval mode: report-all, trim, explicit, report-all-tagged,
* NULL, report-all-tagged-default, report-all-tagged-strip (extended)
* <prepend> CLI prefix: prepend before cli syntax output
* @retval 0 OK
* @retval -1 Error
* @code
* clispec:
* show config, cli_show_config("running","xml");
@ -752,8 +765,8 @@ cli_show_option_withdefault(cvec *argv,
* @see cli_show_auto_mode autocli with edit menu support
*/
int
cli_show_config(clicon_handle h,
cvec *cvv,
cli_show_config(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
@ -769,7 +782,7 @@ cli_show_config(clicon_handle h,
char *xpath = "/";
char *namespace = NULL;
int fromroot = 0;
if (cvec_len(argv) < 2 || cvec_len(argv) > 8){
clicon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected: <dbname> [<format><xpath> <namespace> <pretty> <state> <default> <prepend>]", cvec_len(argv));
goto done;
@ -815,29 +828,18 @@ cli_show_config(clicon_handle h,
return retval;
}
/*! Show configuration and state CLIGEN callback function
/*! Show configuration xpath
*
* @param[in] h CLICON handle
* @param[in] h Clixon handle
* @param[in] cvv Vector of variables from CLIgen command-line
* @param[in] argv String vector of show options, format:
* <dbname> "running"|"candidate"|"startup"
* @code
* show config id <n:string>, cli_show_config("running","xml","iface[name='foo']","urn:example:example");
* @endcode
* @see cli_show_config_state For config and state data (not only config)
*/
/*! Show configuration as text given an xpath using canonical namespace
*
* Utility function used by cligen spec file
* @param[in] h CLICON handle
* @param[in] cvv Vector of variables from CLIgen command-line must contain xpath and default namespace (if any)
* @param[in] argv A string: <dbname>
* @note Different from cli_show_conf: values taken cvv "xpath" and "ns" instead of argv
* @retval 0 OK
* @retval -1 Error
*/
int
show_conf_xpath(clicon_handle h,
cvec *cvv,
show_conf_xpath(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
@ -847,7 +849,7 @@ show_conf_xpath(clicon_handle h,
cvec *nsc = NULL;
yang_stmt *yspec;
int fromroot = 0;
if (cvec_len(argv) != 1){
clicon_err(OE_PLUGIN, EINVAL, "Requires one element to be <dbname>");
goto done;
@ -886,7 +888,7 @@ done:
*/
int
cli_show_version(clicon_handle h,
cvec *vars,
cvec *cvv,
cvec *argv)
{
cligen_output(stdout, "Clixon: %s\n", CLIXON_VERSION_STRING);
@ -914,6 +916,8 @@ cli_show_version(clicon_handle h,
* NULL, report-all-tagged-default, report-all-tagged-strip (extended)
* <prepend> CLI prefix: prepend before cli syntax output
* <fromroot> true|false: Show from root
* @retval 0 OK
* @retval -1 Error
* @code
* clispec:
* show config @datamodelshow, cli_show_auto("candidate", "xml");
@ -931,7 +935,7 @@ cli_show_version(clicon_handle h,
* XXX merge cli_show_auto and cli_show_auto_mode
* @see cli_callback_generate where api_path_fmt + mt-point are generated
*/
int
int
cli_show_auto(clicon_handle h,
cvec *cvv,
cvec *argv)
@ -955,7 +959,7 @@ cli_show_auto(clicon_handle h,
char *str;
char *mtpoint = NULL;
int fromroot = 0;
if (cvec_len(argv) < 2 || cvec_len(argv) > 9){
clicon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected:: <api-path-fmt>* <database> [<format> <pretty> <state> <default> <prepend> <fromroot>]", cvec_len(argv));
goto done;
@ -996,7 +1000,7 @@ cli_show_auto(clicon_handle h,
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
}
if (mtpoint){
if (mtpoint){
/* Get and combined api-path01 */
if (mtpoint_paths(yspec0, mtpoint, api_path_fmt, &api_path_fmt01) < 0)
goto done;
@ -1046,6 +1050,8 @@ cli_show_auto(clicon_handle h,
* <default> Retrieval mode: report-all, trim, explicit, report-all-tagged,
* NULL, report-all-tagged-default, report-all-tagged-strip (extended)
* <prepend> CLI prefix: prepend before cli syntax output
* @retval 0 OK
* @retval -1 Error
* @cli_show_auto_ctrl
code
* clispec:
@ -1088,7 +1094,7 @@ cli_show_auto_mode(clicon_handle h,
cvec *nsc0 = NULL;
cg_var *cv;
int fromroot = 0;
if (cvec_len(argv) < 2 || cvec_len(argv) > 7){
clicon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected: <database> [ <format> <pretty> <state> <default> <cli-prefix>]", cvec_len(argv));
goto done;
@ -1142,7 +1148,7 @@ cli_show_auto_mode(clicon_handle h,
goto done;
}
if (mtpoint){
cprintf(cbxpath, "%s", mtpoint);
cprintf(cbxpath, "%s", mtpoint);
if (xml_nsctx_yangspec(yspec0, &nsc0) < 0)
goto done;
cv = NULL; /* Append cvv1 to cvv2 */
@ -1170,9 +1176,14 @@ cli_show_auto_mode(clicon_handle h,
/*! Show clixon configuration options as loaded
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of command variables
* @param[in] argv
* @retval 0 OK
* @retval -1 Error
'* @see clicon_option_dump clicon_option_dump1
*/
int
int
cli_show_options(clicon_handle h,
cvec *cvv,
cvec *argv)
@ -1185,7 +1196,7 @@ cli_show_options(clicon_handle h,
size_t klen;
size_t vlen;
cxobj *x = NULL;
if (clicon_hash_keys(hash, &keys, &klen) < 0)
goto done;
for(i = 0; i < klen; i++) {
@ -1228,9 +1239,12 @@ cli_show_options(clicon_handle h,
}
/*! Show pagination
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cvv Vector of cli string and instantiated variables
* @param[in] argv Vector. Format: <xpath> <prefix> <namespace> <format> <limit>
* @retval 0 OK
* @retval -1 Error
* Also, if there is a cligen variable called "xpath" it will override argv xpath arg
*/
int
@ -1239,7 +1253,7 @@ cli_pagination(clicon_handle h,
cvec *argv)
{
int retval = -1;
cbuf *cb = NULL;
cbuf *cb = NULL;
char *xpath = NULL;
char *prefix = NULL;
char *namespace = NULL;
@ -1256,7 +1270,7 @@ cli_pagination(clicon_handle h,
cxobj **xvec = NULL;
size_t xlen;
int locked = 0;
if (cvec_len(argv) != 5){
clicon_err(OE_PLUGIN, 0, "Expected usage: <xpath> <prefix> <namespace> <format> <limit>");
goto done;
@ -1363,7 +1377,7 @@ cli_pagination(clicon_handle h,
*
* Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
@ -1421,7 +1435,7 @@ cli2cbuf(clicon_handle h,
}
/* Create prepend variable string */
if ((cbpre = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if (prepend)
@ -1466,7 +1480,7 @@ cli2cbuf(clicon_handle h,
/* For lists, print cbpre before its elements */
if (yang_keyword_get(ys) == Y_LIST)
cprintf(cb, "%s\n", cbuf_get(cbpre));
cprintf(cb, "%s\n", cbuf_get(cbpre));
/* Then loop through all other (non-keys) */
xe = NULL;
while ((xe = xml_child_each(xn, xe, -1)) != NULL){
@ -1491,15 +1505,17 @@ cli2cbuf(clicon_handle h,
*
* Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] f Output FILE (eg stdout)
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
* @param[in] fn Callback to make print function
* @retval 0 OK
* @retval -1 Error
*/
static int
cli2file(clicon_handle h,
FILE *f,
FILE *f,
cxobj *xn,
char *prepend,
clicon_output_cb *fn)
@ -1548,7 +1564,7 @@ cli2file(clicon_handle h,
}
/* Create prepend variable string */
if ((cbpre = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if (prepend)
@ -1593,7 +1609,7 @@ cli2file(clicon_handle h,
/* For lists, print cbpre before its elements */
if (yang_keyword_get(ys) == Y_LIST)
(*fn)(f, "%s\n", cbuf_get(cbpre));
(*fn)(f, "%s\n", cbuf_get(cbpre));
/* Then loop through all other (non-keys) */
xe = NULL;
while ((xe = xml_child_each(xn, xe, -1)) != NULL){
@ -1618,7 +1634,7 @@ cli2file(clicon_handle h,
*
* Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] f Output FILE (eg stdout)
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
@ -1630,7 +1646,7 @@ cli2file(clicon_handle h,
*/
int
clixon_cli2file(clicon_handle h,
FILE *f,
FILE *f,
cxobj *xn,
char *prepend,
clicon_output_cb *fn,
@ -1660,7 +1676,7 @@ clixon_cli2file(clicon_handle h,
*
* Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] f Output FILE (eg stdout)
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
@ -1698,8 +1714,8 @@ clixon_cli2cbuf(clicon_handle h,
/*! CLI callback show statistics
*/
int
cli_show_statistics(clicon_handle h,
cvec *cvv,
cli_show_statistics(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
@ -1712,7 +1728,7 @@ cli_show_statistics(clicon_handle h,
parse_tree *pt;
uint64_t nr = 0;
size_t sz = 0;
if (argv != NULL && cvec_len(argv) != 1){
clicon_err(OE_PLUGIN, EINVAL, "Expected arguments: [modules]");
goto done;
@ -1734,7 +1750,7 @@ cli_show_statistics(clicon_handle h,
nr = 0; sz = 0;
pt_stats(pt, &nr, &sz);
cligen_output(stdout, "%s: nr=%" PRIu64 " size:%zu\n",
cligen_ph_name_get(ph), nr, sz);
cligen_ph_name_get(ph), nr, sz);
}
/* Backend */
cprintf(cb, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);

View file

@ -50,6 +50,7 @@ extern "C" {
*/
/*! Called when plugin loaded. Only mandadory callback. All others optional
*
* @see plginit_t
*/
int plugin_init(clicon_handle h);

View file

@ -43,10 +43,11 @@
* Types
*/
/*! Autocli list keyword type, see clixon-autocli.yang list-keyword-type
*
* Assume a YANG LIST:
* list a {
* key x;
* leaf x;
* list a {
* key x;
* leaf x;
* leaf y;
* }
* Maybe this type should be in cli_autocli.h
@ -77,7 +78,7 @@ cligen_handle cli_cligen(clicon_handle h);
/* cli_common.c */
int cli_notification_register(clicon_handle h, char *stream, enum format_enum format,
char *filter, int status,
char *filter, int status,
int (*fn)(int, void*), void *arg);
int mtpoint_paths(yang_stmt *yspec0, char *mtpoint, char *api_path_fmt1, char **api_path_fmt01);
@ -115,7 +116,7 @@ int cvec_concat_cb(cvec *cvv, cbuf *cb);
int cli_process_control(clicon_handle h, cvec *vars, cvec *argv);
/* In cli_show.c */
int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
cvec *commands, cvec *helptexts);
int clixon_cli2file(clicon_handle h, FILE *f, cxobj *xn, char *prepend, clicon_output_cb *fn, int skiptop);
int clixon_cli2cbuf(clicon_handle h, cbuf *cb, cxobj *xn, char *prepend, int skiptop);

View file

@ -46,8 +46,8 @@
* (Duplicated. Also in netconf_*.h)
*/
int netconf_xpath(cxobj *xsearch,
cxobj *xfilter,
cbuf *xf, cbuf *xf_err,
cxobj *xfilter,
cbuf *xf, cbuf *xf_err,
cxobj *xt);

View file

@ -97,16 +97,17 @@ leafstring(cxobj *x)
}
/*! Internal recursive part where configuration xml tree is pruned from filter
*
* assume parent has been selected and filter match (same name) as parent
* parent is pruned according to selection.
* @param[in] xfilter Filter xml
* @param[out] xconf Configuration xml
* @retval 0 OK
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_filter_recursive(cxobj *xfilter,
cxobj *xparent,
xml_filter_recursive(cxobj *xfilter,
cxobj *xparent,
int *remove_me)
{
cxobj *s;
@ -122,7 +123,7 @@ xml_filter_recursive(cxobj *xfilter,
*remove_me = 0;
/* 1. Check selection */
if (xml_child_nr(xfilter) == 0)
if (xml_child_nr(xfilter) == 0)
goto match;
/* Count containment/selection nodes in filter */
@ -190,6 +191,7 @@ xml_filter_recursive(cxobj *xfilter,
}
/*! Remove parts of configuration xml tree that does not match filter xml tree
*
* @param[in] xfilter Filter xml
* @param[out] xconf Configuration xml
* @retval 0 OK
@ -197,15 +199,15 @@ xml_filter_recursive(cxobj *xfilter,
* This is the top-level function, calls a recursive variant.
*/
int
xml_filter(cxobj *xfilter,
xml_filter(cxobj *xfilter,
cxobj *xconfig)
{
int retval;
int remove_s;
/* Call recursive variant */
retval = xml_filter_recursive(xfilter,
xconfig,
retval = xml_filter_recursive(xfilter,
xconfig,
&remove_s);
return retval;
}

View file

@ -41,7 +41,7 @@
/*
* Prototypes
*/
*/
int xml_filter(cxobj *xf, cxobj *xn);
#endif /* _NETCONF_FILTER_H_ */

View file

@ -99,6 +99,8 @@ static int _netconf_hello_nr = 0;
* includes any "xmlns" attributes.
* @param[in] xrpc Incoming message on the form <rpc>...
* @param[in,out] xrep Reply message on the form <rpc-reply>...
* @retval 0 OK
* @retval -1 Error
*/
static int
netconf_add_request_attr(cxobj *xrpc,
@ -133,9 +135,14 @@ netconf_add_request_attr(cxobj *xrpc,
}
/*! Process netconf hello message
*
* A server receiving a <hello> message with a <session-id> element MUST
* terminate the NETCONF session.
* @param[out] eof Request termination
* @param[in] h Clixon handle
* @param[in] xn
* @param[out] eof Request termination
* @retval 0 OK
* @retval -1 Error
*/
static int
netconf_hello_msg(clicon_handle h,
@ -152,7 +159,7 @@ netconf_hello_msg(clicon_handle h,
int foundbase_11 = 0;
char *body;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
_netconf_hello_nr++;
if (xml_find_type(xn, NULL, "session-id", CX_ELMNT) != NULL) {
clicon_err(OE_XML, errno, "Server received hello with session-id from client, terminating (see RFC 6241 Sec 8.1");
@ -172,12 +179,12 @@ netconf_hello_msg(clicon_handle h,
* event any parameters are encoded at the end of the URI string. */
if (strncmp(body, NETCONF_BASE_CAPABILITY_1_0, strlen(NETCONF_BASE_CAPABILITY_1_0)) == 0){ /* RFC 4741 */
foundbase_10++;
clicon_debug(1, "%s foundbase10", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s foundbase10", __FUNCTION__);
}
else if (strncmp(body, NETCONF_BASE_CAPABILITY_1_1, strlen(NETCONF_BASE_CAPABILITY_1_1)) == 0 &&
clicon_option_int(h, "CLICON_NETCONF_BASE_CAPABILITY") > 0){ /* RFC 6241 */
foundbase_11++;
clicon_debug(1, "%s foundbase11", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s foundbase11", __FUNCTION__);
clicon_data_int_set(h, NETCONF_FRAMING_TYPE, NETCONF_SSH_CHUNKED); /* enable chunked enc */
}
}
@ -195,6 +202,7 @@ netconf_hello_msg(clicon_handle h,
}
/*! Process incoming Netconf RPC netconf message
*
* @param[in] h Clixon handle
* @param[in] xreq XML tree containing netconf RPC message
* @param[in] yspec YANG spec
@ -223,7 +231,7 @@ netconf_rpc_message(clicon_handle h,
/* Copy attributes from incoming request to reply. Skip already present (dont overwrite) */
if (netconf_add_request_attr(xrpc, xret) < 0)
goto done;
if ((cbret = cbuf_new()) == NULL){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
@ -239,12 +247,12 @@ netconf_rpc_message(clicon_handle h,
if ((ret = xml_bind_yang_rpc(h, xrpc, yspec, &xret)) < 0)
goto done;
if (ret > 0 &&
(ret = xml_yang_validate_rpc(h, xrpc, 0, &xret)) < 0)
(ret = xml_yang_validate_rpc(h, xrpc, 0, &xret)) < 0)
goto done;
if (ret == 0){
if (netconf_add_request_attr(xrpc, xret) < 0)
goto done;
if ((cbret = cbuf_new()) == NULL){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
@ -265,7 +273,7 @@ netconf_rpc_message(clicon_handle h,
goto done;
if (netconf_add_request_attr(xrpc, xret) < 0)
goto done;
if ((cbret = cbuf_new()) == NULL){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
@ -281,7 +289,7 @@ netconf_rpc_message(clicon_handle h,
/* Copy attributes from incoming request to reply. Skip already present (dont overwrite) */
if (netconf_add_request_attr(xrpc, xc) < 0)
goto done;
if ((cbret = cbuf_new()) == NULL){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
@ -303,6 +311,7 @@ netconf_rpc_message(clicon_handle h,
}
/*! Process incoming a single netconf message parsed as XML
*
* Identify what netconf message it is
* @param[in] h Clixon handle
* @param[in] xreq XML tree containing netconf
@ -325,8 +334,8 @@ netconf_input_packet(clicon_handle h,
cxobj *xret = NULL;
netconf_framing_type framing;
clicon_debug(1, "%s", __FUNCTION__);
clicon_debug_xml(1, xreq, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clixon_debug_xml(1, xreq, "%s", __FUNCTION__);
rpcname = xml_name(xreq);
rpcprefix = xml_prefix(xreq);
framing = clicon_data_int_get(h, NETCONF_FRAMING_TYPE);
@ -339,7 +348,7 @@ netconf_input_packet(clicon_handle h,
goto done;
if (netconf_add_request_attr(xreq, xret) < 0)
goto done;
if ((cbret = cbuf_new()) == NULL){
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
@ -381,8 +390,11 @@ netconf_input_packet(clicon_handle h,
}
/*! Get netconf message: detect end-of-msg
* @param[in] s Socket where input arrived. read from this.
* @param[in] arg Clixon handle.
*
* @param[in] s Socket where input arrived. read from this.
* @param[in] arg Clixon handle.
* @retval 0 OK
* @retval -1 Error
* This routine continuously reads until no more data on s. There could
* be risk of starvation, but the netconf client does little else than
* read data so I do not see a danger of true starvation here.
@ -418,7 +430,7 @@ netconf_input_cb(int s,
unsigned char *p = buf;
ssize_t len;
size_t plen;
yspec = clicon_dbspec_yang(h);
/* Get unfinished frame */
if ((ptr = clicon_hash_value(cdat, NETCONF_FRAME_MSG, &cdatlen)) != NULL){
@ -457,14 +469,14 @@ netconf_input_cb(int s,
&eom) < 0)
goto done;
if (eom == 0){ /* frame not complete */
clicon_debug(CLIXON_DBG_DETAIL, "%s: frame: %lu", __FUNCTION__, cbuf_len(cbmsg));
clixon_debug(CLIXON_DBG_DETAIL, "%s: frame: %lu", __FUNCTION__, cbuf_len(cbmsg));
/* Extra data to read, save data and continue on next round */
if (clicon_hash_add(cdat, NETCONF_FRAME_MSG, &cbmsg, sizeof(cbmsg)) == NULL)
goto done;
cbmsg = NULL;
break;
}
clicon_debug(CLIXON_DBG_MSG, "Recv ext: %s", cbuf_get(cbmsg));
clixon_debug(CLIXON_DBG_MSG, "Recv ext: %s", cbuf_get(cbmsg));
if ((ret = netconf_input_frame2(cbmsg, YB_RPC, yspec, &xtop, &xerr)) < 0)
goto done;
cbuf_reset(cbmsg);
@ -499,7 +511,7 @@ netconf_input_cb(int s,
}
}
if (eof){ /* socket closed / read returns 0 */
clicon_debug(1, "%s len==0, closing", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s len==0, closing", __FUNCTION__);
clixon_event_unreg_fd(s, netconf_input_cb);
close(s);
clixon_exit_set(1);
@ -522,16 +534,19 @@ netconf_input_cb(int s,
}
/*! Send netconf hello message
*
* @param[in] h Clixon handle
* @param[in] s File descriptor to write on (eg 1 - stdout)
* @retval 0 OK
* @retval -1 Error
*/
static int
send_hello(clicon_handle h,
int s,
uint32_t id)
{
int retval = -1;
cbuf *cb;
int retval = -1;
cbuf *cb;
netconf_framing_type framing;
if ((cb = cbuf_new()) == NULL){
@ -553,6 +568,7 @@ send_hello(clicon_handle h,
}
/*! Clean and close all state of netconf process (but dont exit).
*
* Cannot use h after this
* @param[in] h Clixon handle
*/
@ -562,7 +578,7 @@ netconf_terminate(clicon_handle h)
yang_stmt *yspec;
cvec *nsctx;
cxobj *x;
if (clixon_exit_get() == 0)
clixon_exit_set(1);
/* Delete all plugins, and RPC callbacks */
@ -591,7 +607,7 @@ static int
netconf_signal_init (clicon_handle h)
{
int retval = -1;
if (set_signal(SIGPIPE, SIG_IGN, NULL) < 0){
clicon_err(OE_UNIX, errno, "Setting DIGPIPE signal");
goto done;
@ -606,10 +622,11 @@ timeout_fn(int s,
void *arg)
{
clicon_err(OE_EVENTS, ETIMEDOUT, "User request timeout");
return -1;
return -1;
}
/*! Usage help routine
*
* @param[in] h Clixon handle
* @param[in] argv0 command line
*/
@ -666,12 +683,12 @@ main(int argc,
size_t sz;
int config_dump = 0;
enum format_enum config_dump_format = FORMAT_XML;
/* Create handle */
if ((h = clicon_handle_init()) == NULL)
return -1;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Set username to clixon handle. Use in all communication to backend */
if ((pw = getpwuid(getuid())) == NULL){
@ -712,14 +729,14 @@ main(int argc,
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(dbg, NULL);
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clixon_debug_init(dbg, NULL);
yang_init(h);
/* Find, read and parse configfile */
if (clicon_options_main(h) < 0)
goto done;
/* Now rest of options */
optind = 1;
opterr = 0;
@ -822,23 +839,23 @@ main(int argc,
/* Setup signal handlers, int particular PIPE that occurs if backend closes / restarts */
if (netconf_signal_init(h) < 0)
goto done;
/* Initialize plugin module by creating a handle holding plugin and callback lists */
if (clixon_plugin_module_init(h) < 0)
goto done;
/* In case ietf-yang-metadata is loaded by application, handle annotation extension */
if (yang_metadata_init(h) < 0)
goto done;
goto done;
/* Create top-level yang spec and store as option */
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
clicon_dbspec_yang_set(h, yspec);
/* Load netconf plugins before yangs are loaded (eg extension callbacks) */
if ((dir = clicon_netconf_dir(h)) != NULL &&
clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
goto done;
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
if ((str = clicon_yang_main_file(h)) != NULL){
@ -865,7 +882,7 @@ main(int argc,
/* Add netconf yang spec, used by netconf client and as internal protocol */
if (netconf_module_load(h) < 0)
goto done;
/* Here all modules are loaded
/* Here all modules are loaded
* Compute and set canonical namespace context
*/
if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0)
@ -894,7 +911,7 @@ main(int argc,
if (clicon_hello_req(h, "cl:netconf", NULL, &id) < 0)
goto done;
clicon_session_id_set(h, id);
/* Send hello to northbound client
* Note that this is a violation of RDFC 6241 Sec 8.1:
* When the NETCONF session is opened, each peer(both client and server) MUST send a <hello..

View file

@ -80,13 +80,13 @@
*/
static int
netconf_get_config_subtree(clicon_handle h,
cxobj *xfilter,
netconf_get_config_subtree(clicon_handle h,
cxobj *xfilter,
cxobj **xret)
{
int retval = -1;
cxobj *xdata;
/* a subtree filter is comprised of zero or more element subtrees*/
if ((xdata = xpath_first(*xret, NULL, "/rpc-reply/data")) == NULL)
goto ok;
@ -107,9 +107,12 @@ ok:
}
/*! Get configuration
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
* @retval 0 OK
* @retval -1 Error
* @note filter type subtree and xpath is supported, but xpath is preferred, and
* better performance and tested. Please use xpath.
*
@ -155,8 +158,8 @@ ok:
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface/ipv4"/></get-config></rpc>]]>]]>
*/
static int
netconf_get_config(clicon_handle h,
cxobj *xn,
netconf_get_config(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
@ -206,13 +209,14 @@ netconf_get_config(clicon_handle h,
}
/*! Get options from netconf edit-config
*
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] op Operation type, eg merge,replace,...
* @param[out] testopt test option, eg set, test
* @param[out] erropt Error option, eg stop-on-error
* @retval -1 Fatal Error
* @retval 0 parameter error, xret returns error
* @retval 1 OK, op, testopt and erropt set
* @retval 0 parameter error, xret returns error
* @retval -1 Fatal Error
* @example
* <edit-config>
* <config>...</config>
@ -230,7 +234,7 @@ get_edit_opts(cxobj *xn,
int retval = -1;
cxobj *x;
char *optstr;
if ((x = xpath_first(xn, NULL, "test-option")) != NULL){
if ((optstr = xml_body(x)) != NULL){
if (strcmp(optstr, "test-then-set") == 0)
@ -267,6 +271,7 @@ get_edit_opts(cxobj *xn,
}
/*! Netconf edit configuration
*
Write the change on a tmp file, then load that into candidate configuration.
<edit-config>
<target>
@ -317,7 +322,7 @@ CLIXON addition:
*/
static int
netconf_edit_config(clicon_handle h,
cxobj *xn,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
@ -353,9 +358,11 @@ netconf_edit_config(clicon_handle h,
/*! Get running configuration and device state information
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
* @param[out] xret Return XML, error or OK
* @retval 0 OK
* @retval -1 Error
* @note filter type subtree and xpath is supported, but xpath is preferred, and
* better performance and tested. Please use xpath.
*
@ -364,8 +371,8 @@ netconf_edit_config(clicon_handle h,
* </get></rpc>]]>]]>
*/
static int
netconf_get(clicon_handle h,
cxobj *xn,
netconf_get(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
@ -409,11 +416,12 @@ netconf_get(clicon_handle h,
retval = 0;
done:
if(nsc)
cvec_free(nsc);
cvec_free(nsc);
return retval;
}
/*! Called when a notification has happened on backend
*
* and this session has registered for that event.
* Filter it and forward it.
<notification>
@ -436,7 +444,7 @@ netconf_get(clicon_handle h,
* beyond the scope of this document.
*/
static int
netconf_notification_cb(int s,
netconf_notification_cb(int s,
void *arg)
{
struct clicon_msg *reply = NULL;
@ -449,9 +457,9 @@ netconf_notification_cb(int s,
yang_stmt *yspec = NULL;
cvec *nsc = NULL;
int ret;
cxobj *xerr = NULL;
cxobj *xerr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* get msg (this is the reason this function is called) */
if (clicon_msg_rcv(s, NULL, 0, &reply, &eof) < 0)
goto done;
@ -464,7 +472,7 @@ netconf_notification_cb(int s,
goto done;
}
yspec = clicon_dbspec_yang(h);
if ((ret = clicon_msg_decode(reply, yspec, NULL, &xt, &xerr)) < 0)
if ((ret = clicon_msg_decode(reply, yspec, NULL, &xt, &xerr)) < 0)
goto done;
if (ret == 0){ /* XXX use xerr */
clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
@ -496,7 +504,7 @@ netconf_notification_cb(int s,
ok:
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
if (nsc)
@ -524,12 +532,12 @@ netconf_notification_cb(int s,
* @see netconf_notification_cb for asynchronous stream notifications
*/
static int
netconf_create_subscription(clicon_handle h,
cxobj *xn,
netconf_create_subscription(clicon_handle h,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
cxobj *xfilter;
cxobj *xfilter;
int s;
char *ftype;
@ -552,8 +560,8 @@ netconf_create_subscription(clicon_handle h,
goto done;
if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL)
goto ok;
if (clixon_event_reg_fd(s,
netconf_notification_cb,
if (clixon_event_reg_fd(s,
netconf_notification_cb,
h,
"notification socket") < 0)
goto done;
@ -571,15 +579,14 @@ netconf_create_subscription(clicon_handle h,
* @param[in] h clicon handle
* @param[in] xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
* @param[out] xret Return XML, error or OK
*
* @retval -1 Error
* @retval 0 OK, not found handler.
* @retval 1 OK, handler called
* @retval 0 OK, not found handler.
* @retval -1 Error
* @see netconf_input_packet Assume bind and validation made there
*/
static int
netconf_application_rpc(clicon_handle h,
cxobj *xn,
cxobj *xn,
cxobj **xret)
{
int retval = -1;
@ -593,7 +600,7 @@ netconf_application_rpc(clicon_handle h,
cbuf *cbret = NULL;
int ret;
int nr = 0;
/* First check system / netconf RPC:s */
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "cbuf_new");
@ -658,7 +665,7 @@ netconf_application_rpc(clicon_handle h,
goto done;
if (ret == 0){
if (clixon_xml2cbuf(cbret, xerr, 0, 0, NULL, -1, 0) < 0)
goto done;
goto done;
clicon_log(LOG_WARNING, "Errors in output netconf %s", cbuf_get(cbret));
goto ok;
}
@ -679,6 +686,7 @@ netconf_application_rpc(clicon_handle h,
}
/*! The central netconf rpc dispatcher. Look at first tag and dispach to sub-functions.
*
* Call plugin handler if tag not found. If not handled by any handler, return
* error.
* @param[in] h clicon handle
@ -690,7 +698,7 @@ netconf_application_rpc(clicon_handle h,
*/
int
netconf_rpc_dispatch(clicon_handle h,
cxobj *xn,
cxobj *xn,
cxobj **xret,
int *eof)
{
@ -698,7 +706,7 @@ netconf_rpc_dispatch(clicon_handle h,
cxobj *xe;
char *username;
cxobj *xa;
/* Tag username on all incoming requests in case they are forwarded as internal messages
* This may be unecesary since not all are forwarded.
* It may even be wrong if something else is done with the incoming message?
@ -721,12 +729,12 @@ netconf_rpc_dispatch(clicon_handle h,
strcmp(xml_name(xe), "kill-session") == 0 ||
strcmp(xml_name(xe), "validate") == 0 || /* :validate */
strcmp(xml_name(xe), "commit") == 0 || /* :candidate */
strcmp(xml_name(xe), "cancel-commit") == 0 ||
strcmp(xml_name(xe), "cancel-commit") == 0 ||
strcmp(xml_name(xe), "discard-changes") == 0 ||
strcmp(xml_name(xe), "action") == 0
){
if (clicon_rpc_netconf_xml(h, xml_parent(xe), xret, NULL) < 0)
goto done;
goto done;
}
else if (strcmp(xml_name(xe), "get-config") == 0){
if (netconf_get_config(h, xe, xret) < 0)
@ -743,7 +751,7 @@ netconf_rpc_dispatch(clicon_handle h,
else if (strcmp(xml_name(xe), "close-session") == 0){
*eof = 1; /* Pending close */
if (clicon_rpc_netconf_xml(h, xml_parent(xe), xret, NULL) < 0)
goto done;
goto done;
}
/* RFC 5277 :notification */
else if (strcmp(xml_name(xe), "create-subscription") == 0){

View file

@ -41,10 +41,10 @@
/*
* Prototypes
*/
*/
int
netconf_rpc_dispatch(clicon_handle h,
cxobj *xn,
cxobj *xn,
cxobj **xret,
int *eof);

View file

@ -39,7 +39,7 @@
/*
* Types
*/
struct clixon_http1_yacc {
struct clixon_http1_yacc {
const char *hy_name; /* Name of syntax (for error string) */
clicon_handle hy_h; /* Clixon handle */
restconf_conn *hy_rc; /* Connection handle */

View file

@ -75,7 +75,7 @@
#define _HY ((clixon_http1_yacc *)_hy)
#undef clixon_api_path_parsewrap
int
int
clixon_http1_parsewrap(void)
{
return 1;
@ -100,35 +100,35 @@ query [A-Za-z0-9\-\._~!$&'()*+,;=:@?/]|%[0-9a-fA-F][0-9a-fA-F]
<REQLINE,REQTARG,REQUERY,REQHTTP,FLDNAME,FLDVALUE><<EOF>> { return X_EOF; }
<REQLINE>[ ] { BEGIN(REQTARG); return SP; }
<REQLINE>{token} { clixon_http1_parselval.string = strdup(yytext);
return TOKEN; }
return TOKEN; }
<REQLINE>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
<REQTARG>\? { BEGIN(REQUERY); return QMARK; }
<REQTARG>\/ { return SLASH; }
<REQTARG>[ ] { BEGIN(REQHTTP); return SP; }
<REQTARG>{pchar}+ { clixon_http1_parselval.string = yytext;
return PCHARS; }
return PCHARS; }
<REQTARG>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
<REQUERY>\/ { return SLASH; }
<REQUERY>[ ] { BEGIN(REQHTTP); return SP; }
<REQUERY>{query}+ { clixon_http1_parselval.string = strdup(yytext);
return QUERY; }
return QUERY; }
<REQUERY>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
<REQHTTP>\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; }
<REQHTTP>\/ { return SLASH; }
<REQHTTP>\. { return DOT; }
<REQHTTP>HTTP { BEGIN(REQHTTP); return HTTP; }
<REQHTTP>[0-9] { clixon_http1_parselval.intval = atoi(yytext);
<REQHTTP>HTTP { BEGIN(REQHTTP); return HTTP; }
<REQHTTP>[0-9] { clixon_http1_parselval.intval = atoi(yytext);
return DIGIT; }
<REQHTTP>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
<FLDNAME>: { BEGIN(FLDVALUE); return COLON; }
<FLDNAME>\r\n { BEGIN(BODYM); return CRLF; _HY->hy_linenum++; }
<FLDNAME>[ \t]+ { return RWS; }
<FLDNAME>{token} { clixon_http1_parselval.string = strdup(yytext);
return TOKEN; }
<FLDNAME>{token} { clixon_http1_parselval.string = strdup(yytext);
return TOKEN; }
<FLDNAME>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
<FLDVALUE>\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; }
@ -141,7 +141,7 @@ query [A-Za-z0-9\-\._~!$&'()*+,;=:@?/]|%[0-9a-fA-F][0-9a-fA-F]
return BODY; }
<BODYM>\n { clixon_http1_parselval.string = strdup(yytext);
_HY->hy_linenum++;
return BODY; }
return BODY; }
<BODYM><<EOF>> { return X_EOF; }
%%
@ -155,7 +155,7 @@ http1_scan_init(clixon_http1_yacc *hy)
hy->hy_lexbuf = yy_scan_string(hy->hy_parse_string);
#if 1 /* XXX: just to use unput to avoid warning */
if (0)
yyunput(0, "");
yyunput(0, "");
#endif
return 0;
@ -172,4 +172,3 @@ http1_scan_exit(clixon_http1_yacc *hy)
clixon_http1_parselex_destroy(); /* modern */
return 0;
}

View file

@ -81,7 +81,7 @@
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_http1_parsetext, _HY->hy_linenum); YYERROR;}
/* add _yy to error parameters */
#define YY_(msgid) msgid
#define YY_(msgid) msgid
#include "clixon_config.h"
@ -106,29 +106,29 @@
/* Best debugging is to enable PARSE_DEBUG below and add -d to the LEX compile statement in the Makefile
* And then run the testcase with -D 1
* Disable it to stop any calls to clicon_debug. Having it on by default would mean very large debug outputs.
* Disable it to stop any calls to clixon_debug. Having it on by default would mean very large debug outputs.
*/
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG1(s, s1) clicon_debug(1,(s), (s1))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#define _PARSE_DEBUG1(s, s1) clixon_debug(1,(s), (s1))
#else
#define _PARSE_DEBUG(s)
#define _PARSE_DEBUG1(s, s1)
#endif
/*
/*
also called from yacc generated code *
*/
void
void
clixon_http1_parseerror(void *_hy,
char *s)
{
clicon_err(OE_RESTCONF, 0, "%s on line %d: %s at or before: '%s'",
char *s)
{
clicon_err(OE_RESTCONF, 0, "%s on line %d: %s at or before: '%s'",
_HY->hy_name,
_HY->hy_linenum ,
s,
clixon_http1_parsetext);
_HY->hy_linenum,
s,
clixon_http1_parsetext);
return;
}
@ -151,7 +151,7 @@ http1_parse_query(clixon_http1_yacc *hy,
int retval = -1;
restconf_stream_data *sd = NULL;
clicon_debug(1, "%s: ?%s ", __FUNCTION__, query);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: ?%s ", __FUNCTION__, query);
if ((sd = restconf_stream_find(hy->hy_rc, 0)) == NULL){
clicon_err(OE_RESTCONF, 0, "stream 0 not found");
goto done;
@ -170,7 +170,7 @@ http1_body(clixon_http1_yacc *hy,
int retval = -1;
restconf_stream_data *sd = NULL;
clicon_debug(1, "%s: %s ", __FUNCTION__, body);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %s ", __FUNCTION__, body);
if ((sd = restconf_stream_find(hy->hy_rc, 0)) == NULL){
clicon_err(OE_RESTCONF, 0, "stream 0 not found");
goto done;
@ -200,11 +200,11 @@ http1_parse_header_field(clixon_http1_yacc *hy,
return retval;
}
%}
%}
%%
/* start-line *( header-field CRLF ) CRLF [ message-body ]
/* start-line *( header-field CRLF ) CRLF [ message-body ]
* start-line = request-line / status-line (only request-line here, ignore status-line)
*/
http_message : request_line header_fields CRLF body X_EOF
@ -215,7 +215,7 @@ http_message : request_line header_fields CRLF body X_EOF
}
_PARSE_DEBUG("http-message -> request-line header-fields body");
YYACCEPT;
}
}
;
body : body BODY
@ -224,22 +224,22 @@ body : body BODY
free($2);
YYABORT;
}
else
else
free($2);
_PARSE_DEBUG("body -> body BODY");
}
| ERROR { _PARSE_DEBUG("body -> ERROR"); YYABORT; /* shouldnt happen */ }
| { _PARSE_DEBUG("body -> "); $$ = NULL; }
| ERROR { _PARSE_DEBUG("body -> ERROR"); YYABORT; /* shouldnt happen */ }
| { _PARSE_DEBUG("body -> "); $$ = NULL; }
;
/* request-line = method SP request-target SP HTTP-version CRLF */
request_line : method SP request_target SP HTTP_version CRLF
{
{
_PARSE_DEBUG("request-line -> method request-target HTTP_version CRLF");
}
;
/*
/*
The request methods defined by this specification can be found in
Section 4 of [RFC7231], along with information regarding the HTTP
http://www.iana.org/assignments/http-methods/http-methods.xhtml
@ -331,7 +331,7 @@ HTTP_version : HTTP SLASH DIGIT DOT DIGIT
/* make sanity check later */
_HY->hy_rc->rc_proto_d1 = $3;
_HY->hy_rc->rc_proto_d2 = $5;
clicon_debug(1, "clixon_http1_parse: http/%d.%d", $3, $5);
clixon_debug(CLIXON_DBG_DEFAULT, "clixon_http1_parse: http/%d.%d", $3, $5);
_PARSE_DEBUG("HTTP-version -> HTTP / DIGIT . DIGIT");
}
;
@ -388,7 +388,7 @@ field_vchars : field_vchars RWS VCHARS
RWS = 1*( SP / HTAB )
; required whitespace
*/
ows : RWS
ows : RWS
|
;

View file

@ -87,8 +87,8 @@ static const map_str2str mime_map[] = {
/*! Check if uri path denotes a data path
*
* @param[in] h Clixon handle
* @retval 0 No, not a data path, or not enabled
* @retval 1 Yes, a data path and "data" points to www-data if given
* @retval 0 No, not a data path, or not enabled
*/
int
api_path_is_data(clicon_handle h)
@ -103,7 +103,7 @@ api_path_is_data(clicon_handle h)
goto done;
if ((http_data_path = clicon_option_str(h, "CLICON_HTTP_DATA_PATH")) == NULL)
goto done;
if (strlen(path) < strlen(http_data_path))
if (strlen(path) < strlen(http_data_path))
goto done;
if (path[0] != '/')
goto done;
@ -117,6 +117,7 @@ api_path_is_data(clicon_handle h)
}
/*! Generic restconf error function on get/head request
*
* @param[in] h Clixon handle
* @param[in] req Generic http handle
* @param[in] code Error code
@ -130,7 +131,7 @@ api_http_data_err(clicon_handle h,
int retval = -1;
cbuf *cb = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -152,23 +153,24 @@ api_http_data_err(clicon_handle h,
// ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Check validity of path, may only be regular dir or file
*
* No .., soft link, ~, etc
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] prefix Prefix of path0, where to start file check
* @param[in,out] cbpath Filepath as cbuf, internal redirection may change it
* @param[out] fp Open file, if retval = 1
* @param[out] fsz Size of file, if retval = 1
* @retval -1 Error
* @retval 0 Invalid
* @retval 1 OK, fp,fsz set
* @retval 0 Invalid
* @retval -1 Error
*/
static int
http_data_check_file_path(clicon_handle h,
@ -190,7 +192,7 @@ http_data_check_file_path(clicon_handle h,
goto done;
}
p = cbuf_get(cbpath);
clicon_debug(1, "%s %s", __FUNCTION__, p);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, p);
if (strncmp(prefix, p, strlen(prefix)) != 0){
clicon_err(OE_UNIX, EINVAL, "prefix is not prefix of cbpath");
goto done;
@ -200,31 +202,31 @@ http_data_check_file_path(clicon_handle h,
p[i] = '\0';
/* Ensure not soft link */
if (lstat(p, &fstat) < 0){
clicon_debug(1, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
code = 404;
goto invalid;
}
if (!S_ISDIR(fstat.st_mode)){
clicon_debug(1, "%s Error lstat(%s): Not dir", __FUNCTION__, p);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): Not dir", __FUNCTION__, p);
code = 403;
goto invalid;
}
p[i] = '/';
}
else if (p[i] == '~'){
clicon_debug(1, "%s Error lstat(%s): ~ not allowed in file path", __FUNCTION__, p);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): ~ not allowed in file path", __FUNCTION__, p);
code = 403;
goto invalid;
}
else if (p[i] == '.' && i>strlen(prefix) && p[i-1] == '.'){
clicon_debug(1, "%s Error lstat(%s): .. not allowed in file path", __FUNCTION__, p);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): .. not allowed in file path", __FUNCTION__, p);
code = 403;
goto invalid;
}
}
/* Resulting file (ensure not soft link) */
if (lstat(p, &fstat) < 0){
clicon_debug(1, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
code = 404;
goto invalid;
}
@ -233,22 +235,22 @@ http_data_check_file_path(clicon_handle h,
if (S_ISDIR(fstat.st_mode)){
cprintf(cbpath, "/%s", HTTP_DATA_INTERNAL_REDIRECT);
p = cbuf_get(cbpath);
clicon_debug(1, "%s internal redirect: %s", __FUNCTION__, p);
clixon_debug(CLIXON_DBG_DEFAULT, "%s internal redirect: %s", __FUNCTION__, p);
if (lstat(p, &fstat) < 0){
clicon_debug(1, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
code = 404;
goto invalid;
}
}
}
#endif
if (!S_ISREG(fstat.st_mode)){
clicon_debug(1, "%s Error lstat(%s): Not regular file", __FUNCTION__, p);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): Not regular file", __FUNCTION__, p);
code = 403;
goto invalid;
}
*fsz = fstat.st_size;
if ((f = fopen(p, "rb")) == NULL){
clicon_debug(1, "%s Error fopen(%s) %s", __FUNCTION__, p, strerror(errno));
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error fopen(%s) %s", __FUNCTION__, p, strerror(errno));
code = 403;
goto invalid;
}
@ -257,17 +259,20 @@ http_data_check_file_path(clicon_handle h,
done:
return retval;
invalid:
if (api_http_data_err(h, req, code) < 0)
if (api_http_data_err(h, req, code) < 0)
goto done;
retval = 0;
goto done;
}
/*! Read file data request
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] pathname With stripped prefix (eg /data), ultimately a filename
* @param[in] head HEAD not GET
* @retval 0 OK
* @retval -1 Error
* @note: primitive file handling, just check if file exists and read it all
* XXX 1: Buffer copying once too many, see #if 0 below
*/
@ -291,7 +296,7 @@ api_http_data_file(clicon_handle h,
char *buf = NULL;
size_t sz;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((cbfile = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -304,9 +309,9 @@ api_http_data_file(clicon_handle h,
cprintf(cbfile, "%s", www_data_root);
if (pathname){
if (strlen(pathname) && pathname[0] != '/'){
clicon_debug(1, "%s Error fopen(%s) pathname not prefixed with /",
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error fopen(%s) pathname not prefixed with /",
__FUNCTION__, pathname);
if (api_http_data_err(h, req, 404) < 0)
if (api_http_data_err(h, req, 404) < 0)
goto done;
goto ok;
}
@ -333,7 +338,7 @@ api_http_data_file(clicon_handle h,
fsize = ftell(f);
/* Extra sanity check, had some problems with wrong file types */
if (fsz != fsize){
clicon_debug(1, "%s Error file %s size mismatch sz:%zu vs %li",
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error file %s size mismatch sz:%zu vs %li",
__FUNCTION__, filename, (size_t)fsz, fsize);
if (api_http_data_err(h, req, 500) < 0) /* Internal error? */
goto done;
@ -357,7 +362,7 @@ api_http_data_file(clicon_handle h,
}
sz = (size_t)ret;
if (sz != 1){
clicon_debug(1, "%s Error fread(%s) sz:%zu", __FUNCTION__, filename, sz);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error fread(%s) sz:%zu", __FUNCTION__, filename, sz);
if (api_http_data_err(h, req, 500) < 0) /* Internal error? */
goto done;
goto ok;
@ -371,7 +376,7 @@ api_http_data_file(clicon_handle h,
if (restconf_reply_send(req, 200, cbdata, head) < 0)
goto done;
cbdata = NULL; /* consumed by reply-send */
clicon_debug(1, "%s Read %s OK", __FUNCTION__, filename);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Read %s OK", __FUNCTION__, filename);
ok:
retval = 0;
done:
@ -396,10 +401,12 @@ api_http_data_file(clicon_handle h,
* 5. indata should be NULL (no write operations)
* 6. Limited media: text/html, JavaScript, image, and css
* 7. Authentication as restconf
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
* @param[in] pathname With stripped prefix (eg /data), ultimately a filename
* @retval 0 OK
* @retval -1 Error
* Need to enable clixon-restconf.yang www-data feature
*/
int
@ -416,7 +423,7 @@ api_http_data(clicon_handle h,
cbuf *indata = NULL;
char *path = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (req == NULL){
errno = EINVAL;
goto done;
@ -442,7 +449,7 @@ api_http_data(clicon_handle h,
else {
if (api_http_data_err(h, req, 405) < 0) /* method not allowed */
goto done;
goto ok;
goto ok;
}
/* 3. query parameters not accepted */
if (qvec != NULL){
@ -460,7 +467,7 @@ api_http_data(clicon_handle h,
goto done;
goto ok;
}
/* 5. Accepted media_out: should check text/html, JavaScript, image, and css
/* 5. Accepted media_out: should check text/html, JavaScript, image, and css
*/
if ((media_str = restconf_param_get(h, "HTTP_ACCEPT")) == NULL){
}
@ -491,6 +498,6 @@ api_http_data(clicon_handle h,
done:
if (path)
free(path);
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}

View file

@ -45,6 +45,7 @@ extern "C" {
* Types
*/
/*! RESTCONF media types
*
* @see http_media_map
* @note DUPLICATED in restconf_lib.h
*/

View file

@ -69,6 +69,7 @@
/*! HTTP headers done, if there is a message body coming next
*
* @param[in] req Fastcgi request handle
* @retval body Handle for body handling (in fcgi same as req)
*
@ -86,9 +87,12 @@ restconf_reply_body_start(void *req0)
}
/*! Add HTTP header field name and value to reply, fcgi specific
*
* @param[in] req Fastcgi request handle
* @param[in] name HTTP header field name
* @param[in] vfmt HTTP header field value format string w variable parameter
* @retval 0 OK
* @retval -1 Error
* @see eg RFC 7230
*/
int
@ -102,7 +106,7 @@ restconf_reply_header(void *req0,
size_t vlen;
char *value = NULL;
va_list ap;
if (req == NULL || name == NULL || vfmt == NULL){
clicon_err(OE_CFG, EINVAL, "req, name or value is NULL");
return -1;
@ -116,14 +120,14 @@ restconf_reply_header(void *req0,
goto done;
}
/* second round: compute actual value */
va_start(ap, vfmt);
va_start(ap, vfmt);
if (vsnprintf(value, vlen+1, vfmt, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
}
va_end(ap);
FCGX_FPrintF(req->out, "%s: %s\r\n", name, value);
FCGX_FPrintF(req->out, "%s: %s\r\n", name, value);
retval = 0;
done:
if (value)
@ -132,9 +136,12 @@ restconf_reply_header(void *req0,
}
/*! Add HTTP message body to reply, fcgi specific
*
* @param[in] req Fastcgi request handle
* @param[in,out] content_len This is for Content-Length header
* @param[in] bfmt HTTP message body format string w variable parameter
* @retval 0 OK
* @retval -1 Error
* @see eg RFC 7230
*/
int
@ -163,14 +170,14 @@ restconf_reply_body_add(void *req0,
goto done;
}
/* second round: compute actual body */
va_start(ap, bfmt);
va_start(ap, bfmt);
if (vsnprintf(body, blen+1, bfmt, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
}
va_end(ap);
FCGX_FPrintF(req->out, "%s", body);
FCGX_FPrintF(req->out, "%s", body);
/* Increment in/out Content-Length parameter */
if (content_len){
sz = strlen(body);
@ -184,12 +191,14 @@ restconf_reply_body_add(void *req0,
}
/*! Send HTTP reply with potential message body
* @param[in] req Fastcgi request handle
* @param[in] code Status code
* @param[in] cb Body as a cbuf if non-NULL. Note is consumed
* @param[in] head Only send headers, dont send body.
*
*
* Prerequisites: status code set, headers given, body if wanted set
* @param[in] req Fastcgi request handle
* @param[in] code Status code
* @param[in] cb Body as a cbuf if non-NULL. Note is consumed
* @param[in] head Only send headers, dont send body.
* @retval 0 OK
* @retval -1 Error
*/
int
restconf_reply_send(void *req0,
@ -222,6 +231,7 @@ restconf_reply_send(void *req0,
}
/*! Get input data from http request, eg such as curl -X PUT http://... <indata>
*
* @param[in] req Fastcgi request handle
* @retval indata
* @retval NULL Error

View file

@ -65,9 +65,12 @@
#include "restconf_native.h"
/*! Add HTTP header field name and value to reply
*
* @param[in] req request handle
* @param[in] name HTTP header field name
* @param[in] vfmt HTTP header field value format string w variable parameter
* @retval 0 OK
* @retval -1 Error
* @see eg RFC 7230
*/
int
@ -83,7 +86,7 @@ restconf_reply_header(void *req0,
char *value = NULL;
va_list ap;
clicon_debug(1, "%s %s", __FUNCTION__, name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, name);
if (sd == NULL || name == NULL || vfmt == NULL){
clicon_err(OE_CFG, EINVAL, "sd, name or value is NULL");
goto done;
@ -102,7 +105,7 @@ restconf_reply_header(void *req0,
goto done;
}
/* Second round: compute actual value */
va_start(ap, vfmt);
va_start(ap, vfmt);
if (vsnprintf(value, vlen+1, vfmt, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
@ -121,11 +124,13 @@ restconf_reply_header(void *req0,
}
/*! Send HTTP reply with potential message body
* @param[in] req http request handle
* @param[in] code Status code
* @param[in] cb Body as a cbuf if non-NULL. Note: is consumed
* @param[in] head Only send headers, dont send body.
*
*
* @param[in] req http request handle
* @param[in] code Status code
* @param[in] cb Body as a cbuf if non-NULL. Note: is consumed
* @param[in] head Only send headers, dont send body.
* @retval 0 OK
* @retval -1 Error
* Prerequisites: status code set, headers given, body if wanted set
*/
int
@ -137,7 +142,7 @@ restconf_reply_send(void *req0,
int retval = -1;
restconf_stream_data *sd = (restconf_stream_data *)req0;
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
clixon_debug(CLIXON_DBG_DEFAULT, "%s code:%d", __FUNCTION__, code);
if (sd == NULL){
clicon_err(OE_CFG, EINVAL, "sd is NULL");
goto done;
@ -145,7 +150,7 @@ restconf_reply_send(void *req0,
sd->sd_code = code;
if (cb != NULL){
if (cbuf_len(cb)){
sd->sd_body_len = cbuf_len(cb);
sd->sd_body_len = cbuf_len(cb);
if (head){
cbuf_free(cb);
}
@ -156,17 +161,18 @@ restconf_reply_send(void *req0,
}
else{
cbuf_free(cb);
sd->sd_body_len = 0;
sd->sd_body_len = 0;
}
}
else
sd->sd_body_len = 0;
sd->sd_body_len = 0;
retval = 0;
done:
return retval;
}
/*! Get input data from http request, eg such as curl -X PUT http://... <indata>
*
* @param[in] req Request handle
* @note: reuses cbuf from stream-data
*/
@ -175,7 +181,7 @@ restconf_get_indata(void *req0)
{
restconf_stream_data *sd = (restconf_stream_data *)req0;
cbuf *cb = NULL;
if (sd == NULL){
clicon_err(OE_CFG, EINVAL, "sd is NULL");
goto done;

View file

@ -70,10 +70,13 @@
#include "restconf_err.h"
/*! HTTP error 405 Not Allowed
*
* @param[in] req Generic http handle
* @param[in] allow Which methods are allowed
* @param[in] pretty Pretty-print of reply
* @param[in] media_out Restconf output media
* @retval 0 OK
* @retval -1 Error
*/
int
restconf_method_notallowed(clicon_handle h,
@ -100,7 +103,10 @@ restconf_method_notallowed(clicon_handle h,
}
/*! HTTP error 415 Unsupported media
*
* @param[in] req Generic http handle
* @retval 0 OK
* @retval -1 Error
* RFC8040, section 5.2:
* If the server does not support the requested input encoding for a request, then it MUST
* return an error response with a "415 Unsupported Media Type" status-line
@ -117,7 +123,7 @@ restconf_unsupported_media(clicon_handle h,
if (netconf_operation_not_supported_xml(&xerr, "protocol", "Unsupported Media Type") < 0)
goto done;
/* override with 415 netconf->restoconf translation which gives a 405 */
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
goto done;
retval = 0;
done:
@ -129,7 +135,9 @@ restconf_unsupported_media(clicon_handle h,
/*! HTTP error 406 Not acceptable
*
* @param[in] req Generic http handle
* RFC8040, section 5.2:
* @retval 0 OK
* @retval -1 Error
* @see RFC8040, section 5.2:
* If the server does not support any of the requested output encodings for a request, then it MUST
* return an error response with a "406 Not Acceptable" status-line.
*/
@ -145,7 +153,7 @@ restconf_not_acceptable(clicon_handle h,
if (netconf_operation_not_supported_xml(&xerr, "protocol", "Unacceptable output encoding") < 0)
goto done;
/* Override with 415 netconf->restoconf translation which gives a 405 */
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
goto done;
if (restconf_reply_send(req, 415, NULL, 0) < 0)
goto done;
@ -179,6 +187,7 @@ restconf_notimplemented(clicon_handle h,
}
/*! Generic restconf error function on get/head request
*
* @param[in] h Clixon handle
* @param[in] req Generic http handle
* @param[in] xerr XML error message (eg from backend, or from a clixon_netconf_lib function)
@ -186,6 +195,8 @@ restconf_notimplemented(clicon_handle h,
* @param[in] media Output media
* @param[in] code If 0 use rfc8040 sec 7 netconf2restconf error-tag mapping
* otherwise use this code
* @retval 0 OK
* @retval -1 Error
* xerr should be on the form: <rpc-error>... otherwise an internal error is generated
* @note there are special cases see code
*/
@ -202,12 +213,12 @@ api_return_err(clicon_handle h,
cbuf *cberr = NULL;
cxobj *xtag;
char *tagstr;
int code;
int code;
cxobj *xerr2 = NULL;
cxobj *xmsg;
char *mb;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -238,7 +249,7 @@ api_return_err(clicon_handle h,
}
}
#if 1
clicon_debug_xml(1, xerr, "%s Send error:", __FUNCTION__);
clixon_debug_xml(CLIXON_DBG_DEFAULT, xerr, "%s Send error:", __FUNCTION__);
#endif
if (xml_name_set(xerr, "error") < 0)
goto done;
@ -265,17 +276,17 @@ api_return_err(clicon_handle h,
if (strcmp(tagstr, "invalid-value") == 0 &&
(xmsg = xpath_first(xerr, NULL, "error-message")) != NULL &&
(mb = xml_body(xmsg)) != NULL &&
strcmp(mb, "Invalid HTTP data method") == 0)
strcmp(mb, "Invalid HTTP data method") == 0)
code = 404; /* Not found */
}
}
}
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media)) < 0) // XXX
goto done;
switch (media){
case YANG_DATA_XML:
case YANG_PATCH_XML:
case YANG_PAGINATION_XML:
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
clixon_debug(CLIXON_DBG_DEFAULT, "%s code:%d", __FUNCTION__, code);
if (pretty){
cprintf(cb, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">\n");
if (clixon_xml2cbuf(cb, xerr, 2, pretty, NULL, -1, 0) < 0)
@ -291,7 +302,7 @@ api_return_err(clicon_handle h,
break;
case YANG_DATA_JSON:
case YANG_PATCH_JSON:
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
clixon_debug(CLIXON_DBG_DEFAULT, "%s code:%d", __FUNCTION__, code);
if (pretty){
cprintf(cb, "{\n\"ietf-restconf:errors\" : ");
if (clixon_json2cbuf(cb, xerr, pretty, 0, 0) < 0)
@ -318,7 +329,7 @@ api_return_err(clicon_handle h,
// ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
if (cberr)
@ -337,6 +348,8 @@ api_return_err(clicon_handle h,
* @param[in] media Output media
* @param[in] code If 0 use rfc8040 sec 7 netconf2restconf error-tag mapping
* otherwise use this code
* @retval 0 OK
* @retval -1 Error
* @see api_return_err where top level is expected to be <rpc-error>
*/
int

View file

@ -77,6 +77,7 @@
* entries in the struct below.
*/
/*! Backend specific handle added to header CLICON handle
*
* This file should only contain access functions for the _specific_
* entries in the struct below.
* @note The top part must be equivalent to struct clicon_handle in clixon_handle.c
@ -88,7 +89,7 @@ struct restconf_handle {
clicon_hash_t *rh_data; /* internal clicon data (HDR) */
clicon_hash_t *rh_db_elmnt; /* xml datastore element cache data */
event_stream_t *rh_stream; /* notification streams, see clixon_stream.[ch] */
/* ------ end of common handle ------ */
clicon_hash_t *rh_params; /* restconf parameters, including http headers */
clixon_auth_type_t rh_auth_type; /* authentication type */
@ -110,6 +111,7 @@ restconf_handle_init(void)
}
/*! Deallocates a backend handle, including all client structs
*
* @note: handle 'h' cannot be used in calls after this
* @see backend_client_rm
*/
@ -117,7 +119,7 @@ int
restconf_handle_exit(clicon_handle h)
{
struct restconf_handle *rh = handle(h);
if (rh->rh_fcgi_socket)
free(rh->rh_fcgi_socket);
clicon_handle_exit(h); /* frees h and options (and streams) */
@ -125,7 +127,8 @@ restconf_handle_exit(clicon_handle h)
}
/*! Get restconf http parameter
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @retval val Data value as string
* Currently using clixon runtime data but there is risk for colliding names
@ -142,7 +145,8 @@ restconf_param_get(clicon_handle h,
}
/*! Set restconf http parameter
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[in] val Data value as null-terminated string
* @retval 0 OK
@ -156,7 +160,7 @@ restconf_param_set(clicon_handle h,
{
struct restconf_handle *rh = handle(h);
clicon_debug(1, "%s: %s=%s", __FUNCTION__, param, val);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %s=%s", __FUNCTION__, param, val);
if (rh->rh_params == NULL)
if ((rh->rh_params = clicon_hash_init()) == NULL)
return -1;
@ -164,7 +168,8 @@ restconf_param_set(clicon_handle h,
}
/*! Delete all restconf http parameter
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @retval 0 OK
* @retval -1 Error
@ -175,7 +180,7 @@ restconf_param_del_all(clicon_handle h)
{
int retval = -1;
struct restconf_handle *rh = handle(h);
if (rh->rh_params != NULL){
if (clicon_hash_free(rh->rh_params) < 0)
goto done;
@ -187,7 +192,8 @@ restconf_param_del_all(clicon_handle h)
}
/*! Get restconf http parameter
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval auth_type
*/
clixon_auth_type_t
@ -199,7 +205,8 @@ restconf_auth_type_get(clicon_handle h)
}
/*! Set restconf http parameter
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[in] val Data value as null-terminated string
* @retval 0 OK
@ -217,7 +224,8 @@ restconf_auth_type_set(clicon_handle h,
}
/*! Get restconf pretty-print (for replies)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval pretty
*/
int
@ -229,7 +237,8 @@ restconf_pretty_get(clicon_handle h)
}
/*! Set restconf pretty-print
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] pretty 0 or 1
* @retval 0 OK
* @retval -1 Error
@ -245,6 +254,7 @@ restconf_pretty_set(clicon_handle h,
}
/*! Get restconf http-data
*
* @param[in] h Clixon handle
* @retval 0 Yes, http-data enabled
* @retval 1 No, http-data disabled
@ -258,6 +268,7 @@ restconf_http_data_get(clicon_handle h)
}
/*! Set restconf http-data
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
@ -273,7 +284,8 @@ restconf_http_data_set(clicon_handle h,
}
/*! Get restconf fcgi socket path
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval socketpath
*/
char*
@ -285,7 +297,8 @@ restconf_fcgi_socket_get(clicon_handle h)
}
/*! Set restconf fcgi socketpath
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[in] val Data value as null-terminated string
* @retval 0 OK

View file

@ -69,7 +69,7 @@
#include "clixon_http_data.h"
/* Size of xml read buffer */
#define BUFLEN 1024
#define BUFLEN 1024
/*! HTTP/1 parsing function. Input is string and side-effect is populating connection structs
*
@ -80,7 +80,7 @@
* @retval 0 Parse OK
* @retval -1 Error with clicon_err called.
*/
static int
static int
_http1_parse(clicon_handle h,
restconf_conn *rc,
char *str,
@ -90,7 +90,7 @@ _http1_parse(clicon_handle h,
clixon_http1_yacc hy = {0,};
int ret;
clicon_debug(1, "%s:\n%s", __FUNCTION__, str);
clixon_debug(CLIXON_DBG_DEFAULT, "%s:\n%s", __FUNCTION__, str);
if (strlen(str) == 0)
goto ok;
hy.hy_parse_string = str;
@ -119,7 +119,7 @@ _http1_parse(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}
@ -147,7 +147,7 @@ clixon_http1_parse_file(clicon_handle h,
int len = 0;
int oldbuflen;
clicon_debug(1, "%s %s", __FUNCTION__, filename);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, filename);
if (f == NULL){
clicon_err(OE_RESTCONF, EINVAL, "f is NULL");
goto done;
@ -197,7 +197,7 @@ clixon_http1_parse_file(clicon_handle h,
* @retval 0 Parse OK
* @retval -1 Error with clicon_err called.
*/
int
int
clixon_http1_parse_string(clicon_handle h,
restconf_conn *rc,
char *str)
@ -217,7 +217,7 @@ clixon_http1_parse_string(clicon_handle h,
* @note Had preferred to do this without copying, OR
* input flex with a non-null terminated string
*/
int
int
clixon_http1_parse_buf(clicon_handle h,
restconf_conn *rc,
char *buf,
@ -225,7 +225,7 @@ clixon_http1_parse_buf(clicon_handle h,
{
char *str = NULL;
int ret;
if ((str = malloc(n+1)) == NULL){
clicon_err(OE_RESTCONF, errno, "malloc");
return -1;
@ -239,6 +239,7 @@ clixon_http1_parse_buf(clicon_handle h,
#ifdef HAVE_LIBNGHTTP2
/*! Check http/1 UPGRADE to http/2
*
* If upgrade headers are encountered AND http/2 is configured, then
* - add upgrade headers or signal error
* - set http2 flag get settings to and signal to upper layer to do the actual transition.
@ -256,13 +257,13 @@ http1_upgrade_http2(clicon_handle h,
char *str;
char *settings;
cxobj *xerr = NULL;
if ((str = restconf_param_get(h, "HTTP_UPGRADE")) != NULL &&
clicon_option_bool(h, "CLICON_RESTCONF_HTTP2_PLAIN") == 1){
/* Only accept "h2c" */
if (strcmp(str, "h2c") != 0){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid upgrade token") < 0)
goto done;
goto done;
if (api_return_err0(h, sd, xerr, 1, YANG_DATA_JSON, 0) < 0)
goto done;
if (xerr)
@ -301,7 +302,7 @@ restconf_http1_reply(restconf_conn *rc,
int retval = -1;
cg_var *cv;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* If body, add a content-length header
* A server MUST NOT send a Content-Length header field in any response
* with a status code of 1xx (Informational) or 204 (No Content). A
@ -311,7 +312,7 @@ restconf_http1_reply(restconf_conn *rc,
*/
if (sd->sd_code != 204 && sd->sd_code > 199)
if (restconf_reply_header(sd, "Content-Length", "%zu", sd->sd_body_len) < 0)
goto done;
goto done;
/* Create reply and write headers */
#if 0 /* XXX need some keep-alive logic here */
/* protocol is HTTP/1.0 and clients wants to keep established */
@ -342,9 +343,12 @@ restconf_http1_reply(restconf_conn *rc,
return retval;
}
/*!
/*! restconf http1 path root
*
* @param[in] h Clixon handle
* @param[in] rc Clixon request connect pointer
* @retval 0 OK
* @retval -1 Error
*/
int
restconf_http1_path_root(clicon_handle h,
@ -360,8 +364,8 @@ restconf_http1_path_root(clicon_handle h,
#ifdef HAVE_LIBNGHTTP2
int ret;
#endif
clicon_debug(1, "------------");
clixon_debug(CLIXON_DBG_DEFAULT, "------------");
pretty = restconf_pretty_get(h);
if ((sd = restconf_stream_find(rc, 0)) == NULL){
clicon_err(OE_RESTCONF, EINVAL, "No stream_data");
@ -392,7 +396,7 @@ restconf_http1_path_root(clicon_handle h,
*/
if (sd->sd_path != NULL){
free(sd->sd_path);
sd->sd_path = NULL;
sd->sd_path = NULL;
}
#endif
if ((sd->sd_path = restconf_uripath(rc->rc_h)) == NULL)
@ -459,7 +463,7 @@ restconf_http1_path_root(clicon_handle h,
goto done;
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (subject)
free(subject);
if (xerr)
@ -486,7 +490,7 @@ http1_check_expect(clicon_handle h,
{
int retval = -1;
char *val;
if ((val = restconf_param_get(h, "HTTP_EXPECT")) != NULL &&
strcmp(val, "100-continue") == 0){ /* just drop if not well-formed */
sd->sd_code = 100;
@ -521,7 +525,7 @@ http1_check_content_length(clicon_handle h,
int retval = -1;
char *val;
int len;
if ((val = restconf_param_get(h, "HTTP_CONTENT_LENGTH")) == NULL ||
(len = atoi(val)) == 0)
*status = 0;

View file

@ -125,7 +125,7 @@ Mapping netconf error-tag -> status code
static const map_str2int netconf_restconf_map[] = {
{"in-use", 409},
{"invalid-value", 400}, /* or 404 special case if msg is: "Invalid HTTP data method" handled in api_return_err */
{"invalid-value", 404},
{"invalid-value", 404},
{"invalid-value", 406},
{"too-big", 413}, /* request */
{"too-big", 400}, /* response */
@ -137,7 +137,7 @@ static const map_str2int netconf_restconf_map[] = {
{"unknown-element", 400},
{"unknown-namespace", 400},
{"access-denied", 403}, /* or 401 special case if msg is: "The requested URL was unauthorized" handled in api_return_err */
{"access-denied", 401},
{"access-denied", 401},
{"lock-denied", 409},
{"resource-denied", 409},
{"rollback-failed", 500},
@ -157,7 +157,7 @@ static const map_str2int netconf_restconf_map[] = {
static const map_str2int http_reason_phrase_map[] = {
{"Continue", 100},
{"Switching Protocols", 101},
{"OK", 200},
{"OK", 200},
{"Created", 201},
{"Accepted", 202},
{"Non-Authoritative Information", 203},
@ -215,7 +215,7 @@ static const map_str2int http_media_map[] = {
static const map_str2int http_proto_map[] = {
{"http/1.0", HTTP_10},
{"http/1.1", HTTP_11},
{"http/2", HTTP_2},
{"http/2", HTTP_2},
{NULL, -1}
};
@ -262,7 +262,7 @@ restconf_proto2str(int proto)
* media-type = type "/" subtype *( OWS ";" OWS parameter )
* type = token
* subtype = token
*
*
*/
restconf_media
restconf_content_type(clicon_handle h)
@ -291,7 +291,7 @@ restconf_convert_hdr(clicon_handle h,
int i;
char c;
size_t len;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -322,10 +322,12 @@ restconf_convert_hdr(clicon_handle h,
* @param[in] cookiestr cookie string according to rfc6265 (modified)
* @param[in] attribute cookie attribute
* @param[out] val malloced cookie value, free with free()
* @retval 0 OK
* @retval -1 Error
*/
int
get_user_cookie(char *cookiestr,
char *attribute,
get_user_cookie(char *cookiestr,
char *attribute,
char **val)
{
int retval = -1;
@ -345,7 +347,7 @@ get_user_cookie(char *cookiestr,
return retval;
}
/*! Clean and close all state of restconf process (but dont exit).
/*! Clean and close all state of restconf process (but dont exit).
*
* Cannot use h after this
* @param[in] h Clixon handle
@ -358,7 +360,7 @@ restconf_terminate(clicon_handle h)
cxobj *x;
int fs; /* fgcx socket */
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((fs = clicon_socket_get(h)) != -1)
close(fs);
/* Delete all plugins, and RPC callbacks */
@ -376,8 +378,8 @@ restconf_terminate(clicon_handle h)
xpath_optimize_exit();
restconf_handle_exit(h);
clixon_err_exit();
clicon_debug(1, "%s pid:%u done", __FUNCTION__, getpid());
clicon_log_exit(); /* Must be after last clicon_debug */
clixon_debug(CLIXON_DBG_DEFAULT, "%s pid:%u done", __FUNCTION__, getpid());
clicon_log_exit(); /* Must be after last clixon_debug */
return 0;
}
@ -492,10 +494,10 @@ restconf_insert_attributes(cxobj *xdata,
/*! Callback for yang extensions ietf-restconf:yang-data
*
* @param[in] h Clixon handle
* @param[in] yext Yang node of extension
* @param[in] yext Yang node of extension
* @param[in] ys Yang node of (unknown) statement belonging to extension
* @retval 0 OK, all callbacks executed OK
* @retval -1 Error in one callback
* @retval 0 OK, all callbacks executed OK
* @retval -1 Error in one callback
* @note This extension adds semantics to YANG according to RFC8040 as follows:
* - The list-stmt is not required to have a key-stmt defined.(NB!!)
* - The if-feature-stmt is ignored if present.
@ -516,13 +518,13 @@ restconf_main_extension_cb(clicon_handle h,
yang_stmt *ymod;
yang_stmt *yc;
yang_stmt *yn = NULL;
ymod = ys_module(yext);
modname = yang_argument_get(ymod);
extname = yang_argument_get(yext);
if (strcmp(modname, "ietf-restconf") != 0 || strcmp(extname, "yang-data") != 0)
goto ok;
clicon_debug(1, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
if ((yc = yang_find(ys, 0, NULL)) == NULL)
goto ok;
if ((yn = ys_dup(yc)) == NULL)
@ -566,7 +568,9 @@ restconf_uripath(clicon_handle h)
/*! Drop privileges from root to user (or already at user)
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* Group set to CLICON_SOCK_GROUP to communicate with backend
*/
int
@ -579,8 +583,8 @@ restconf_drop_privileges(clicon_handle h)
gid_t gid = -1;
char *user;
enum priv_mode_t priv_mode = PM_NONE;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* Sanity check: backend group exists */
if ((group = clicon_sock_group(h)) == NULL){
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
@ -635,7 +639,7 @@ restconf_drop_privileges(clicon_handle h)
case PM_NONE:
break; /* catched above */
}
clicon_debug(1, "%s dropped privileges from root to %s(%d)",
clixon_debug(CLIXON_DBG_DEFAULT, "%s dropped privileges from root to %s(%d)",
__FUNCTION__, user, newuid);
ok:
retval = 0;
@ -643,8 +647,9 @@ restconf_drop_privileges(clicon_handle h)
return retval;
}
/*!
* @param[in] h Clicon handle
/*! restconf auth cb
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] pretty Pretty-print
* @param[in] media_out Restconf output media
@ -666,9 +671,9 @@ restconf_authentication_cb(clicon_handle h,
cxobj *xret = NULL;
cxobj *xerr;
char *anonymous = NULL;
auth_type = restconf_auth_type_get(h);
clicon_debug(1, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
clixon_debug(CLIXON_DBG_DEFAULT, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
ret = 0;
authenticated = 0;
/* ret: -1 Error, 0: Ignore/not handled, 1: OK see authenticated parameter */
@ -689,7 +694,7 @@ restconf_authentication_cb(clicon_handle h,
if ((anonymous = clicon_option_str(h, "CLICON_ANONYMOUS_USER")) == NULL){
break; /* not authenticated */
}
clicon_username_set(h, anonymous);
clicon_username_set(h, anonymous);
authenticated = 1;
break;
case CLIXON_AUTH_CLIENT_CERTIFICATE: {
@ -701,7 +706,7 @@ restconf_authentication_cb(clicon_handle h,
}
break;
}
case CLIXON_AUTH_USER:
case CLIXON_AUTH_USER:
authenticated = 0;
break;
}
@ -720,7 +725,7 @@ restconf_authentication_cb(clicon_handle h,
/* If set but no user, set a dummy user */
retval = 1;
done:
clicon_debug(1, "%s retval:%d authenticated:%d user:%s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d authenticated:%d user:%s",
__FUNCTION__, retval, authenticated, clicon_username_get(h));
if (username)
free(username);
@ -752,7 +757,7 @@ restconf_config_init(clicon_handle h,
int auth_type;
yang_stmt *yspec;
yang_stmt *y;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -763,7 +768,7 @@ restconf_config_init(clicon_handle h,
if ((x = xpath_first(xrestconf, nsc, "enable")) != NULL &&
(enable = xml_body(x)) != NULL){
if (strcmp(enable, "false") == 0){
clicon_debug(1, "%s restconf disabled", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s restconf disabled", __FUNCTION__);
goto disable;
}
}
@ -794,7 +799,7 @@ restconf_config_init(clicon_handle h,
strcmp(bstr, "true") == 0) {
restconf_http_data_set(h, 1);
}
else
else
restconf_http_data_set(h, 0);
/* Check if fcgi-socket is true and that feature is enabled
@ -817,14 +822,16 @@ restconf_config_init(clicon_handle h,
}
/*! Create and bind restconf socket
*
*
* @param[in] netns0 Network namespace, special value "default" is same as NULL
* @param[in] addrstr Address as string, eg "0.0.0.0", "::"
* @param[in] addrtype One of inet:ipv4-address or inet:ipv6-address
* @param[in] port TCP port
* @param[in] backlog Listen backlog, queie of pending connections
* @param[in] flags Socket flags OR:ed in with the socket(2) type parameter
* @param[in] backlog Listen backlog, queie of pending connections
* @param[in] flags Socket flags OR:ed in with the socket(2) type parameter
* @param[out] ss Server socket (bound for accept)
* @retval 0 OK
* @retval -1 Error
*/
int
restconf_socket_init(const char *netns0,
@ -841,7 +848,7 @@ restconf_socket_init(const char *netns0,
size_t sa_len;
const char *netns;
clicon_debug(1, "%s %s %s %s %hu", __FUNCTION__, netns0, addrtype, addrstr, port);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %s %s %hu", __FUNCTION__, netns0, addrtype, addrstr, port);
/* netns default -> NULL */
if (netns0 != NULL && strcmp(netns0, RESTCONF_NETNS_DEFAULT)==0)
netns = NULL;
@ -851,10 +858,10 @@ restconf_socket_init(const char *netns0,
goto done;
if (clixon_netns_socket(netns, sa, sa_len, backlog, flags, addrstr, ss) < 0)
goto done;
clicon_debug(1, "%s ss=%d", __FUNCTION__, *ss);
clixon_debug(CLIXON_DBG_DEFAULT, "%s ss=%d", __FUNCTION__, *ss);
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}

View file

@ -45,6 +45,7 @@ extern "C" {
* Types
*/
/*! RESTCONF media types
*
* @see http_media_map
* @note DUPLICATED in clixon_restconf.h
*/
@ -76,7 +77,7 @@ enum restconf_http_proto{
HTTP_2
};
typedef enum restconf_http_proto restconf_http_proto;
/*
* Prototypes
*/

View file

@ -91,8 +91,11 @@
#define RESTCONF_OPTS "hD:f:E:l:C:p:d:y:a:u:rW:R:o:"
/*! Convert FCGI parameters to clixon runtime data
*
* @param[in] h Clixon handle
* @param[in] envp Fastcgi request handle parameter array on the format "<param>=<value>"
* @retval 0 OK
* @retval -1 Error
* @see https://nginx.org/en/docs/http/ngx_http_core_module.html#var_https
*/
static int
@ -104,7 +107,7 @@ fcgi_params_set(clicon_handle h,
char *param = NULL;
char *val = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
for (i = 0; envp[i] != NULL; i++){ /* on the form <param>=<value> */
if (clixon_strsplit(envp[i], '=', &param, &val) < 0)
goto done;
@ -121,7 +124,7 @@ fcgi_params_set(clicon_handle h,
}
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}
@ -134,7 +137,7 @@ restconf_main_config(clicon_handle h,
{
int retval = -1;
struct passwd *pw;
cxobj *xconfig = NULL;
cxobj *xconfig = NULL;
cxobj *xrestconf = NULL;
uint32_t id = 0;
cxobj *xerr = NULL;
@ -144,7 +147,7 @@ restconf_main_config(clicon_handle h,
/* 1. try inline configure option */
if (inline_config != NULL && strlen(inline_config)){
clicon_debug(1, "restconf_main_fcgi using restconf inline config");
clixon_debug(CLIXON_DBG_DEFAULT, "restconf_main_fcgi using restconf inline config");
if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf, &xerr)) < 0)
goto done;
if (ret == 0){
@ -217,19 +220,19 @@ static clicon_handle _CLICON_HANDLE = NULL;
*/
static int _MYSOCK;
/*! Signall terminates process
/*! Signal terminates process
*/
static void
restconf_sig_term(int arg)
{
static int i=0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (i++ == 0)
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
__PROGRAM__, __FUNCTION__, getpid(), arg);
else{
clicon_debug(1, "%s done", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s done", __FUNCTION__);
exit(-1);
}
@ -237,11 +240,12 @@ restconf_sig_term(int arg)
* is entered, it will terminate.
* However there may be a case of sockets closing rather abruptly for clients
*/
clixon_exit_set(1);
clixon_exit_set(1);
close(_MYSOCK);
}
/*! Reap stream child
*
* XXX The -1 should be changed to proper pid, see eg clixon_process_waitpid
*/
static void
@ -255,8 +259,9 @@ restconf_sig_child(int arg)
}
/*! Usage help routine
*
* @param[in] h Clixon handle
* @param[in] argv0 command line
* @param[in] h Clicon handle
*/
static void
usage(clicon_handle h,
@ -285,9 +290,9 @@ usage(clicon_handle h,
}
/*! Main routine for fastcgi restconf */
int
main(int argc,
char **argv)
int
main(int argc,
char **argv)
{
int retval = -1;
int sock;
@ -318,7 +323,7 @@ main(int argc,
enum format_enum config_dump_format = FORMAT_XML;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Create handle */
if ((h = restconf_handle_init()) == NULL)
@ -355,12 +360,12 @@ main(int argc,
break;
} /* switch getopt */
/*
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(dbg, NULL);
clixon_debug_init(dbg, NULL);
clicon_log(LOG_NOTICE, "%s fcgi: %u Started", __PROGRAM__, getpid());
if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){
clicon_err(OE_DAEMON, errno, "Setting signal");
@ -450,10 +455,10 @@ main(int argc,
if ((sz = clicon_option_int(h, "CLICON_LOG_STRING_LIMIT")) != 0)
clicon_log_string_limit_set(sz);
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
xml_nsctx_namespace_netconf_default(h);
/* Add (hardcoded) netconf features in case ietf-netconf loaded here
* Otherwise it is loaded in netconf_module_load below
*/
@ -470,7 +475,7 @@ main(int argc,
goto done;
/* In case ietf-yang-metadata is loaded by application, handle annotation extension */
if (yang_metadata_init(h) < 0)
goto done;
goto done;
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
if ((dir = clicon_restconf_dir(h)) != NULL)
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
@ -510,7 +515,7 @@ main(int argc,
/* Load yang restconf module */
if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0)
goto done;
#ifdef CLIXON_YANG_PATCH
/* Load yang restconf patch module */
if (yang_spec_parse_module(h, "ietf-yang-patch", NULL, yspec)< 0)
@ -520,7 +525,7 @@ main(int argc,
/* Add netconf yang spec, used as internal protocol */
if (netconf_module_load(h) < 0)
goto done;
/* Add system modules */
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0)
@ -561,7 +566,7 @@ main(int argc,
clicon_err(OE_CFG, errno, "FCGX_Init");
goto done;
}
clicon_debug(1, "restconf_main: Opening FCGX socket: %s", sockpath);
clixon_debug(CLIXON_DBG_DEFAULT, "restconf_main: Opening FCGX socket: %s", sockpath);
if ((sock = FCGX_OpenSocket(sockpath, 10)) < 0){
clicon_err(OE_CFG, errno, "FCGX_OpenSocket");
goto done;
@ -596,7 +601,7 @@ main(int argc,
* @see clicon_hello_req
*/
clicon_data_set(h, "session-transport", "cl:restconf");
if (FCGX_InitRequest(req, sock, 0) != 0){
clicon_err(OE_CFG, errno, "FCGX_InitRequest");
goto done;
@ -608,7 +613,7 @@ main(int argc,
clicon_err(OE_CFG, errno, "FCGX_Accept_r");
goto done;
}
clicon_debug(1, "------------");
clixon_debug(CLIXON_DBG_DEFAULT, "------------");
/* Translate from FCGI parameter form to Clixon runtime data
* XXX: potential name collision?
@ -616,7 +621,7 @@ main(int argc,
if (fcgi_params_set(h, req->envp) < 0)
goto done;
if ((path = restconf_param_get(h, "REQUEST_URI")) == NULL){
clicon_debug(1, "NULL URI");
clixon_debug(CLIXON_DBG_DEFAULT, "NULL URI");
}
else {
/* Matching algorithm:
@ -637,7 +642,7 @@ main(int argc,
if (uri_str2cvec(query, '&', '=', 1, &qvec) < 0)
goto done;
if (api_root_restconf(h, req, qvec) < 0)
goto done;
goto done;
}
else if (api_path_is_stream(h)){
query = restconf_param_get(h, "QUERY_STRING");
@ -648,9 +653,9 @@ main(int argc,
(void)api_stream(h, req, qvec, &finish);
}
else{
clicon_debug(1, "top-level %s not found", path);
clixon_debug(CLIXON_DBG_DEFAULT, "top-level %s not found", path);
if (netconf_invalid_value_xml(&xerr, "protocol", "Top-level path not found") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, 1, YANG_DATA_JSON, 0) < 0)
goto done;
if (xerr){

View file

@ -180,11 +180,13 @@ static int session_id_context = 1;
/*! Set restconf native handle
*
* @param[in] h Clicon handle
* @param[in] rh Restconf native handle (malloced pointer)
* @param[in] h Clixon handle
* @param[in] rh Restconf native handle (malloced pointer)
* @retval 0 OK
* @retval -1 Error
*/
static int
restconf_native_handle_set(clicon_handle h,
restconf_native_handle_set(clicon_handle h,
restconf_native_handle *rh)
{
clicon_hash_t *cdat = clicon_data(h);
@ -215,7 +217,7 @@ clixon_openssl_log_cb(void *handle,
int suberr,
cbuf *cb)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
ERR_print_errors_cb(print_cb, cb);
return 0;
}
@ -224,7 +226,7 @@ clixon_openssl_log_cb(void *handle,
*/
static int
init_openssl(void)
{
{
int retval = -1;
/* In Openssl 1.1 lib inits itself (?)
@ -241,7 +243,8 @@ init_openssl(void)
return retval;
}
/*!
/*! Verify cert
*
* The verify_callback function is used to control the behaviour when the SSL_VERIFY_PEER flag
* is set. It must be supplied by the application and receives two arguments: preverify_ok
* indicates, whether the verification of the certificate in question was passed
@ -258,23 +261,22 @@ restconf_verify_certs(int preverify_ok,
int depth;
// SSL *ssl;
// clicon_handle h;
err_cert = X509_STORE_CTX_get_current_cert(store);
err = X509_STORE_CTX_get_error(store);
depth = X509_STORE_CTX_get_error_depth(store);
// ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
clicon_debug(1, "%s preverify_ok:%d err:%d depth:%d", __FUNCTION__, preverify_ok, err, depth);
clixon_debug(CLIXON_DBG_DEFAULT, "%s preverify_ok:%d err:%d depth:%d", __FUNCTION__, preverify_ok, err, depth);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
switch (err){
case X509_V_ERR_HOSTNAME_MISMATCH:
clicon_debug(1, "%s X509_V_ERR_HOSTNAME_MISMATCH", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s X509_V_ERR_HOSTNAME_MISMATCH", __FUNCTION__);
break;
case X509_V_ERR_CERT_HAS_EXPIRED:
clicon_debug(1, "%s X509_V_ERR_CERT_HAS_EXPIRED", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s X509_V_ERR_CERT_HAS_EXPIRED", __FUNCTION__);
break;
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
clicon_debug(1, "%s X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT", __FUNCTION__);
break;
}
/* Catch a too long certificate chain. should be +1 in SSL_CTX_set_verify_depth() */
@ -282,7 +284,7 @@ restconf_verify_certs(int preverify_ok,
preverify_ok = 0;
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
X509_STORE_CTX_set_error(store, err);
}
}
else{
/* Verify the CA name */
}
@ -303,7 +305,7 @@ alpn_proto_dump(const char *label,
const char *inp,
unsigned len)
{
clicon_debug(1, "%s %.*s", label, (int)len, inp);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %.*s", label, (int)len, inp);
return 0;
}
@ -325,13 +327,13 @@ alpn_select_proto_cb(SSL *ssl,
unsigned char len;
int pref = 0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* select http/1.1 */
inp = (unsigned char*)in;
while ((inp-in) < inlen) {
len = *inp;
inp++;
if (clicon_debug_get()) /* debug print the protoocol */
if (clixon_debug_get()) /* debug print the protoocol */
alpn_proto_dump(__FUNCTION__, (const char*)inp, len);
#ifdef HAVE_HTTP1
if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){
@ -454,18 +456,18 @@ restconf_listcerts(SSL *ssl)
X509 *cert;
char *line;
clicon_debug(1, "%s get peer certificates:", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s get peer certificates:", __FUNCTION__);
if ((cert = SSL_get_peer_certificate(ssl)) != NULL) { /* Get certificates (if available) */
if ((line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) != NULL){
clicon_debug(1, "Subject: %s", line);
clixon_debug(CLIXON_DBG_DEFAULT, "Subject: %s", line);
free(line);
}
if ((line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) != NULL){
clicon_debug(1, "Issuer: %s", line);
clixon_debug(CLIXON_DBG_DEFAULT, "Issuer: %s", line);
free(line);
}
if ((line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) != NULL){
clicon_debug(1, "Subject: %s", line);
clixon_debug(CLIXON_DBG_DEFAULT, "Subject: %s", line);
free(line);
}
X509_free(cert);
@ -475,7 +477,7 @@ restconf_listcerts(SSL *ssl)
#endif/* debug */
/*! Check if a "cert" file exists
*
*
* @param[in] xrestconf XML tree containing restconf config
* @param[in] name Name of configured "cert" name
* @param[out] var String variable
@ -515,6 +517,8 @@ restconf_checkcert_file(cxobj *xrestconf,
*
* @param[in] fd Socket (unix or ip)
* @param[in] arg typecast clicon_handle
* @retval 0 OK
* @retval -1 Error
* @see openssl_init_socket where this callback is registered
*/
static int
@ -530,11 +534,11 @@ restconf_accept_client(int fd,
char *name = NULL;
void *addr;
clicon_debug(1, "%s %d", __FUNCTION__, fd);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, fd);
if ((rsock = (restconf_socket *)arg) == NULL){
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
goto done;
}
}
h = rsock->rs_h;
len = sizeof(from);
if ((s = accept(rsock->rs_ss, &from, &len)) < 0){
@ -566,7 +570,7 @@ restconf_accept_client(int fd,
}
if (inet_ntop(from.sa_family, addr, rsock->rs_from_addr, INET6_ADDRSTRLEN) < 0)
goto done;
clicon_debug(1, "%s type:%s from:%s, dest:%s port:%hu", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s type:%s from:%s, dest:%s port:%hu", __FUNCTION__,
rsock->rs_addrtype,
rsock->rs_from_addr,
rsock->rs_addrstr,
@ -577,7 +581,7 @@ restconf_accept_client(int fd,
goto done;
retval = 0;
done:
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval %d", __FUNCTION__, retval);
if (name)
free(name);
return retval;
@ -592,7 +596,7 @@ restconf_native_terminate(clicon_handle h)
restconf_socket *rsock;
restconf_conn *rc;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((rn = restconf_native_handle_get(h)) != NULL){
while ((rsock = rn->rn_sockets) != NULL){
while ((rc = rsock->rs_conns) != NULL){
@ -702,11 +706,11 @@ restconf_clixon_backend(clicon_handle h,
/*! Per-socket openssl inits
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xs XML config of single restconf socket
* @param[in] nsc Namespace context
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
static int
openssl_init_socket(clicon_handle h,
@ -723,7 +727,7 @@ openssl_init_socket(clicon_handle h,
restconf_socket *rsock = NULL; /* openssl per socket struct */
struct timeval now;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/*
* Create per-socket openssl handle
* See restconf_native_terminate for freeing
@ -782,7 +786,7 @@ openssl_init_socket(clicon_handle h,
/* ss is a server socket that the clients connect to. The callback
therefore accepts clients on ss */
rsock->rs_ss = ss;
if (clixon_event_reg_fd(rsock->rs_ss, restconf_accept_client, rsock, "restconf socket") < 0)
if (clixon_event_reg_fd(rsock->rs_ss, restconf_accept_client, rsock, "restconf socket") < 0)
goto done;
}
retval = 0;
@ -793,7 +797,7 @@ openssl_init_socket(clicon_handle h,
/*! Init openssl, open and register server socket (ready for accept)
*
* Given a fully populated configuration tree.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] dbg0 Manually set debug flag, if set overrides configuration setting
* @param[in] xrestconf XML tree containing restconf config
* @retval 0 OK
@ -820,7 +824,7 @@ restconf_openssl_init(clicon_handle h,
size_t veclen;
int i;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* flag used for sanity of certs */
ssl_enable = xpath_first(xrestconf, nsc, "socket[ssl='true']") != NULL;
/* Auth type set in config */
@ -830,7 +834,7 @@ restconf_openssl_init(clicon_handle h,
(x = xpath_first(xrestconf, nsc, "debug")) != NULL &&
(bstr = xml_body(x)) != NULL){
dbg = atoi(bstr);
clicon_debug_init(dbg, NULL);
clixon_debug_init(dbg, NULL);
/* If debug was enabled here from config and not initially,
* print clixn options and loaded yang files
*/
@ -889,7 +893,7 @@ restconf_openssl_init(clicon_handle h,
return retval;
}
/*! Read restconf from config
/*! Read restconf from config
*
* After SEVERAL iterations the code now does as follows:
* - init clixon
@ -897,13 +901,13 @@ restconf_openssl_init(clicon_handle h,
* - if local config found, open sockets accordingly and exit function
* - 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] h Clixon handle
* @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
* @retval -1 Error
*/
*/
int
restconf_clixon_init(clicon_handle h,
char *inline_config,
@ -984,7 +988,6 @@ restconf_clixon_init(clicon_handle h,
/* Load yang restconf module */
if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0)
goto done;
#ifdef CLIXON_YANG_PATCH
/* Load yang restconf patch module */
if (yang_spec_parse_module(h, "ietf-yang-patch", NULL, yspec)< 0)
@ -1010,7 +1013,7 @@ restconf_clixon_init(clicon_handle h,
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
goto done;
if (inline_config != NULL && strlen(inline_config)){
clicon_debug(1, "%s reading from inline config", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s reading from inline config", __FUNCTION__);
if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf, &xerr)) < 0)
goto done;
if (ret == 0){
@ -1032,10 +1035,10 @@ restconf_clixon_init(clicon_handle h,
goto done;
}
else if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS") == 0){
clicon_debug(1, "%s reading from clixon config", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s reading from clixon config", __FUNCTION__);
/* If not read from backend, try to get restconf config from local config-file */
if ((xrestconf = clicon_conf_restconf(h)) != NULL){
/*! Basic config init, set auth-type, pretty, etc ret 0 means disabled */
/* Basic config init, set auth-type, pretty, etc ret 0 means disabled */
if ((ret = restconf_config_init(h, xrestconf)) < 0)
goto done;
/* ret == 1 means this config is OK */
@ -1050,7 +1053,7 @@ restconf_clixon_init(clicon_handle h,
/* If no local config, or it is disabled, try to query backend of config.
*/
else {
clicon_debug(1, "%s reading from backend datastore config", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s reading from backend datastore config", __FUNCTION__);
if ((ret = restconf_clixon_backend(h, xrestconfp)) < 0)
goto done;
if (ret == 0)
@ -1075,7 +1078,7 @@ restconf_sig_term(int arg)
{
static int i=0;
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
__PROGRAM__, __FUNCTION__, getpid(), arg);
if (i++ > 0) /* Allow one sigterm before proper exit */
exit(-1);
@ -1083,13 +1086,13 @@ restconf_sig_term(int arg)
* is entered, it will terminate.
* However there may be a case of sockets closing rather abruptly for clients
*/
clixon_exit_set(1);
clixon_exit_set(1);
}
/*! Usage help routine
*
* @param[in] argv0 command line
* @param[in] h Clicon handle
* @param[in] h Clixon handle
*/
static void
usage(clicon_handle h,
@ -1138,7 +1141,7 @@ main(int argc,
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Create handle */
if ((h = restconf_handle_init()) == NULL)
goto done;
@ -1175,7 +1178,7 @@ main(int argc,
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
/*
* Register error category and error/log callbacks for openssl special error handling
@ -1195,7 +1198,7 @@ main(int argc,
) < 0)
goto done;
#endif
clicon_debug_init(dbg, NULL);
clixon_debug_init(dbg, NULL);
clicon_log(LOG_NOTICE, "%s native %u Started", __PROGRAM__, getpid());
if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){
clicon_err(OE_DAEMON, errno, "Setting signal");
@ -1214,7 +1217,6 @@ main(int argc,
if (clicon_options_main(h) < 0)
goto done;
// stream_path = clicon_option_str(h, "CLICON_STREAM_PATH");
/* Now rest of options, some overwrite option file */
optind = 1;
opterr = 0;
@ -1280,7 +1282,7 @@ main(int argc,
/* Init restconf auth-type */
restconf_auth_type_set(h, CLIXON_AUTH_NONE);
/* Explicit dump of config (also debug dump below). */
if (config_dump){
if (clicon_option_dump1(h, stdout, config_dump_format, 1) < 0)
@ -1297,7 +1299,7 @@ main(int argc,
if (clixon_plugin_start_all(h) < 0)
goto done;
/* Clixon inits / configs */
/* Clixon inits / configs */
if ((ret = restconf_clixon_init(h, inline_config, &xrestconf)) < 0)
goto done;
if (ret == 0){ /* restconf disabled */
@ -1305,7 +1307,7 @@ main(int argc,
retval = 0;
goto done;
}
/* Create and stroe global openssl handle */
/* Create and stroe global openssl handle */
if ((rn = malloc(sizeof *rn)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -1313,7 +1315,7 @@ main(int argc,
memset(rn, 0, sizeof *rn);
if (restconf_native_handle_set(h, rn) < 0)
goto done;
/* Openssl inits */
/* Openssl inits */
if (restconf_openssl_init(h, dbg, xrestconf) < 0)
goto done;
/* Drop privileges if started as root to CLICON_RESTCONF_USER
@ -1327,13 +1329,13 @@ main(int argc,
*/
clicon_data_set(h, "session-transport", "cl:restconf");
/* Main event loop */
/* Main event loop */
if (clixon_event_loop(h) < 0)
goto done;
ok:
retval = 0;
done:
clicon_debug(1, "restconf_main_openssl done");
clixon_debug(CLIXON_DBG_DEFAULT, "restconf_main_openssl done");
if (xrestconf)
xml_free(xrestconf);
restconf_native_terminate(h);

View file

@ -78,10 +78,12 @@
#include "restconf_methods.h"
/*! REST OPTIONS method
*
* According to restconf
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
*
* @retval 0 OK
* @retval -1 Error
* @code
* curl -G http://localhost/restconf/data/interfaces/interface=eth0
* @endcode
@ -96,7 +98,7 @@ api_data_options(clicon_handle h,
{
int retval = -1;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (restconf_reply_header(req, "Allow", "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE") < 0)
goto done;
if (restconf_reply_header(req, "Accept-Patch", "application/yang-data+xml,application/yang-data+json") < 0)
@ -117,7 +119,7 @@ api_data_options(clicon_handle h,
* @param[in] x1 First XML tree (eg data)
* @param[in] x2 Second XML tree (eg api-path)
* @retval 0 Yes, keys match
* @retval -1 No, keys do not match
* @retval -1 No, keys do not match
* If the target resource represents a YANG leaf-list, then the PUT
* method MUST NOT change the value of the leaf-list instance.
*
@ -140,14 +142,14 @@ match_list_keys(yang_stmt *y,
char *key1;
char *key2;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
switch (yang_keyword_get(y)){
case Y_LIST:
if ((cvk = yang_cvec_get(y)) == NULL) /* Use Y_LIST cache, see ys_populate_list() */
break;
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
keyname = cv_string_get(cvi);
if ((xkey2 = xml_find(x2, keyname)) == NULL)
goto done; /* No key in api-path */
if ((key2 = xml_body(xkey2)) == NULL)
@ -174,11 +176,12 @@ match_list_keys(yang_stmt *y,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*! Common PUT plain PATCH method
*
* Code checks if object exists.
* PUT: If it does not, set op to create, otherwise replace
* PATCH: If it does not, fail, otherwise replace/merge
@ -187,13 +190,15 @@ match_list_keys(yang_stmt *y,
* @param[in] pretty Pretty-print
* @param[in] media_in Restconf input media
* @param[in] media_out Restconf output media
*/
* @retval 0 OK
* @retval -1 Error
*/
int
api_data_write(clicon_handle h,
void *req,
char *api_path0,
void *req,
char *api_path0,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_in,
@ -230,9 +235,9 @@ api_data_write(clicon_handle h,
yang_bind yb;
char *xpath = NULL;
char *attr;
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
clicon_debug(1, "%s data:\"%s\"", __FUNCTION__, data);
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
clixon_debug(CLIXON_DBG_DEFAULT, "%s data:\"%s\"", __FUNCTION__, data);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -290,7 +295,7 @@ api_data_write(clicon_handle h,
if (api_path){ /* XXX mv to copy? */
cxobj *xfrom;
cxobj *xac;
if (api_path && (strcmp(api_path, "/") != 0))
xfrom = xml_parent(xbot);
else
@ -393,7 +398,7 @@ api_data_write(clicon_handle h,
goto done;
/* Top-of tree, no api-path
* Replace xparent with x, ie bottom of api-path with data
*/
*/
dname = xml_name(xdata);
if (api_path==NULL) {
if (strcmp(dname, NETCONF_OUTPUT_DATA)!=0){
@ -422,9 +427,9 @@ api_data_write(clicon_handle h,
/* There is an api-path that defines an element in the datastore tree.
* Not top-of-tree.
*/
clicon_debug(1, "%s Comparing bottom-of api-path (%s) with top-of-data (%s)",__FUNCTION__, xml_name(xbot), dname);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Comparing bottom-of api-path (%s) with top-of-data (%s)",__FUNCTION__, xml_name(xbot), dname);
/* Check same symbol in api-path as data */
/* Check same symbol in api-path as data */
if (strcmp(dname, xml_name(xbot))){
if (netconf_bad_element_xml(&xerr, "application", dname,
"Data element does not match api-path") < 0)
@ -439,7 +444,7 @@ api_data_write(clicon_handle h,
* or the object is the key element:
* eg xpath:obj=a/key data:<key>b</key>
* That is why the conditional is somewhat hairy
*/
*/
xparent = xml_parent(xbot);
if (ybot){
/* Ensure list keys match between uri and data. That is:
@ -479,7 +484,7 @@ api_data_write(clicon_handle h,
}
if (xtop != xbot) /* Should always be true */
xml_purge(xbot);
if (xml_addsub(xparent, xdata) < 0)
if (xml_addsub(xparent, xdata) < 0)
goto done;
/* If restconf insert/point attributes are present, translate to netconf */
if (restconf_insert_attributes(xdata, qvec) < 0)
@ -487,11 +492,11 @@ api_data_write(clicon_handle h,
/* If we already have that default namespace, remove it in child */
if ((xa = xml_find_type(xdata, NULL, "xmlns", CX_ATTR)) != NULL){
if (xml2ns(xparent, NULL, &namespace) < 0){
clicon_debug(1, "%s G done", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s G done", __FUNCTION__);
goto done;
}
if (namespace == NULL){
clicon_debug_xml(1, xparent, "%s xparent:", __FUNCTION__);
clixon_debug_xml(1, xparent, "%s xparent:", __FUNCTION__);
/* XXX */
}
/* Set xmlns="" default namespace attribute (if diff from default) */
@ -535,12 +540,12 @@ api_data_write(clicon_handle h,
if (clixon_xml2cbuf(cbx, xtop, 0, 0, NULL, -1, 0) < 0)
goto done;
cprintf(cbx, "</edit-config></rpc>");
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if (api_return_err(h, req, xe, pretty, media_out, 0) < 0)
goto done;
goto done;
goto ok;
}
if ((xe = xpath_first(xret, NULL, "//ok")) != NULL &&
@ -551,11 +556,11 @@ api_data_write(clicon_handle h,
}
else
if (restconf_reply_send(req, 204, NULL, 0) < 0) /* No content */
goto done;
goto done;
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (xpath)
free(xpath);
if (nsc)
@ -578,6 +583,7 @@ api_data_write(clicon_handle h,
} /* api_data_write */
/*! Generic REST PUT method
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
@ -587,6 +593,8 @@ api_data_write(clicon_handle h,
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @retval 0 OK
* @retval -1 Error
* @note restconf PUT is mapped to edit-config replace.
* @see RFC8040 Sec 4.5 PUT
* @see api_data_post
@ -613,10 +621,10 @@ api_data_write(clicon_handle h,
*/
int
api_data_put(clicon_handle h,
void *req,
char *api_path0,
void *req,
char *api_path0,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_out,
@ -627,9 +635,10 @@ api_data_put(clicon_handle h,
media_in = restconf_content_type(h);
return api_data_write(h, req, api_path0, pi, qvec, data, pretty,
media_in, media_out, 0, ds);
}
}
/*! Generic REST PATCH method for plain patch
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
@ -639,6 +648,8 @@ api_data_put(clicon_handle h,
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @retval 0 OK
* @retval -1 Error
* Netconf: <edit-config> (nc:operation="merge")
* See RFC8040 Sec 4.6.1
* Plain patch can be used to create or update, but not delete, a child
@ -648,10 +659,10 @@ api_data_put(clicon_handle h,
*/
int
api_data_patch(clicon_handle h,
void *req,
char *api_path0,
void *req,
char *api_path0,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_out,
@ -682,9 +693,10 @@ api_data_patch(clicon_handle h,
break;
}
return ret;
}
}
/*! Generic REST DELETE method translated to edit-config
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
@ -692,6 +704,8 @@ api_data_patch(clicon_handle h,
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @retval 0 OK
* @retval -1 Error
* See RFC 8040 Sec 4.7
* Example:
* curl -X DELETE http://127.0.0.1/restconf/data/interfaces/interface=eth0
@ -699,7 +713,7 @@ api_data_patch(clicon_handle h,
*/
int
api_data_delete(clicon_handle h,
void *req,
void *req,
char *api_path,
int pi,
int pretty,
@ -723,7 +737,7 @@ api_data_delete(clicon_handle h,
int ret;
cxobj *xe; /* xml error, no free */
clicon_debug(1, "%s api_path:%s", __FUNCTION__, api_path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:%s", __FUNCTION__, api_path);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -793,12 +807,12 @@ api_data_delete(clicon_handle h,
goto ok;
}
if (restconf_reply_send(req, 204, NULL, 0) < 0)
goto done;
goto done;
ok:
retval = 0;
done:
if (cbx)
cbuf_free(cbx);
cbuf_free(cbx);
if (xret)
xml_free(xret);
if (xretcom)
@ -807,7 +821,7 @@ api_data_delete(clicon_handle h,
xml_free(xretdis);
if (xtop)
xml_free(xtop);
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}

View file

@ -35,7 +35,6 @@
* Restconf method implementation
*/
#ifndef _RESTCONF_METHODS_H_
#define _RESTCONF_METHODS_H_
@ -43,19 +42,19 @@
* Prototypes
*/
int api_data_options(clicon_handle h, void *req);
int api_data_write(clicon_handle h, void *req, char *api_path0,
int api_data_write(clicon_handle h, void *req, char *api_path0,
int pi,
cvec *qvec, char *data,
int pretty, restconf_media media_in, restconf_media media_out,
int plain_patch, ietf_ds_t ds);
int api_data_put(clicon_handle h, void *req, char *api_path,
int pi,
int api_data_put(clicon_handle h, void *req, char *api_path,
int pi,
cvec *qvec, char *data,
int pretty, restconf_media media_out, ietf_ds_t ds);
int api_data_patch(clicon_handle h, void *req, char *api_path,
int pi,
int api_data_patch(clicon_handle h, void *req, char *api_path,
int pi,
cvec *qvec, char *data, int pretty,
restconf_media media_out, ietf_ds_t ds);

View file

@ -75,7 +75,9 @@ static int api_data_pagination(clicon_handle h, void *req, char *api_path, int p
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] head If 1 is HEAD, otherwise GET
* @param[in] head If 1 is HEAD, otherwise GET
* @retval 0 OK
* @retval -1 Error
* @code
* curl -X GET http://localhost/restconf/data/interfaces/interface=eth0
* @endcode
@ -97,7 +99,7 @@ static int api_data_pagination(clicon_handle h, void *req, char *api_path, int p
static int
api_data_get2(clicon_handle h,
void *req,
char *api_path,
char *api_path,
int pi,
cvec *qvec,
int pretty,
@ -125,8 +127,8 @@ api_data_get2(clicon_handle h,
yang_stmt *y = NULL;
char *defaults = NULL;
cvec *nscd = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -137,7 +139,7 @@ api_data_get2(clicon_handle h,
if (api_path){
if ((xtop = xml_new("top", NULL, CX_ELMNT)) == NULL)
goto done;
/* Translate api-path to xml, but to validate the api-path, note: strict=1
/* Translate api-path to xml, but to validate the api-path, note: strict=1
* xtop and xbot unnecessary for this function but needed by function
*/
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y, &xerr)) < 0)
@ -166,7 +168,7 @@ api_data_get2(clicon_handle h,
}
/* Check for content attribute */
if ((attr = cvec_find_str(qvec, "content")) != NULL){
clicon_debug(1, "%s content=%s", __FUNCTION__, attr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s content=%s", __FUNCTION__, attr);
if ((int)(content = netconf_content_str2int(attr)) == -1){
if (netconf_bad_attribute_xml(&xerr, "application",
"content", "Unrecognized value of content attribute") < 0)
@ -178,7 +180,7 @@ api_data_get2(clicon_handle h,
}
/* Check for depth attribute */
if ((attr = cvec_find_str(qvec, "depth")) != NULL){
clicon_debug(1, "%s depth=%s", __FUNCTION__, attr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s depth=%s", __FUNCTION__, attr);
if (strcmp(attr, "unbounded") != 0){
char *reason = NULL;
if ((ret = parse_int32(attr, &depth, &reason)) < 0){
@ -196,11 +198,11 @@ api_data_get2(clicon_handle h,
}
}
if ((attr = cvec_find_str(qvec, "with-defaults")) != NULL){
clicon_debug(1, "%s with_defaults=%s", __FUNCTION__, attr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s with_defaults=%s", __FUNCTION__, attr);
defaults = attr;
}
clicon_debug(1, "%s path:%s", __FUNCTION__, xpath);
clixon_debug(CLIXON_DBG_DEFAULT, "%s path:%s", __FUNCTION__, xpath);
ret = clicon_rpc_get(h, xpath, nsc, content, depth, defaults, &xret);
if (ret < 0){
@ -214,8 +216,8 @@ api_data_get2(clicon_handle h,
* We need to cut that tree to only the object.
*/
#if 0 /* DEBUG */
if (clicon_debug_get())
clicon_debug_xml(1, xret, "%s xret:", __FUNCTION__);
if (clixon_debug_get())
clixon_debug_xml(CLIXON_DBG_DEFAULT, xret, "%s xret:", __FUNCTION__);
#endif
/* Check if error return */
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
@ -290,7 +292,7 @@ api_data_get2(clicon_handle h,
break;
}
}
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
clixon_debug(CLIXON_DBG_DEFAULT, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
goto done;
if (restconf_reply_header(req, "Cache-Control", "no-cache") < 0)
@ -301,7 +303,7 @@ api_data_get2(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (xpath)
free(xpath);
if (nscd)
@ -322,6 +324,7 @@ api_data_get2(clicon_handle h,
}
/*! GET Collection
*
* According to restconf collection draft. Lists, work in progress
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
@ -330,7 +333,9 @@ api_data_get2(clicon_handle h,
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] head If 1 is HEAD, otherwise GET
* @param[in] head If 1 is HEAD, otherwise GET
* @retval 0 OK
* @retval -1 Error
* @code
* curl -X GET http://localhost/restconf/data/interfaces
* @endcode
@ -342,7 +347,7 @@ api_data_get2(clicon_handle h,
static int
api_data_pagination(clicon_handle h,
void *req,
char *api_path,
char *api_path,
int pi,
cvec *qvec,
int pretty,
@ -375,8 +380,8 @@ api_data_pagination(clicon_handle h,
char *sort;
char *where;
char *ns;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -425,7 +430,7 @@ api_data_pagination(clicon_handle h,
/* Check for content attribute */
if ((attr = cvec_find_str(qvec, "content")) != NULL){
clicon_debug(1, "%s content=%s", __FUNCTION__, attr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s content=%s", __FUNCTION__, attr);
if ((int)(content = netconf_content_str2int(attr)) == -1){
if (netconf_bad_attribute_xml(&xerr, "application",
"content", "Unrecognized value of content attribute") < 0)
@ -439,7 +444,7 @@ api_data_pagination(clicon_handle h,
goto ok;
}
}
clicon_debug(1, "%s path:%s", __FUNCTION__, xpath);
clixon_debug(CLIXON_DBG_DEFAULT, "%s path:%s", __FUNCTION__, xpath);
if (content != CONTENT_CONFIG && content != CONTENT_NONCONFIG && content != CONTENT_ALL){
clicon_err(OE_XML, EINVAL, "Invalid content attribute %d", content);
goto done;
@ -447,7 +452,7 @@ api_data_pagination(clicon_handle h,
/* Clixon extensions and collection attributes */
/* Check for depth attribute */
if ((attr = cvec_find_str(qvec, "depth")) != NULL){
clicon_debug(1, "%s depth=%s", __FUNCTION__, attr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s depth=%s", __FUNCTION__, attr);
if (strcmp(attr, "unbounded") != 0){
char *reason = NULL;
if ((ret = parse_int32(attr, &depth, &reason)) < 0){
@ -486,7 +491,7 @@ api_data_pagination(clicon_handle h,
sort = cvec_find_str(qvec, "sort-by");
where = cvec_find_str(qvec, "where");
if (clicon_rpc_get_pageable_list(h, "running", xpath, nsc, content,
depth, NULL, offset, limit, direction, sort, where,
depth, NULL, offset, limit, direction, sort, where,
&xret) < 0){
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
goto done;
@ -502,7 +507,7 @@ api_data_pagination(clicon_handle h,
* We need to cut that tree to only the object.
*/
#if 0 /* DEBUG */
clicon_debug_xml(1, xret, "%s xret:", __FUNCTION__);
clixon_debug_xml(CLIXON_DBG_DEFAULT, xret, "%s xret:", __FUNCTION__);
#endif
/* Check if error return */
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
@ -538,7 +543,7 @@ api_data_pagination(clicon_handle h,
}
if (xml_rm(xp) < 0)
goto done;
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
goto done;
}
if (clixon_xml2cbuf(cbx, xpr, 0, pretty, NULL, -1, 0) < 0) /* Dont print top object? */
@ -551,7 +556,7 @@ api_data_pagination(clicon_handle h,
default:
break;
}
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
clixon_debug(CLIXON_DBG_DEFAULT, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
goto done;
if (restconf_reply_header(req, "Cache-Control", "no-cache") < 0)
@ -562,7 +567,7 @@ api_data_pagination(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cbrpc)
cbuf_free(cbrpc);
if (xpath)
@ -585,6 +590,11 @@ api_data_pagination(clicon_handle h,
}
/*! REST HEAD method
*
* The HEAD method is sent by the client to retrieve just the header fields
* that would be returned for the comparable GET method, without the
* response message-body.
* Relation to netconf: none
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
@ -593,11 +603,8 @@ api_data_pagination(clicon_handle h,
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
*
* The HEAD method is sent by the client to retrieve just the header fields
* that would be returned for the comparable GET method, without the
* response message-body.
* Relation to netconf: none
* @retval 0 OK
* @retval -1 Error
*/
int
api_data_head(clicon_handle h,
@ -613,6 +620,7 @@ api_data_head(clicon_handle h,
}
/*! REST GET method
*
* According to restconf
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
@ -623,6 +631,8 @@ api_data_head(clicon_handle h,
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds RFC8527 datastore
* @retval 0 OK
* @retval -1 Error
* @code
* curl -G http://localhost/restconf/data/interfaces/interface=eth0
* @endcode
@ -640,7 +650,7 @@ api_data_head(clicon_handle h,
int
api_data_get(clicon_handle h,
void *req,
char *api_path,
char *api_path,
int pi,
cvec *qvec,
int pretty,
@ -648,7 +658,7 @@ api_data_get(clicon_handle h,
ietf_ds_t ds)
{
int retval = -1;
switch (media_out){
case YANG_DATA_XML:
case YANG_DATA_JSON: /* ad-hoc algorithm in get to determine if a paginated request */
@ -667,6 +677,7 @@ api_data_get(clicon_handle h,
}
/*! GET restconf/operations resource
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] path According to restconf (Sec 3.5.1.1 in [draft])
@ -675,11 +686,12 @@ api_data_get(clicon_handle h,
* @param[in] data Stream input data
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
*
* @retval 0 OK
* @retval -1 Error
* @code
* curl -G http://localhost/restconf/operations
* @endcode
* RFC8040 Sec 3.3.2:
* @see RFC8040 Sec 3.3.2:
* This optional resource is a container that provides access to the
* data-model-specific RPC operations supported by the server. The
* server MAY omit this resource if no data-model-specific RPC
@ -693,9 +705,9 @@ api_data_get(clicon_handle h,
int
api_operations_get(clicon_handle h,
void *req,
char *path,
char *path,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_out)
@ -708,8 +720,8 @@ api_operations_get(clicon_handle h,
cbuf *cbx = NULL;
cxobj *xt = NULL;
int i;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
yspec = clicon_dbspec_yang(h);
if ((cbx = cbuf_new()) == NULL)
goto done;
@ -730,7 +742,7 @@ api_operations_get(clicon_handle h,
i = 0;
while ((ymod = yn_each(yspec, ymod)) != NULL) {
namespace = yang_find_mynamespace(ymod);
yc = NULL;
yc = NULL;
while ((yc = yn_each(ymod, yc)) != NULL) {
if (yang_keyword_get(yc) != Y_RPC)
continue;
@ -777,7 +789,7 @@ api_operations_get(clicon_handle h,
// ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cbx)
cbuf_free(cbx);
if (xt)

View file

@ -41,11 +41,11 @@
/*
* Prototypes
*/
int api_data_head(clicon_handle h, void *req, char *api_path, int pi,
int api_data_head(clicon_handle h, void *req, char *api_path, int pi,
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
int api_data_get(clicon_handle h, void *req, char *api_path, int pi,
int api_data_get(clicon_handle h, void *req, char *api_path, int pi,
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
int api_operations_get(clicon_handle h, void *req,
int api_operations_get(clicon_handle h, void *req,
char *api_path, int pi, cvec *qvec, char *data,
int pretty, restconf_media media_out);

View file

@ -100,11 +100,12 @@ yang_patch_op2int(char *op)
}
/*! Add square brackets after the surrounding curly brackets in JSON
*
* Needed, in order to modify the result of clixon_json2cbuf() to be valid input
* to api_data_post() and api_data_write()
* @param[in] x_simple_patch a cxobj to pass to clixon_json2cbuf()
* @retva cbuf With the modified json
* @retva NULL Error
* @retval cbuf With the modified json
* @retval NULL Error
*/
static cbuf*
yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch)
@ -150,7 +151,7 @@ yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch)
return json_simple_patch;
}
/*!yang_patch_strip_after_last_slash
/*! yang_patch_strip_after_last_slash
*
* Strip /... from end of val
* so that e.g. "/interface=eth2" becomes "/"
@ -187,6 +188,7 @@ yang_patch_strip_after_last_slash(char* val)
}
/*! YANG PATCH replace method
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start api-path
@ -199,6 +201,8 @@ yang_patch_strip_after_last_slash(char* val)
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
* @param[in] x_simple_patch pointer to XML containing module name, e.g. <ietf-interfaces:interface/>
* @retval 0 OK
* @retval -1 Error
*/
static int
yang_patch_do_replace(clicon_handle h,
@ -287,6 +291,7 @@ yang_patch_do_replace(clicon_handle h,
}
/*! YANG PATCH create method
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start api-path
@ -298,6 +303,8 @@ yang_patch_do_replace(clicon_handle h,
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
* @param[in] x_simple_patch pointer to XML containing module name, e.g. <ietf-interfaces:interface/>
* @retval 0 OK
* @retval -1 Error
*/
static int
yang_patch_do_create(clicon_handle h,
@ -343,12 +350,13 @@ yang_patch_do_create(clicon_handle h,
}
/*! YANG PATCH insert method
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start api-path
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start api-path
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces"
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
@ -356,6 +364,8 @@ yang_patch_do_create(clicon_handle h,
* @param[in] where_val value in "where" field of edit in YANG patch
* @param[in] api_path full API path, e.g. "/restconf/data/example-jukebox:jukebox/playlist=Foo-One"
* @param[in] point_val value in "point" field of edit in YANG patch
* @retval 0 OK
* @retval -1 Error
*/
static int
yang_patch_do_insert(clicon_handle h,
@ -431,19 +441,22 @@ yang_patch_do_insert(clicon_handle h,
}
/*! YANG PATCH merge method
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces"
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
* @param[in] x_simple_patch pointer to XML containing module name, e.g. "<ietf-interfaces:interface/>"
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
* @param[in] x_simple_patch pointer to XML containing module name, e.g. "<ietf-interfaces:interface/>"
* @param[in] where_val value in "where" field of edit in YANG patch
* @param[in] key_xn XML with key tag and value, e.g. "<name>Foo-One</name>"
* @retval 0 OK
* @retval -1 Error
*/
static int
yang_patch_do_merge(clicon_handle h,
@ -622,7 +635,7 @@ yang_patch_do_edit(clicon_handle h,
yang_stmt *ybot = NULL;
yang_stmt *ymod;
clicon_debug_xml(1, xn, "%s %d xn:", __FUNCTION__, __LINE__);
clixon_debug_xml(1, xn, "%s %d xn:", __FUNCTION__, __LINE__);
/* Create cbufs:s */
if ((simple_patch_request_uri = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
@ -655,7 +668,7 @@ yang_patch_do_edit(clicon_handle h,
if (point_val == NULL || where_val == NULL){
clicon_err(OE_YANG, 0, "point/where: expected element not found");
goto done;
}
}
}
// Construct request URI
cprintf(simple_patch_request_uri, "%s", uripath0);
@ -704,7 +717,7 @@ yang_patch_do_edit(clicon_handle h,
} else {
// TODO - do not send error
}
api_data_delete(h, req, cbuf_get(simple_patch_request_uri), pi, pretty, YANG_DATA_JSON, ds);
api_data_delete(h, req, cbuf_get(simple_patch_request_uri), pi, pretty, YANG_DATA_JSON, ds);
}
ok:
retval = 0;
@ -723,6 +736,7 @@ yang_patch_do_edit(clicon_handle h,
}
/*! YANG PATCH method
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path0 According to restconf (Sec 3.5.3.1 in rfc8040)
@ -755,7 +769,7 @@ api_data_yang_patch(clicon_handle h,
{
int retval = -1;
int i;
cxobj *xpatch = NULL;
cxobj *xpatch = NULL;
yang_stmt *yspec;
char *api_path;
cxobj *xerr = NULL; /* malloced must be freed */
@ -764,7 +778,7 @@ api_data_yang_patch(clicon_handle h,
size_t veclen;
cxobj **vec = NULL;
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -805,7 +819,7 @@ api_data_yang_patch(clicon_handle h,
goto done;
goto ok;
}
/*
/*
* RFC 8072 2.1: The message-body MUST identify exactly one resource instance
*/
if (xml_child_nr_type(xpatch, CX_ELMNT) != 1){
@ -819,7 +833,7 @@ api_data_yang_patch(clicon_handle h,
if ((uripath0 = restconf_uripath(h)) == NULL)
goto done;
/* Find all edit operations and loop over them
*/
*/
if (xpath_vec(xpatch, NULL, "yang-patch/edit", &vec, &veclen) < 0)
goto done;
for (i = 0; i < veclen; i++) {

View file

@ -66,8 +66,11 @@
#include "restconf_methods_post.h"
/*! Print location header from
*
* @param[in] req Generic Www handle
* @param[in] xobj If set (eg POST) add to api-path
* @retval 0 OK
* @retval -1 Error
* $https on if connection operates in SSL mode, or an empty string otherwise
* @note ports are ignored
*/
@ -116,6 +119,7 @@ http_location_header(clicon_handle h,
}
/*! Generic REST POST method
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
@ -153,9 +157,9 @@ http_location_header(clicon_handle h,
int
api_data_post(clicon_handle h,
void *req,
char *api_path,
char *api_path,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_in,
@ -179,14 +183,14 @@ api_data_post(clicon_handle h,
cxobj *xretdis = NULL; /* return from discard-changes */
cxobj *xerr = NULL; /* malloced must be freed */
cxobj *xe; /* dont free */
cxobj *x;
cxobj *x;
char *username;
int ret;
int nrchildren0 = 0;
yang_bind yb;
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path);
clicon_debug(1, "%s data:\"%s\"", __FUNCTION__, data);
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:\"%s\"", __FUNCTION__, api_path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s data:\"%s\"", __FUNCTION__, data);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -249,7 +253,7 @@ api_data_post(clicon_handle h,
goto ok;
}
break;
case YANG_DATA_JSON:
case YANG_DATA_JSON:
if ((ret = clixon_json_parse_string(data, 1, yb, yspec, &xbot, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
@ -272,7 +276,7 @@ api_data_post(clicon_handle h,
/* RFC 8040 4.4.1: The message-body MUST contain exactly one instance of the
* expected data resource.
*/
clicon_debug(1, "%s nrchildren0: %d", __FUNCTION__, nrchildren0);
clixon_debug(CLIXON_DBG_DEFAULT, "%s nrchildren0: %d", __FUNCTION__, nrchildren0);
if (xml_child_nr_type(xbot, CX_ELMNT) - nrchildren0 != 1){
if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0)
goto done;
@ -283,7 +287,7 @@ api_data_post(clicon_handle h,
/* Find the actual (new) object, the single unmarked one */
x = NULL;
while ((x = xml_child_each(xbot, x, CX_ELMNT)) != NULL){
if (xml_flag(x, XML_FLAG_MARK)){
if (xml_flag(x, XML_FLAG_MARK)){
xml_flag_reset(x, XML_FLAG_MARK);
continue;
}
@ -326,7 +330,7 @@ api_data_post(clicon_handle h,
if (restconf_insert_attributes(xdata, qvec) < 0)
goto done;
#if 1
clicon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
clixon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
#endif
/* Create text buffer for transfer to backend */
@ -365,7 +369,7 @@ api_data_post(clicon_handle h,
if (clixon_xml2cbuf(cbx, xtop, 0, 0, NULL, -1, 0) < 0)
goto done;
cprintf(cbx, "</edit-config></rpc>");
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
@ -376,11 +380,11 @@ api_data_post(clicon_handle h,
if (http_location_header(h, req, xdata) < 0)
goto done;
if (restconf_reply_send(req, 201, NULL, 0) < 0)
goto done;
goto done;
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (xret)
xml_free(xret);
if (xerr)
@ -392,11 +396,12 @@ api_data_post(clicon_handle h,
if (xtop)
xml_free(xtop);
if (cbx)
cbuf_free(cbx);
cbuf_free(cbx);
return retval;
} /* api_data_post */
/*! Handle input data to api_operations_post
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] data Stream input data
@ -436,7 +441,7 @@ api_operations_post_input(clicon_handle h,
int ret;
restconf_media media_in;
clicon_debug(1, "%s %s", __FUNCTION__, data);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, data);
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_UNIX, 0, "cbuf_new");
goto done;
@ -486,7 +491,7 @@ api_operations_post_input(clicon_handle h,
* <data><input xmlns="urn:example:clixon">...</input></data>
*/
#if 1
clicon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
clixon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
#endif
/* Validate that exactly only <input> tag */
if ((xinput = xml_child_i_type(xdata, 0, CX_ELMNT)) == NULL ||
@ -499,23 +504,23 @@ api_operations_post_input(clicon_handle h,
}
else
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto fail;
}
// clicon_debug(1, "%s input validation passed", __FUNCTION__);
// clixon_debug(CLIXON_DBG_DEFAULT, "%s input validation passed", __FUNCTION__);
/* Add all input under <rpc>path */
x = NULL;
while ((x = xml_child_i_type(xinput, 0, CX_ELMNT)) != NULL)
if (xml_addsub(xrpc, x) < 0)
if (xml_addsub(xrpc, x) < 0)
goto done;
/* Here xrpc is: <myfn xmlns="uri"><x>42</x></myfn>
*/
// ok:
retval = 1;
done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
if (cbret)
cbuf_free(cbret);
if (xerr)
@ -529,6 +534,7 @@ api_operations_post_input(clicon_handle h,
}
/*! Handle output data to api_operations_post
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] xret XML reply messages from backend/handler
@ -552,7 +558,6 @@ api_operations_post_output(clicon_handle h,
int pretty,
restconf_media media_out,
cxobj **xoutputp)
{
int retval = -1;
cxobj *xoutput = NULL;
@ -561,8 +566,8 @@ api_operations_post_output(clicon_handle h,
cxobj *x;
cxobj *xok;
int isempty;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* Validate that exactly only <rpc-reply> tag with exactly one element child */
if ((xoutput = xml_child_i_type(xret, 0, CX_ELMNT)) == NULL ||
strcmp(xml_name(xoutput),"rpc-reply") != 0
@ -573,7 +578,7 @@ api_operations_post_output(clicon_handle h,
*/
){
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto fail;
@ -583,7 +588,7 @@ api_operations_post_output(clicon_handle h,
xml_name_set(xoutput, "output");
/* xoutput should now look: <output><x xmlns="uri">0</x></output> */
#if 1
clicon_debug_xml(1, xoutput, "%s xoutput:", __FUNCTION__);
clixon_debug_xml(1, xoutput, "%s xoutput:", __FUNCTION__);
#endif
/* Remove original netconf default namespace. Somewhat unsure what "output" belongs to? */
if ((xa = xml_find_type(xoutput, NULL, "xmlns", CX_ATTR)) != NULL)
@ -628,7 +633,7 @@ api_operations_post_output(clicon_handle h,
if (isempty) {
/* Internal error - invalid output from rpc handler */
if (restconf_reply_send(req, 204, NULL, 0) < 0)
goto done;
goto done;
goto fail;
}
/* Clear namespace of parameters */
@ -644,7 +649,7 @@ api_operations_post_output(clicon_handle h,
*xoutputp = xoutput;
retval = 1;
done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
if (xerr)
xml_free(xerr);
return retval;
@ -654,6 +659,7 @@ api_operations_post_output(clicon_handle h,
}
/*! REST operation POST method
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
@ -661,6 +667,8 @@ api_operations_post_output(clicon_handle h,
* @param[in] data Stream input data
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @retval 0 OK
* @retval -1 Error
* See RFC 8040 Sec 3.6 / 4.4.2
* @note We map post to edit-config create.
* POST {+restconf}/operations/<operation>
@ -685,9 +693,9 @@ api_operations_post_output(clicon_handle h,
int
api_operations_post(clicon_handle h,
void *req,
char *api_path,
char *api_path,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_out)
@ -713,8 +721,8 @@ api_operations_post(clicon_handle h,
yang_stmt *ys = NULL;
char *namespace = NULL;
int nr = 0;
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, api_path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, api_path);
/* 1. Initialize */
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
@ -784,7 +792,7 @@ api_operations_post(clicon_handle h,
* XML: <input xmlns="uri"><x>0</x></input>
*/
namespace = xml_find_type_value(xbot, NULL, "xmlns", CX_ATTR);
clicon_debug(1, "%s : 4. Parse input data: %s", __FUNCTION__, data);
clixon_debug(CLIXON_DBG_DEFAULT, "%s : 4. Parse input data: %s", __FUNCTION__, data);
if (data && strlen(data)){
if ((ret = api_operations_post_input(h, req, data, yspec, yrpc, xbot,
pretty, media_out)) < 0)
@ -795,7 +803,7 @@ api_operations_post(clicon_handle h,
/* Here xtop is:
<rpc username="foo"><myfn xmlns="uri"><x>42</x></myfn></rpc> */
#if 1
clicon_debug_xml(1, xtop, "%s 5. Translate input args:", __FUNCTION__);
clixon_debug_xml(1, xtop, "%s 5. Translate input args:", __FUNCTION__);
#endif
/* 6. Validate outgoing RPC and fill in defaults */
if ((ret = xml_bind_yang_rpc(h, xtop, yspec, &xerr)) < 0) /* */
@ -816,7 +824,7 @@ api_operations_post(clicon_handle h,
* <rpc username="foo"><myfn xmlns="uri"><x>42</x><y>99</y></myfn></rpc>
*/
#if 0
clicon_debug_xml(1, xtop, "%s 6. Validate and defaults:", __FUNCTION__);
clixon_debug_xml(1, xtop, "%s 6. Validate and defaults:", __FUNCTION__);
#endif
/* 7. Send to RPC handler, either local or backend
* Note (1) xtop is <rpc><method> xbot is <method>
@ -857,7 +865,7 @@ api_operations_post(clicon_handle h,
* <rpc-reply><x xmlns="uri">0</x></rpc-reply>
*/
#if 1
clicon_debug_xml(1, xret, "%s Receive reply:", __FUNCTION__);
clixon_debug_xml(1, xret, "%s Receive reply:", __FUNCTION__);
#endif
youtput = yang_find(yrpc, Y_OUTPUT, NULL);
if ((ret = api_operations_post_output(h, req, xret, yspec, youtput, namespace,
@ -889,7 +897,7 @@ api_operations_post(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (prefix)
free(prefix);
if (id)

View file

@ -44,7 +44,7 @@
int api_data_post(clicon_handle h, void *req, char *api_path,
int pi, cvec *qvec, char *data,
int pretty,
restconf_media media_in,
restconf_media media_in,
restconf_media media_out, ietf_ds_t ds);
int api_operations_post(clicon_handle h, void *req, char *api_path,

View file

@ -80,7 +80,8 @@
/* Forward */
static int restconf_idle_cb(int fd, void *arg);
/*!
/*! Create restconf stream
*
* @param[in] rc Restconf connection handle
* @see restconf_stream_free
*/
@ -118,7 +119,8 @@ restconf_stream_data_new(restconf_conn *rc,
return sd;
}
/*!
/*! Find restconf stream data
*
* @param[in] rc Restconf connection handle
*/
restconf_stream_data *
@ -190,11 +192,12 @@ restconf_conn_new(clicon_handle h,
rc->rc_callhome = rsock->rs_callhome;
rc->rc_socket = rsock;
INSQ(rc, rsock->rs_conns);
clicon_debug(1, "%s %p", __FUNCTION__, rc);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %p", __FUNCTION__, rc);
return rc;
}
/*! Free clixon/cbuf resources related to a connection
*
* @param[in] rc restconf connection
*/
static int
@ -205,7 +208,7 @@ restconf_conn_free(restconf_conn *rc)
restconf_socket *rsock;
restconf_conn *rc1;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (rc == NULL){
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
goto done;
@ -238,8 +241,11 @@ restconf_conn_free(restconf_conn *rc)
}
/*! Given SSL connection, get peer certificate one-line name
*
* @param[in] ssl SSL session
* @param[out] oneline Cert name one-line
* @retval 0 OK
* @retval -1 Error
*/
int
ssl_x509_name_oneline(SSL *ssl,
@ -261,7 +267,7 @@ ssl_x509_name_oneline(SSL *ssl,
if ((cert = SSL_get1_peer_certificate(ssl)) == NULL)
goto ok;
#endif
if ((name = X509_get_subject_name(cert)) == NULL)
if ((name = X509_get_subject_name(cert)) == NULL)
goto ok;
if ((p = X509_NAME_oneline(name, NULL, 0)) == NULL)
goto ok;
@ -308,7 +314,7 @@ restconf_connection_sanity(clicon_handle h,
restconf_media media_out = YANG_DATA_JSON;
char *media_str = NULL;
char *oneline = NULL;
/* 1) Check if http/2 non-tls is disabled */
if (rc->rc_ssl == NULL &&
rc->rc_proto == HTTP_2 &&
@ -383,7 +389,7 @@ native_buf_write(clicon_handle h,
char *buf,
size_t buflen,
restconf_conn *rc,
const char *callfn)
const char *callfn)
{
int retval = -1;
ssize_t len;
@ -400,7 +406,7 @@ native_buf_write(clicon_handle h,
* 1. they are not "strings" in the sense they are not NULL-terminated
* 2. they are often very long
*/
if (clicon_debug_get()) {
if (clixon_debug_get()) {
char *dbgstr = NULL;
size_t sz;
sz = buflen>256?256:buflen; /* Truncate to 256 */
@ -410,7 +416,7 @@ native_buf_write(clicon_handle h,
}
memcpy(dbgstr, buf, sz);
dbgstr[sz] = '\0';
clicon_debug(1, "%s %s buflen:%zu buf:\n%s", __FUNCTION__, callfn, buflen, dbgstr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s buflen:%zu buf:\n%s", __FUNCTION__, callfn, buflen, dbgstr);
free(dbgstr);
}
while (totlen < buflen){
@ -424,7 +430,7 @@ native_buf_write(clicon_handle h,
goto closed; /* Close socket and ssl */
}
else if (er == EAGAIN){
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
usleep(10000);
continue;
}
@ -445,7 +451,7 @@ native_buf_write(clicon_handle h,
if ((len = write(rc->rc_s, buf+totlen, buflen-totlen)) < 0){
switch (errno){
case EAGAIN: /* Operation would block */
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
usleep(10000);
continue;
break;
@ -465,7 +471,7 @@ native_buf_write(clicon_handle h,
} /* while */
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
closed:
retval = 0;
@ -473,13 +479,14 @@ native_buf_write(clicon_handle h,
}
/*! Send early handcoded bad request reply before actual packet received, just after accept
*
* @param[in] h Clixon handle
* @param[in] media
* @param[in] body If given add message body using media
* @param[in] rc Restconf connection, note may be closed in this
* @retval 1 OK
* @retval 0 OK, but socket write returned error, caller should close rc
* @retval -1 Error
* @retval 1 OK
* @retval 0 OK, but socket write returned error, caller should close rc
* @retval -1 Error
* @see restconf_badrequest which can only be called in a request context
*/
static int
@ -490,8 +497,8 @@ native_send_badrequest(clicon_handle h,
{
int retval = -1;
cbuf *cb = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -548,8 +555,8 @@ http1_native_clear_input(clicon_handle h,
* @param[in] sz Size of input buffer
* @param[out] np Bytes read
* @param[out] again If set, read data again, do not continue processing
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
static int
read_ssl(restconf_conn *rc,
@ -560,10 +567,10 @@ read_ssl(restconf_conn *rc,
{
int retval = -1;
int sslerr;
if ((*np = SSL_read(rc->rc_ssl, buf, sz)) <= 0){
sslerr = SSL_get_error(rc->rc_ssl, *np);
clicon_debug(1, "%s SSL_read() n:%zd errno:%d sslerr:%d", __FUNCTION__, *np, errno, sslerr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_read() n:%zd errno:%d sslerr:%d", __FUNCTION__, *np, errno, sslerr);
switch (sslerr){
case SSL_ERROR_WANT_READ: /* 2 */
/* SSL_ERROR_WANT_READ is returned when the last operation was a read operation
@ -571,7 +578,7 @@ read_ssl(restconf_conn *rc,
* That is, it can happen if restconf_socket_init() below is called
* with SOCK_NONBLOCK
*/
clicon_debug(1, "%s SSL_read SSL_ERROR_WANT_READ", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_read SSL_ERROR_WANT_READ", __FUNCTION__);
usleep(1000);
*again = 1;
break;
@ -580,13 +587,13 @@ read_ssl(restconf_conn *rc,
break;
default:
clicon_log(LOG_WARNING, "%s SSL_read(): %s sslerr:%d", __FUNCTION__, strerror(errno), sslerr);
*np = 0;
*np = 0;
break;
} /* switch */
}
retval = 0;
// done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}
@ -597,9 +604,9 @@ read_ssl(restconf_conn *rc,
* @param[in] sz Size of input buffer
* @param[out] np Bytes read
* @param[out] again If set, read data again, do not continue processing
* @retval -1 Error
* @retval 0 Socket closed, quit
* @retval 1 OK
* @retval 0 Socket closed, quit
* @retval -1 Error
* XXX:
* readmore/continue
* goto ok
@ -612,18 +619,18 @@ read_regular(restconf_conn *rc,
int *again)
{
int retval = -1;
if ((*np = read(rc->rc_s, buf, sz)) < 0){ /* XXX atomicio ? */
switch(errno){
case ECONNRESET:/* Connection reset by peer */
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
retval = 0; /* Close socket and ssl */
goto done;
break;
case EAGAIN:
clicon_debug(1, "%s read EAGAIN", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s read EAGAIN", __FUNCTION__);
usleep(1000);
*again = 1;
break;
@ -646,9 +653,9 @@ read_regular(restconf_conn *rc,
* @param[in] buf Input buffer
* @param[in] n Length of data in input buffer
* @param[out] readmore If set, read data again, do not continue processing
* @retval -1 Error
* @retval 0 Socket closed, quit
* @retval 1 OK
* @retval 0 Socket closed, quit
* @retval -1 Error
*/
static int
restconf_http1_process(restconf_conn *rc,
@ -662,7 +669,7 @@ restconf_http1_process(restconf_conn *rc,
int ret;
int status;
cbuf *cberr = NULL;
h = rc->rc_h;
if ((sd = restconf_stream_find(rc, 0)) == NULL){
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
@ -803,7 +810,7 @@ restconf_http2_upgrade(restconf_conn *rc)
{
int retval = -1;
restconf_stream_data *sd;
if ((sd = restconf_stream_find(rc, 0)) == NULL){
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
goto done;
@ -854,19 +861,20 @@ restconf_http2_upgrade(restconf_conn *rc)
retval = 0;
done:
return retval;
return retval;
}
#endif /* HAVE_LIBHTTP1 */
/*! Restconf HTTP/2 processing after chunk of bytes read
*
* @param[in] rc Restconf connection
* @param[in] buf Input buffer
* @param[in] n Size of input buffer
* @param[in] n Length of data in input buffer
* @param[out] readmore If set, read data again, do not continue processing
* @retval -1 Error
* @retval 0 Socket closed, quit
* @retval 1 OK
* @retval 0 Socket closed, quit
* @retval -1 Error
*/
static int
restconf_http2_process(restconf_conn *rc,
@ -878,7 +886,7 @@ restconf_http2_process(restconf_conn *rc,
int ret;
nghttp2_error ngerr;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (rc->rc_exit){ /* Server-initiated exit for http/2 */
if ((ngerr = nghttp2_session_terminate_session(rc->rc_ngsession, 0)) < 0){
clicon_err(OE_NGHTTP2, ngerr, "nghttp2_session_terminate_session %d", ngerr);
@ -905,13 +913,14 @@ restconf_http2_process(restconf_conn *rc,
}
retval = 1;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}
#endif /* HAVE_LIBNGHTTP2 */
/*! Get restconf native handle
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval rn Restconf native handle
*/
restconf_native_handle *
@ -933,7 +942,7 @@ restconf_native_handle_get(clicon_handle h)
* @param[in] s Socket where message arrived. read from this.
* @param[in] arg Client entry (from).
* @retval 0 OK
* @retval -1 Error Terminates backend and is never called). Instead errors are
* @retval -1 Error Terminates backend and is never called). Instead errors are
* propagated back to client.
* @see restconf_accept_client where this callback is registered
* @note read buffer is limited. More data can be read in two ways: returns a buffer
@ -952,7 +961,7 @@ restconf_connection(int s,
int readmore = 1;
int ret;
clicon_debug(1, "%s %d", __FUNCTION__, s);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, s);
if ((rc = (restconf_conn*)arg) == NULL){
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
goto done;
@ -963,7 +972,7 @@ restconf_connection(int s,
}
gettimeofday(&rc->rc_t, NULL); /* activity timer */
while (readmore) {
clicon_debug(1, "%s readmore", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s readmore", __FUNCTION__);
readmore = 0;
/* Example: curl -Ssik -u wilma:bar -X GET https://localhost/restconf/data/example:x */
if (rc->rc_ssl){
@ -976,11 +985,11 @@ restconf_connection(int s,
if (ret == 0)
goto ok; /* abort here */
}
clicon_debug(1, "%s read:%zd", __FUNCTION__, n);
clixon_debug(CLIXON_DBG_DEFAULT, "%s read:%zd", __FUNCTION__, n);
if (readmore)
continue;
if (n == 0){
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s n=0 closing socket", __FUNCTION__);
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
goto done;
rc = NULL;
@ -1020,15 +1029,18 @@ restconf_connection(int s,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval %d", __FUNCTION__, retval);
return retval;
} /* restconf_connection */
/*----------------------------- Close socket ------------------------------*/
/*! Close Restconf native connection socket and unregister callback
*
* For callhome also start reconnect timer
* @param[in] rc rstconf connection
* @retval 0 OK
* @retval -1 Error
*/
static int
restconf_connection_close1(restconf_conn *rc)
@ -1041,7 +1053,7 @@ restconf_connection_close1(restconf_conn *rc)
goto done;
}
rsock = rc->rc_socket;
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
if (close(rc->rc_s) < 0){
clicon_err(OE_UNIX, errno, "close");
goto done;
@ -1056,16 +1068,19 @@ restconf_connection_close1(restconf_conn *rc)
}
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}
/*! Utility function to close restconf server ssl socket.
*
* There are many variants to closing, one could probably make this more generic
* and always use this function, but it is difficult.
* @param[in] rc restconf connection
* @param[in] callfn For debug
* @param[in] dontshutdown If != 0, do not shutdown
* @retval 0 OK
* @retval -1 Error
*/
int
restconf_close_ssl_socket(restconf_conn *rc,
@ -1077,16 +1092,15 @@ restconf_close_ssl_socket(restconf_conn *rc,
int sslerr;
int er;
clicon_debug(1, "%s %s", __FUNCTION__, callfn);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, callfn);
if (rc->rc_ssl != NULL){
if (!dontshutdown &&
(ret = SSL_shutdown(rc->rc_ssl)) < 0){
er = errno;
sslerr = SSL_get_error(rc->rc_ssl, ret);
clicon_debug(1, "%s errno:%s(%d) sslerr:%d", __FUNCTION__, strerror(er), er, sslerr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s errno:%s(%d) sslerr:%d", __FUNCTION__, strerror(er), er, sslerr);
if (sslerr == SSL_ERROR_SSL || /* 1 */
sslerr == SSL_ERROR_ZERO_RETURN){ /* 6 */
}
else if (sslerr == SSL_ERROR_SYSCALL){ /* 5 */
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
@ -1112,14 +1126,16 @@ restconf_close_ssl_socket(restconf_conn *rc,
goto done;
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*------------------------------ Accept--------------------------------*/
/*! Check ALPN result
* @proto[out] proto
*
* @param[in] h Clixon handle
* @param[out] proto
* @retval 1 OK with proto set
* @retval 0 Fail, ALPN null or not recognized
* @retval -1 Error
@ -1133,8 +1149,8 @@ ssl_alpn_check(clicon_handle h,
{
int retval = -1;
cbuf *cberr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* Alternatively, call restconf_str2proto but alpn is not a proper string */
if (alpn && alpnlen == 8 && memcmp("http/1.1", alpn, 8) == 0){
*proto = HTTP_11;
@ -1152,7 +1168,7 @@ ssl_alpn_check(clicon_handle h,
if (alpn != NULL){
cprintf(cberr, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>ALPN: protocol not recognized: %s</error-message></error></errors>", alpn);
clicon_log(LOG_INFO, "%s Warning: %s", __FUNCTION__, cbuf_get(cberr));
if (native_send_badrequest(h,
if (native_send_badrequest(h,
"application/yang-data+xml",
cbuf_get(cberr), rc) < 0)
goto done;
@ -1165,7 +1181,7 @@ ssl_alpn_check(clicon_handle h,
#if defined(HAVE_LIBNGHTTP2)
char *pstr; /* Both http/1 and http/2 */
int p = -1;
pstr = clicon_option_str(h, "CLICON_NOALPN_DEFAULT");
if (pstr)
p = restconf_str2proto(pstr);
@ -1186,7 +1202,7 @@ ssl_alpn_check(clicon_handle h,
}
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cberr)
cbuf_free(cberr);
return retval;
@ -1196,6 +1212,7 @@ ssl_alpn_check(clicon_handle h,
} /* ssl_alpn_check */
/*! Accept new socket client. Note SSL not ip, this applies also to callhome
*
* @param[in] h Clixon handle
* @param[in] s Socket (unix or ip)
* @param[in] rsock Socket struct
@ -1223,7 +1240,7 @@ restconf_ssl_accept_client(clicon_handle h,
unsigned int alpnlen = 0;
restconf_http_proto proto = HTTP_11; /* Non-SSL negotiation NYI */
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
#ifdef HAVE_LIBNGHTTP2
#ifndef HAVE_HTTP1
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
@ -1238,13 +1255,13 @@ restconf_ssl_accept_client(clicon_handle h,
*/
if ((rc = restconf_conn_new(h, s, rsock)) == NULL)
goto done;
clicon_debug(1, "%s s:%d", __FUNCTION__, rc->rc_s);
clixon_debug(CLIXON_DBG_DEFAULT, "%s s:%d", __FUNCTION__, rc->rc_s);
if (rsock->rs_ssl){
if ((rc->rc_ssl = SSL_new(rn->rn_ctx)) == NULL){
clicon_err(OE_SSL, 0, "SSL_new");
goto done;
}
clicon_debug(1, "%s SSL_new(%p)", __FUNCTION__, rc->rc_ssl);
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_new(%p)", __FUNCTION__, rc->rc_ssl);
/* CCL_CTX_set_verify already set, need not call SSL_set_verify again for this server
*/
/* X509_CHECK_FLAG_NO_WILDCARDS disables wildcard expansion */
@ -1281,11 +1298,11 @@ restconf_ssl_accept_client(clicon_handle h,
* Both error cases: Call SSL_get_error() with the return value ret
*/
if ((ret = SSL_accept(rc->rc_ssl)) != 1) {
clicon_debug(1, "%s SSL_accept() ret:%d errno:%d", __FUNCTION__, ret, er=errno);
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_accept() ret:%d errno:%d", __FUNCTION__, ret, er=errno);
e = SSL_get_error(rc->rc_ssl, ret);
switch (e){
case SSL_ERROR_SSL: /* 1 */
clicon_debug(1, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
#ifdef HTTP_ON_HTTPS_REPLY
SSL_free(rc->rc_ssl);
rc->rc_ssl = NULL;
@ -1298,12 +1315,12 @@ restconf_ssl_accept_client(clicon_handle h,
goto closed;
break;
case SSL_ERROR_SYSCALL: /* 5 */
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
may contain more information on the error. For socket I/O on Unix systems,
consult errno for details. If this error occurs then no further I/O
operations should be performed on the connection and SSL_shutdown() must
not be called.*/
clicon_debug(1, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
if (restconf_close_ssl_socket(rc, __FUNCTION__, 1) < 0)
goto done;
rc = NULL;
@ -1316,7 +1333,7 @@ restconf_ssl_accept_client(clicon_handle h,
* That is, it can happen if restconf_socket_init() below is called
* with SOCK_NONBLOCK
*/
clicon_debug(1, "%s write SSL_ERROR_WANT_READ", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write SSL_ERROR_WANT_READ", __FUNCTION__);
usleep(10000);
readmore = 1;
break;
@ -1350,7 +1367,7 @@ restconf_ssl_accept_client(clicon_handle h,
if (ret == 0){
goto closed;
}
clicon_debug(1, "%s proto:%s", __FUNCTION__, restconf_proto2str(proto));
clixon_debug(CLIXON_DBG_DEFAULT, "%s proto:%s", __FUNCTION__, restconf_proto2str(proto));
#if 0 /* Seems too early to fail here, instead let authentication callback deal with this */
/* For client-cert authentication, check if any certs are present,
@ -1388,7 +1405,7 @@ restconf_ssl_accept_client(clicon_handle h,
const char *peername = SSL_get0_peername(rc->rc_ssl);
if (peername != NULL) {
/* Name checks were in scope and matched the peername */
clicon_debug(1, "%s peername:%s", __FUNCTION__, peername);
clixon_debug(CLIXON_DBG_DEFAULT, "%s peername:%s", __FUNCTION__, peername);
}
}
#if 0
@ -1402,7 +1419,7 @@ restconf_ssl_accept_client(clicon_handle h,
}
#endif
#if 0 /* debug */
if (clicon_debug_get())
if (clixon_debug_get())
restconf_listcerts(rc->rc_ssl);
#endif
} /* if ssl */
@ -1441,7 +1458,7 @@ restconf_ssl_accept_client(clicon_handle h,
*rcp = rc;
retval = 1; /* OK, up */
done:
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval %d", __FUNCTION__, retval);
if (name)
free(name);
return retval;
@ -1457,7 +1474,7 @@ restconf_idle_timer_set(struct timeval t,
{
int retval = -1;
cbuf *cb = NULL;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -1475,8 +1492,11 @@ restconf_idle_timer_set(struct timeval t,
return retval;
}
/*! idle timeout timer callback
* @param[in] rc restconf connection, more specifically: callhome connection
/*! Idle timeout timer callback
*
* @param[in] rc Restconf connection, more specifically: callhome connection
* @retval 0 OK
* @retval -1 Error
*
* t0 tp t1 tn
* |---------|-----------|--------------------|
@ -1509,7 +1529,7 @@ restconf_idle_cb(int fd,
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
goto done;
}
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
if (rc->rc_callhome && rsock->rs_periodic && rc->rc_s > 0 && rsock->rs_idle_timeout){
gettimeofday(&now, NULL);
timersub(&now, &rc->rc_t, &td); /* Last packet timestamp */
@ -1520,7 +1540,7 @@ restconf_idle_cb(int fd,
else{
to.tv_sec = rsock->rs_idle_timeout;
timeradd(&now, &to, &tn);
clicon_debug(1, "%s now:%lu timeout:%lu.%lu", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s now:%lu timeout:%lu.%lu", __FUNCTION__,
now.tv_sec, tn.tv_sec, tn.tv_usec);
if (restconf_idle_timer_set(tn, rc, rsock->rs_description) < 0)
goto done;
@ -1538,6 +1558,7 @@ restconf_idle_timer_unreg(restconf_conn *rc)
}
/*! Set callhome periodic idle-timeout
*
* 1) If callhome and periodic, set timer for t0+idle-timeout(ti)
* 2) Timestamp any data passing on the socket(td)
* 3) At timeout (ti) check if ti = td+idle-timeout (for first timeout same as t0=td),
@ -1559,13 +1580,13 @@ restconf_idle_timer(restconf_conn *rc)
if (rc == NULL || !rc->rc_callhome){
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL or not callhome");
goto done;
}
}
rsock = rc->rc_socket;
if (rsock == NULL || !rsock->rs_periodic || rsock->rs_idle_timeout==0){
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not periodic");
goto done;
}
clicon_debug(1, "%s \"%s\" register", __FUNCTION__, rsock->rs_description);
}
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\" register", __FUNCTION__, rsock->rs_description);
gettimeofday(&now, NULL);
to.tv_sec = rsock->rs_idle_timeout;
timeradd(&now, &to, &t);
@ -1603,7 +1624,7 @@ restconf_callhome_cb(int fd,
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
goto done;
}
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
h = rsock->rs_h;
/* Already computed in restconf_socket_init, could be saved in rsock? */
if (clixon_inet2sin(rsock->rs_addrtype, rsock->rs_addrstr, rsock->rs_port, sa, &sa_len) < 0)
@ -1613,7 +1634,7 @@ restconf_callhome_cb(int fd,
goto done;
}
if (connect(s, sa, sa_len) < 0){
clicon_debug(1, "%s connect %hu fail:%d %s", __FUNCTION__, rsock->rs_port, errno, strerror(errno));
clixon_debug(CLIXON_DBG_DEFAULT, "%s connect %hu fail:%d %s", __FUNCTION__, rsock->rs_port, errno, strerror(errno));
close(s);
rsock->rs_attempts++;
/* Fail: Initiate new timer */
@ -1621,7 +1642,7 @@ restconf_callhome_cb(int fd,
goto done;
}
else {
clicon_debug(1, "%s connect %hu OK", __FUNCTION__, rsock->rs_port);
clixon_debug(CLIXON_DBG_DEFAULT, "%s connect %hu OK", __FUNCTION__, rsock->rs_port);
rsock->rs_attempts = 0;
if ((ret = restconf_ssl_accept_client(h, s, rsock, &rc)) < 0)
goto done;
@ -1648,6 +1669,8 @@ restconf_callhome_timer_unreg(restconf_socket *rsock)
* NYI: start-with, anchor-time
* @param[in] rsock restconf_socket
* @param[in] new if periodic: 1: Force a new period
* @retval 0 OK
* @retval -1 Error
* @see restconf_callhome_timer_unreg
*/
int
@ -1659,12 +1682,12 @@ restconf_callhome_timer(restconf_socket *rsock,
struct timeval t;
struct timeval t1 = {0, 0};
cbuf *cb = NULL;
if (rsock == NULL || !rsock->rs_callhome){
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not callhome");
goto done;
}
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
}
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
if (!rsock->rs_callhome)
goto ok; /* shouldnt happen */
gettimeofday(&now, NULL);
@ -1692,9 +1715,9 @@ restconf_callhome_timer(restconf_socket *rsock,
}
cprintf(cb, "restconf callhome timer %s", rsock->rs_description);
if (rsock->rs_description)
clicon_debug(1, "%s registering \"%s\": +%lu", __FUNCTION__, rsock->rs_description, t.tv_sec-now.tv_sec);
clixon_debug(CLIXON_DBG_DEFAULT, "%s registering \"%s\": +%lu", __FUNCTION__, rsock->rs_description, t.tv_sec-now.tv_sec);
else
clicon_debug(1, "%s: %lu", __FUNCTION__, t.tv_sec);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %lu", __FUNCTION__, t.tv_sec);
/* Should be only place restconf_callhome_cb is registered */
if (clixon_event_reg_timeout(t,
restconf_callhome_cb,
@ -1710,7 +1733,8 @@ restconf_callhome_timer(restconf_socket *rsock,
}
/*! Extract socket info from backend config
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xs socket config
* @param[in] nsc Namespace context
* @param[out] rsock restconf socket data, filled in with many fields
@ -1718,6 +1742,8 @@ restconf_callhome_timer(restconf_socket *rsock,
* @param[out] address Address as string, eg "0.0.0.0", "::"
* @param[out] addrtype One of inet:ipv4-address or inet:ipv6-address
* @param[out] port TCP Port
* @retval 0 OK
* @retval -1 Error
*/
int
restconf_socket_extract(clicon_handle h,
@ -1789,7 +1815,7 @@ restconf_socket_extract(clicon_handle h,
* type inet:ipv6-address; <---
* }
*/
*addrtype = yang_argument_get(ysub);
*addrtype = yang_argument_get(ysub);
if ((x = xpath_first(xs, nsc, "port")) != NULL &&
(str = xml_body(x)) != NULL){
if ((ret = parse_uint16(str, port, &reason)) < 0){
@ -1820,7 +1846,7 @@ restconf_socket_extract(clicon_handle h,
}
else if (xpath_first(xs, nsc, "call-home/connection-type/periodic") != NULL){
rsock->rs_periodic = 1;
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/period")) != NULL &&
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/period")) != NULL &&
(str = xml_body(x)) != NULL){
if ((ret = parse_uint32(str, &rsock->rs_period, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_uint16");
@ -1829,9 +1855,9 @@ restconf_socket_extract(clicon_handle h,
if (ret == 0){
clicon_err(OE_XML, EINVAL, "Unrecognized value of period: %s", str);
goto done;
}
}
}
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/idle-timeout")) != NULL &&
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/idle-timeout")) != NULL &&
(str = xml_body(x)) != NULL){
if ((ret = parse_uint16(str, &rsock->rs_idle_timeout, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_uint16");
@ -1840,10 +1866,10 @@ restconf_socket_extract(clicon_handle h,
if (ret == 0){
clicon_err(OE_XML, EINVAL, "Unrecognized value of idle-timeout: %s", str);
goto done;
}
}
}
}
if ((x = xpath_first(xs, nsc, "call-home/reconnect-strategy/max-attempts")) != NULL &&
if ((x = xpath_first(xs, nsc, "call-home/reconnect-strategy/max-attempts")) != NULL &&
(str = xml_body(x)) != NULL){
if ((ret = parse_uint8(str, &rsock->rs_max_attempts, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_uint8");
@ -1852,7 +1878,7 @@ restconf_socket_extract(clicon_handle h,
if (ret == 0){
clicon_err(OE_XML, EINVAL, "Unrecognized value of max-attempts: %s", str);
goto done;
}
}
}
}
retval = 0;

View file

@ -67,7 +67,7 @@ extern "C" {
/*
* Types
*/
/* Forward */
struct restconf_conn;
@ -95,13 +95,13 @@ typedef struct {
} restconf_stream_data;
typedef struct restconf_socket restconf_socket;
/* Restconf connection handle
* Per connection request
*/
typedef struct restconf_conn {
qelem_t rc_qelem; /* List header */
/* XXX rc_proto and rc_proto_d1/d2 may not both be necessary.
/* XXX rc_proto and rc_proto_d1/d2 may not both be necessary.
* remove rc_proto?
*/
int rc_callhome; /* 0: listen, 1: callhome */
@ -188,7 +188,7 @@ int restconf_callhome_timer_unreg(restconf_socket *rsock);
int restconf_callhome_timer(restconf_socket *rsock, int status);
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, restconf_socket *rsock,
char **namespace, char **address, char **addrtype, uint16_t *port);
#endif /* _RESTCONF_NATIVE_H_ */
#ifdef __cplusplus

View file

@ -92,7 +92,8 @@
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
/*! Map http2 frame types in nghttp2
* I had expected it in in libnghttp2 but havent found it
*
* Had expected it in in libnghttp2 but havent found it
*/
static const map_str2int nghttp2_frame_type_map[] = {
{"DATA", NGHTTP2_DATA},
@ -119,7 +120,7 @@ clixon_nghttp2_log_cb(void *handle,
int suberr,
cbuf *cb)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
cprintf(cb, "Fatal error: %s", nghttp2_strerror(suberr));
return 0;
}
@ -131,24 +132,28 @@ nghttp2_print_header(const uint8_t *name,
const uint8_t *value,
size_t valuelen)
{
clicon_debug(1, "%s %s", name, value);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", name, value);
}
/* Print HTTP headers to |f|. Please note that this function does not
take into account that header name and value are sequence of
octets, therefore they may contain non-printable characters. */
/*! Print HTTP headers to |f|.
*
* Please note that this function does not
* take into account that header name and value are sequence of
* octets, therefore they may contain non-printable characters.
*/
static void
nghttp2_print_headers(nghttp2_nv *nva,
size_t nvlen)
{
size_t i;
for (i = 0; i < nvlen; ++i)
for (i = 0; i < nvlen; ++i)
nghttp2_print_header(nva[i].name, nva[i].namelen, nva[i].value, nva[i].valuelen);
}
#endif /* NOTUSED */
/*! Send data to remote peer, Send at most the |length| bytes of |data|.
*
* This callback is required if the application uses
* `nghttp2_session_send()` to send data to the remote endpoint. If
* the application uses solely `nghttp2_session_mem_send()` instead,
@ -172,21 +177,21 @@ session_send_callback(nghttp2_session *session,
ssize_t totlen = 0;
int s;
int sslerr;
clicon_debug(1, "%s buflen:%zu", __FUNCTION__, buflen);
clixon_debug(CLIXON_DBG_DEFAULT, "%s buflen:%zu", __FUNCTION__, buflen);
s = rc->rc_s;
while (totlen < buflen){
if (rc->rc_ssl){
if ((len = SSL_write(rc->rc_ssl, buf+totlen, buflen-totlen)) <= 0){
er = errno;
sslerr = SSL_get_error(rc->rc_ssl, len);
clicon_debug(1, "%s SSL_write: errno:%s(%d) sslerr:%d", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_write: errno:%s(%d) sslerr:%d", __FUNCTION__,
strerror(er),
er,
sslerr);
switch (sslerr){
case SSL_ERROR_WANT_WRITE: /* 3 */
clicon_debug(1, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
usleep(1000);
continue;
break;
@ -196,11 +201,11 @@ session_send_callback(nghttp2_session *session,
goto done; /* Cleanup in http2_recv() */
}
else if (er == EAGAIN){
/* same as want_write above, but different behaviour on different
/* same as want_write above, but different behaviour on different
* platforms, linux here, freebsd want_write, or possibly differnt
* ssl lib versions?
*/
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
usleep(1000);
continue;
}
@ -220,7 +225,7 @@ session_send_callback(nghttp2_session *session,
else{
if ((len = write(s, buf+totlen, buflen-totlen)) < 0){
if (errno == EAGAIN){
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
usleep(10000);
continue;
}
@ -247,10 +252,10 @@ session_send_callback(nghttp2_session *session,
retval = 0;
done:
if (retval < 0){
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
clicon_debug(1, "%s retval:%zd", __FUNCTION__, totlen);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%zd", __FUNCTION__, totlen);
return retval == 0 ? totlen : retval;
}
@ -264,7 +269,7 @@ recv_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -288,8 +293,8 @@ restconf_nghttp2_path(restconf_stream_data *sd)
char *oneline = NULL;
cvec *cvv = NULL;
char *cn;
clicon_debug(1, "------------");
clixon_debug(CLIXON_DBG_DEFAULT, "------------");
rc = sd->sd_conn;
if ((h = rc->rc_h) == NULL){
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
@ -327,21 +332,21 @@ restconf_nghttp2_path(restconf_stream_data *sd)
}
else if (api_path_is_restconf(h)){
if (api_root_restconf(h, sd, sd->sd_qvec) < 0)
goto done;
goto done;
}
else if (api_path_is_data(h)){
if (api_http_data(h, sd, sd->sd_qvec) < 0)
goto done;
}
else if (api_root_restconf(h, sd, sd->sd_qvec) < 0) /* error handling */
goto done;
goto done;
}
/* Clear (fcgi) paramaters from this request */
if (restconf_param_del_all(h) < 0)
goto done;
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (cvv)
cvec_free(cvv);
if (oneline)
@ -350,6 +355,7 @@ restconf_nghttp2_path(restconf_stream_data *sd)
}
/*! data callback, just pass pointer to cbuf
*
* XXX handle several chunks with cbuf
*/
static ssize_t
@ -384,7 +390,7 @@ restconf_sd_read(nghttp2_session *session,
#endif
assert(cbuf_len(cb) > sd->sd_body_offset);
remain = cbuf_len(cb) - sd->sd_body_offset;
clicon_debug(1, "%s length:%zu totlen:%zu, offset:%zu remain:%zu",
clixon_debug(CLIXON_DBG_DEFAULT, "%s length:%zu totlen:%zu, offset:%zu remain:%zu",
__FUNCTION__,
length,
cbuf_len(cb),
@ -400,7 +406,7 @@ restconf_sd_read(nghttp2_session *session,
}
memcpy(buf, cbuf_get(cb) + sd->sd_body_offset, len);
sd->sd_body_offset += len;
clicon_debug(1, "%s retval:%zu", __FUNCTION__, len);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%zu", __FUNCTION__, len);
return len;
}
@ -428,7 +434,7 @@ restconf_submit_response(nghttp2_session *session,
hdr = &hdrs[i++];
hdr->name = (uint8_t*)":status";
snprintf(valstr, 15, "%u", sd->sd_code);
clicon_debug(1, "%s status %d", __FUNCTION__, sd->sd_code);
clixon_debug(CLIXON_DBG_DEFAULT, "%s status %d", __FUNCTION__, sd->sd_code);
hdr->value = (uint8_t*)valstr;
hdr->namelen = strlen(":status");
hdr->valuelen = strlen(valstr);
@ -438,7 +444,7 @@ restconf_submit_response(nghttp2_session *session,
while ((cv = cvec_each(sd->sd_outp_hdrs, cv)) != NULL){
hdr = &hdrs[i++];
hdr->name = (uint8_t*)cv_name_get(cv);
clicon_debug(1, "%s hdr: %s", __FUNCTION__, hdr->name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s hdr: %s", __FUNCTION__, hdr->name);
hdr->value = (uint8_t*)cv_string_get(cv);
hdr->namelen = strlen(cv_name_get(cv));
hdr->valuelen = strlen(cv_string_get(cv));
@ -453,7 +459,7 @@ restconf_submit_response(nghttp2_session *session,
}
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (hdrs)
free(hdrs);
return retval;
@ -469,7 +475,7 @@ http2_exec(restconf_conn *rc,
{
int retval = -1;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (sd->sd_path){
free(sd->sd_path);
sd->sd_path = NULL;
@ -498,7 +504,7 @@ http2_exec(restconf_conn *rc,
*/
if (sd->sd_code != 204 && sd->sd_code > 199 && sd->sd_body_len)
if (restconf_reply_header(sd, "Content-Length", "%zu", sd->sd_body_len) < 0)
goto done;
goto done;
if (sd->sd_code){
if (restconf_submit_response(session, rc, stream_id, sd) < 0)
goto done;
@ -508,7 +514,7 @@ http2_exec(restconf_conn *rc,
}
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -523,8 +529,8 @@ on_frame_recv_callback(nghttp2_session *session,
restconf_conn *rc = (restconf_conn *)user_data;
restconf_stream_data *sd = NULL;
char *query;
clicon_debug(1, "%s %s %d", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %d", __FUNCTION__,
clicon_int2str(nghttp2_frame_type_map, frame->hd.type),
frame->hd.stream_id);
switch (frame->hd.type) {
@ -566,7 +572,7 @@ on_invalid_frame_recv_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -588,9 +594,9 @@ on_data_chunk_recv_callback(nghttp2_session *session,
restconf_conn *rc = (restconf_conn *)user_data;
restconf_stream_data *sd;
clicon_debug(1, "%s %d", __FUNCTION__, stream_id);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, stream_id);
if ((sd = restconf_stream_find(rc, stream_id)) != NULL){
cbuf_append_buf(sd->sd_indata, (void*)data, len);
cbuf_append_buf(sd->sd_indata, (void*)data, len);
}
return 0;
}
@ -603,7 +609,7 @@ before_frame_send_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -615,7 +621,7 @@ on_frame_send_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -628,7 +634,7 @@ on_frame_not_send_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -642,7 +648,7 @@ on_stream_close_callback(nghttp2_session *session,
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
#if 0 // NOTNEEDED /* XXX think this is not necessary? */
if (error_code){
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
@ -662,7 +668,7 @@ on_begin_headers_callback(nghttp2_session *session,
restconf_conn *rc = (restconf_conn *)user_data;
restconf_stream_data *sd;
clicon_debug(1, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type));
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type));
if (frame->hd.type == NGHTTP2_HEADERS &&
frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
sd = restconf_stream_data_new(rc, frame->hd.stream_id);
@ -672,6 +678,7 @@ on_begin_headers_callback(nghttp2_session *session,
}
/*! Map from nghttp2 headers to "fcgi" type parameters used in clixon code
*
* Both |name| and |value| are guaranteed to be NULL-terminated.
*/
static int
@ -683,7 +690,7 @@ nghttp2_hdr2clixon(clicon_handle h,
if (strcmp(name, ":path") == 0){
/* Including ?args, call restconf_uripath() to get only path */
if (restconf_param_set(h, "REQUEST_URI", value) < 0)
if (restconf_param_set(h, "REQUEST_URI", value) < 0)
goto done;
}
else if (strcmp(name, ":method") == 0){
@ -707,6 +714,7 @@ nghttp2_hdr2clixon(clicon_handle h,
}
/*! Header name/value pair is received
*
* Both |name| and |value| are guaranteed to be NULL-terminated.
* If the application uses `nghttp2_session_mem_recv()`, it can return
* :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
@ -728,12 +736,12 @@ on_header_callback(nghttp2_session *session,
switch (frame->hd.type){
case NGHTTP2_HEADERS:
assert (frame->headers.cat == NGHTTP2_HCAT_REQUEST);
clicon_debug(1, "%s HEADERS %s %s", __FUNCTION__, name, value);
clixon_debug(CLIXON_DBG_DEFAULT, "%s HEADERS %s %s", __FUNCTION__, name, value);
if (nghttp2_hdr2clixon(rc->rc_h, (char*)name, (char*)value) < 0)
goto done;
break;
default:
clicon_debug(1, "%s %s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type), name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type), name);
break;
}
retval = 0;
@ -751,7 +759,7 @@ select_padding_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return frame->hd.length;
}
@ -767,12 +775,13 @@ data_source_read_length_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
#endif /* NOTUSED */
/*! Invoked when a frame header is received.
*
* Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will
* also be called when frame header of CONTINUATION frame is received.
*/
@ -782,13 +791,14 @@ on_begin_frame_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, hd->type));
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, hd->type));
if (hd->type == NGHTTP2_CONTINUATION)
assert(0);
return 0;
}
/*! Send complete DATA frame for no-copy
*
* Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
* used in :type:`nghttp2_data_source_read_callback` to send complete
* DATA frame.
@ -801,7 +811,7 @@ send_data_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -815,7 +825,7 @@ pack_extension_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -828,7 +838,7 @@ unpack_extension_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
#endif /* NOTUSED */
@ -843,7 +853,7 @@ on_extension_chunk_recv_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -856,7 +866,7 @@ error_callback(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -871,7 +881,7 @@ error_callback2(nghttp2_session *session,
void *user_data)
{
// restconf_conn *rc = (restconf_conn *)user_data;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clicon_err(OE_NGHTTP2, lib_error_code, "%s", msg);
return 0;
}
@ -893,11 +903,11 @@ http2_recv(restconf_conn *rc,
{
int retval = -1;
nghttp2_error ngerr;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (rc->rc_ngsession == NULL){
/* http2_session_init not called */
clicon_err(OE_RESTCONF, EINVAL, "No nghttp2 session");
clicon_err(OE_RESTCONF, EINVAL, "No nghttp2 session");
goto done;
}
/* may make additional pending frames */
@ -924,14 +934,14 @@ http2_recv(restconf_conn *rc,
*/
clicon_err_reset();
if ((ngerr = nghttp2_session_send(rc->rc_ngsession)) != 0){
if (clicon_errno)
if (clicon_errno)
goto done;
else
goto fail; /* Not fatal error */
}
retval = 1; /* OK */
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
fail:
retval = 0;
@ -948,7 +958,7 @@ http2_send_server_connection(restconf_conn *rc)
,{NGHTTP2_SETTINGS_ENABLE_PUSH, 0}};
nghttp2_error ngerr;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((ngerr = nghttp2_submit_settings(rc->rc_ngsession,
NGHTTP2_FLAG_NONE,
iv,
@ -962,7 +972,7 @@ http2_send_server_connection(restconf_conn *rc)
}
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}

View file

@ -98,8 +98,11 @@ api_path_is_restconf(clicon_handle h)
}
/*! Determine the root of the RESTCONF API by accessing /.well-known
* @param[in] h Clicon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @retval 0 OK
* @retval -1 Error
* @see RFC8040 3.1 and RFC7320
* In line with the best practices defined by [RFC7320], RESTCONF
* enables deployments to specify where the RESTCONF API is located.
@ -113,7 +116,7 @@ api_well_known(clicon_handle h,
cbuf *cb = NULL;
int head;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (req == NULL){
errno = EINVAL;
goto done;
@ -150,12 +153,14 @@ api_well_known(clicon_handle h,
}
/*! Retrieve the Top-Level API Resource /restconf/ (exact)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] req Generic request handle
* @param[in] method Http method
* @param[in] pretty Pretty print
* @param[in] media_out Restconf output media
* @retval 0 OK
* @retval -1 Error
* @note Only returns null for operations and data,...
* See RFC8040 3.3
* @see api_root_restconf for accessing /restconf/ *
@ -174,7 +179,7 @@ api_root_restconf_exact(clicon_handle h,
cbuf *cb = NULL;
int head;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
head = strcmp(request_method, "HEAD") == 0;
if (!head && strcmp(request_method, "GET") != 0){
if (restconf_method_notallowed(h, req, "GET", pretty, media_out) < 0)
@ -208,7 +213,7 @@ api_root_restconf_exact(clicon_handle h,
goto done;
break;
case YANG_DATA_JSON:
case YANG_PATCH_JSON:
case YANG_PATCH_JSON:
if (clixon_json2cbuf(cb, xt, pretty, 0, 0) < 0)
goto done;
break;
@ -230,7 +235,7 @@ api_root_restconf_exact(clicon_handle h,
/** A stub implementation of the operational state datastore. The full
* implementation is required by https://tools.ietf.org/html/rfc8527#section-3.1
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] req Generic http handle
* @param[in] pretty Pretty-print
* @param[in] media_out Restconf output media
@ -243,31 +248,33 @@ api_operational_state(clicon_handle h,
restconf_media media_out)
{
clicon_debug(1, "%s request method:%s", __FUNCTION__, request_method);
clixon_debug(CLIXON_DBG_DEFAULT, "%s request method:%s", __FUNCTION__, request_method);
/* We are not implementing this method at this time, 20201105 despite it
* being mandatory https://tools.ietf.org/html/rfc8527#section-3.1 */
return restconf_notimplemented(h, req, pretty, media_out);
}
/*!
/*! get yang lib version
*
* See https://tools.ietf.org/html/rfc7895
* @param[in] pretty Pretty-print
* @param[in] media_out Restconf output media
* @retval 0 OK
* @retval -1 Error
*/
static int
api_yang_library_version(clicon_handle h,
void *req,
int pretty,
restconf_media media_out)
{
int retval = -1;
cxobj *xt = NULL;
cbuf *cb = NULL;
yang_stmt *yspec;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
goto done;
if (restconf_reply_header(req, "Cache-Control", "no-cache") < 0)
@ -312,6 +319,7 @@ api_yang_library_version(clicon_handle h,
}
/*! Generic REST method, GET, PUT, DELETE, etc
*
* @param[in] h CLIXON handle
* @param[in] r Fastcgi request handle
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [draft])
@ -320,15 +328,17 @@ api_yang_library_version(clicon_handle h,
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Restconf output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
* @retval 0 OK
* @retval -1 Error
*/
static int
api_data(clicon_handle h,
void *req,
char *api_path,
cvec *pcvec,
void *req,
char *api_path,
cvec *pcvec,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_out,
@ -339,9 +349,9 @@ api_data(clicon_handle h,
char *request_method;
cxobj *xerr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
request_method = restconf_param_get(h, "REQUEST_METHOD");
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
clixon_debug(CLIXON_DBG_DEFAULT, "%s method:%s", __FUNCTION__, request_method);
/* https://tools.ietf.org/html/rfc8527#section-3.2 */
/* We assume that dynamic datastores are read only at this time 20201105 */
@ -355,7 +365,7 @@ api_data(clicon_handle h,
if (strcmp(request_method, "OPTIONS")==0)
retval = api_data_options(h, req);
else if (strcmp(request_method, "HEAD")==0) {
if (dynamic)
if (dynamic)
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
else
retval = api_data_head(h, req, api_path, pi, qvec, pretty, media_out, ds);
@ -367,7 +377,7 @@ api_data(clicon_handle h,
retval = api_data_post(h, req, api_path, pi, qvec, data, pretty, restconf_content_type(h), media_out, ds);
}
else if (strcmp(request_method, "PUT")==0) {
if (read_only)
if (read_only)
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
else
retval = api_data_put(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
@ -379,17 +389,17 @@ api_data(clicon_handle h,
retval = api_data_patch(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
}
else if (strcmp(request_method, "DELETE")==0) {
if (read_only)
if (read_only)
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
else
retval = api_data_delete(h, req, api_path, pi, pretty, media_out, ds);
}
else{
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid HTTP data method") < 0)
goto done;
goto done;
retval = api_return_err0(h, req, xerr, pretty, media_out, 0);
}
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
done:
if (xerr)
xml_free(xerr);
@ -397,6 +407,7 @@ api_data(clicon_handle h,
}
/*! Operations REST method, POST
*
* @param[in] h CLIXON handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] request_method eg GET,...
@ -406,15 +417,17 @@ api_data(clicon_handle h,
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data
* @param[in] media_out Output media
* @retval 0 OK
* @retval -1 Error
*/
static int
api_operations(clicon_handle h,
void *req,
void *req,
char *request_method,
char *path,
cvec *pcvec,
cvec *pcvec,
int pi,
cvec *qvec,
cvec *qvec,
char *data,
int pretty,
restconf_media media_out)
@ -422,7 +435,7 @@ api_operations(clicon_handle h,
int retval = -1;
cxobj *xerr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (strcmp(request_method, "GET")==0)
retval = api_operations_get(h, req, path, pi, qvec, data, pretty, media_out);
else if (strcmp(request_method, "POST")==0)
@ -430,7 +443,7 @@ api_operations(clicon_handle h,
pretty, media_out);
else{
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid HTTP operations method") < 0)
goto done;
goto done;
retval = api_return_err0(h, req, xerr, pretty, media_out, 0);
}
done:
@ -440,9 +453,12 @@ api_operations(clicon_handle h,
}
/*! Process a /restconf root input, this is the root of the restconf processing
* @param[in] h Clicon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
* @retval 0 OK
* @retval -1 Error
* @see api_root_restconf_exact for accessing /restconf/ exact
*/
int
@ -466,7 +482,7 @@ api_root_restconf(clicon_handle h,
int ret;
cxobj *xerr = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (req == NULL){
errno = EINVAL;
goto done;
@ -476,7 +492,7 @@ api_root_restconf(clicon_handle h,
goto done;
pretty = restconf_pretty_get(h);
/* Get media for output (proactive negotiation) RFC7231 by using
* Accept:. This is for methods that have output, such as GET,
* Accept:. This is for methods that have output, such as GET,
* operation POST, etc
* If accept is * default is yang-json
*/
@ -496,7 +512,7 @@ api_root_restconf(clicon_handle h,
goto ok;
}
}
clicon_debug(1, "%s ACCEPT: %s %s", __FUNCTION__, media_str, restconf_media_int2str(media_out));
clixon_debug(CLIXON_DBG_DEFAULT, "%s ACCEPT: %s %s", __FUNCTION__, media_str, restconf_media_int2str(media_out));
if ((pvec = clicon_strsep(path, "/", &pn)) == NULL)
goto done;
@ -504,14 +520,14 @@ api_root_restconf(clicon_handle h,
/* Sanity check of path. Should be /restconf/ */
if (pn < 2){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /restconf/ expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
if (strlen(pvec[0]) != 0){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, restconf api root expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
@ -522,19 +538,19 @@ api_root_restconf(clicon_handle h,
}
if ((api_resource = pvec[2]) == NULL){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /restconf/ expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
clicon_debug(1, "%s: api_resource=%s", __FUNCTION__, api_resource);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: api_resource=%s", __FUNCTION__, api_resource);
if (uri_str2cvec(path, '/', '=', 1, &pcvec) < 0) /* rest url eg /album=ricky/foo */
goto done;
/* data */
if ((cb = restconf_get_indata(req)) == NULL) /* XXX NYI ACTUALLY not always needed, do this later? */
goto done;
indata = cbuf_get(cb);
clicon_debug(1, "%s DATA=%s", __FUNCTION__, indata);
clixon_debug(CLIXON_DBG_DEFAULT, "%s DATA=%s", __FUNCTION__, indata);
/* If present, check credentials. See "plugin_credentials" in plugin
* retvals:
@ -564,7 +580,7 @@ api_root_restconf(clicon_handle h,
if (4 > pn) { /* Malformed request, no "ietf-datastores:<datastore>" component */
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, No ietf-datastores:<datastore> component") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
@ -587,7 +603,7 @@ api_root_restconf(clicon_handle h,
}
else { /* Malformed request, unsupported datastore type */
if (netconf_invalid_value_xml(&xerr, "protocol", "Unsupported datastore type") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
@ -597,13 +613,13 @@ api_root_restconf(clicon_handle h,
goto done;
}
else if (strcmp(api_resource, "operations") == 0){ /* rpc */
if (api_operations(h, req, request_method, path, pcvec, 2, qvec, indata,
if (api_operations(h, req, request_method, path, pcvec, 2, qvec, indata,
pretty, media_out) < 0)
goto done;
}
else{
if (netconf_invalid_value_xml(&xerr, "protocol", "API-resource type") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
@ -611,7 +627,7 @@ api_root_restconf(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
#ifdef WITH_RESTCONF_FCGI
if (cb)
cbuf_free(cb);

View file

@ -116,12 +116,12 @@ struct stream_child{
/* Linked list of children
* @note could hang STREAM_CHILD list on clicon handle instead.
*/
static struct stream_child *STREAM_CHILD = NULL;
static struct stream_child *STREAM_CHILD = NULL;
/*! Check if uri path denotes a stream/notification path
*
* @retval 0 No, not a stream path
* @retval 1 Yes, a stream path
* @retval 0 No, not a stream path
*/
int
api_path_is_stream(clicon_handle h)
@ -151,7 +151,7 @@ api_path_is_stream(clicon_handle h)
/*! Find restconf child using PID and cleanup FCGI Request data
*
* For forked, called on SIGCHILD
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] pid Process id of child
* @note could hang STREAM_CHILD list on clicon handle instead.
*/
@ -160,7 +160,7 @@ stream_child_free(clicon_handle h,
int pid)
{
struct stream_child *sc;
if ((sc = STREAM_CHILD) != NULL){
do {
if (pid == sc->sc_pid){
@ -177,6 +177,7 @@ stream_child_free(clicon_handle h,
}
/*! Free all streams
*
* Typically called on restconf exit
*/
int
@ -193,12 +194,15 @@ stream_child_freeall(clicon_handle h)
}
/*! Callback when stream notifications arrive from backend
*
* @param[in] s Socket
* @param[in] req Generic Www handle (can be part of clixon handle)
* @retval 0 OK
* @retval -1 Error
* @see netconf_notification_cb
*/
static int
restconf_stream_cb(int s,
restconf_stream_cb(int s,
void *arg)
{
int retval = -1;
@ -210,23 +214,23 @@ restconf_stream_cb(int s,
cbuf *cb = NULL;
int pretty = 0; /* XXX should be via arg */
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* get msg (this is the reason this function is called) */
if (clicon_msg_rcv(s, NULL, 0, &reply, &eof) < 0){
clicon_debug(1, "%s msg_rcv error", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s msg_rcv error", __FUNCTION__);
goto done;
}
clicon_debug(1, "%s msg: %s", __FUNCTION__, reply?reply->op_body:"null");
clixon_debug(CLIXON_DBG_DEFAULT, "%s msg: %s", __FUNCTION__, reply?reply->op_body:"null");
/* handle close from remote end: this will exit the client */
if (eof){
clicon_debug(1, "%s eof", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s eof", __FUNCTION__);
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
errno = ESHUTDOWN;
FCGX_FPrintF(r->out, "SHUTDOWN\r\n");
FCGX_FPrintF(r->out, "\r\n");
FCGX_FFlush(r->out);
clixon_exit_set(1);
clixon_exit_set(1);
goto done;
}
if ((ret = clicon_msg_decode(reply, NULL, NULL, &xtop, NULL)) < 0) /* XXX pass yang_spec */
@ -262,7 +266,7 @@ restconf_stream_cb(int s,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
if (xtop != NULL)
xml_free(xtop);
if (reply)
@ -273,19 +277,22 @@ restconf_stream_cb(int s,
}
/*! Send subscription to backend
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] name Stream name
* @param[in] qvec
* @param[in] pretty Pretty-print json/xml reply
* @param[in] media_out Restconf output media
* @param[out] sp Socket -1 if not set
* @retval 0 OK
* @retval -1 Error
*/
static int
restconf_stream(clicon_handle h,
void *req,
char *name,
cvec *qvec,
cvec *qvec,
int pretty,
restconf_media media_out,
int *sp)
@ -299,7 +306,7 @@ restconf_stream(clicon_handle h,
cg_var *cv;
char *vname;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
*sp = -1;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
@ -346,7 +353,7 @@ restconf_stream(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
if (xret)
xml_free(xret);
if (cb)
@ -359,18 +366,19 @@ restconf_stream(clicon_handle h,
#include "restconf_stream.h"
/*! Listen sock callback (from proxy?)
*
* @param[in] s Socket
* @param[in] req Generic Www handle (can be part of clixon handle)
*/
static int
stream_checkuplink(int s,
stream_checkuplink(int s,
void *arg)
{
FCGX_Request *r = (FCGX_Request *)arg;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (FCGX_GetError(r->out) != 0){ /* break loop */
clicon_debug(1, "%s FCGX_GetError upstream", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s FCGX_GetError upstream", __FUNCTION__);
clixon_exit_set(1);
}
return 0;
@ -383,10 +391,10 @@ stream_timeout(int s,
struct timeval t;
struct timeval t1;
FCGX_Request *r = (FCGX_Request *)arg;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (FCGX_GetError(r->out) != 0){ /* break loop */
clicon_debug(1, "%s FCGX_GetError upstream", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s FCGX_GetError upstream", __FUNCTION__);
clixon_exit_set(1);
}
else{
@ -396,13 +404,16 @@ stream_timeout(int s,
clixon_event_reg_timeout(t, stream_timeout, arg, "Stream timeout");
}
return 0;
}
}
/*! Process a stream request
* @param[in] h Clicon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
* @param[out] finish Set to zero, if request should not be finnished by upper layer
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
* @param[out] finish Set to zero, if request should not be finnished by upper layer
* @retval 0 OK
* @retval -1 Error
*/
int
api_stream(clicon_handle h,
@ -431,7 +442,7 @@ api_stream(clicon_handle h,
struct stream_child *sc;
#endif
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
streampath = clicon_option_str(h, "CLICON_STREAM_PATH");
if ((path = restconf_uripath(h)) == NULL)
goto done;
@ -441,33 +452,33 @@ api_stream(clicon_handle h,
/* Sanity check of path. Should be /stream/<name> */
if (pn != 3){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
if (strlen(pvec[0]) != 0){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
if (strcmp(pvec[1], streampath)){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
if ((method = pvec[2]) == NULL){
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
goto done;
goto done;
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
clicon_debug(1, "%s: method=%s", __FUNCTION__, method);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: method=%s", __FUNCTION__, method);
if (uri_str2cvec(path, '/', '=', 1, &pcvec) < 0) /* rest url eg /album=ricky/foo */
goto done;
@ -475,7 +486,7 @@ api_stream(clicon_handle h,
if ((cb = restconf_get_indata(req)) == NULL)
goto done;
indata = cbuf_get(cb);
clicon_debug(1, "%s DATA=%s", __FUNCTION__, indata);
clixon_debug(CLIXON_DBG_DEFAULT, "%s DATA=%s", __FUNCTION__, indata);
/* If present, check credentials. See "plugin_credentials" in plugin
* See RFC 8040 section 2.5
@ -501,22 +512,22 @@ api_stream(clicon_handle h,
cbuf_free(cbret);
#endif /* STREAM_FORK */
/* Listen to backend socket */
if (clixon_event_reg_fd(s,
restconf_stream_cb,
req,
"stream socket") < 0)
goto done;
if (clixon_event_reg_fd(rfcgi->listen_sock,
stream_checkuplink,
if (clixon_event_reg_fd(s,
restconf_stream_cb,
req,
"stream socket") < 0)
goto done;
clicon_debug(1, "%s before loop", __FUNCTION__);
if (clixon_event_reg_fd(rfcgi->listen_sock,
stream_checkuplink,
req,
"stream socket") < 0)
goto done;
clixon_debug(CLIXON_DBG_DEFAULT, "%s before loop", __FUNCTION__);
/* Poll upstream errors */
stream_timeout(0, req);
/* Start loop */
clixon_event_loop(h);
clicon_debug(1, "%s after loop", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s after loop", __FUNCTION__);
clicon_rpc_close_session(h);
clixon_event_unreg_fd(s, restconf_stream_cb);
close(s);
@ -551,7 +562,7 @@ api_stream(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (xerr)
xml_free(xerr);
if (pvec)

View file

@ -97,10 +97,10 @@ snmp_common_handler(netsnmp_mib_handler *handler,
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
oid_cbuf(cb, (*shp)->sh_oid, (*shp)->sh_oidlen);
oid_cbuf(cb, (*shp)->sh_oid, (*shp)->sh_oidlen);
if (oid_eq(requestvb->name, requestvb->name_length,
(*shp)->sh_oid, (*shp)->sh_oidlen) == 0){ /* equal */
clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
cbuf_get(cb),
snmp_msg_int2str(reqinfo->mode),
request->inclusive, tablehandler?"table":"scalar");
@ -110,7 +110,7 @@ snmp_common_handler(netsnmp_mib_handler *handler,
oid_cbuf(cb, requestvb->name, requestvb->name_length);
cprintf(cb, ")");
// nhreg->rootoid same as shp
clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
cbuf_get(cb),
snmp_msg_int2str(reqinfo->mode),
request->inclusive, tablehandler?"table":"scalar");
@ -122,7 +122,8 @@ snmp_common_handler(netsnmp_mib_handler *handler,
return retval;
}
/*!
/*! scalar return
*
* @param[in] reqinfo Agent transaction request structure
* @param[in] request The netsnmp request info structure.
* @retval 0 OK
@ -138,7 +139,7 @@ snmp_scalar_return(cxobj *xs,
{
int retval = -1;
int asn1type;
char *xmlstr = NULL;
char *xmlstr = NULL;
char *defaultval = NULL;
u_char *snmpval = NULL;
size_t snmplen = 0;
@ -180,7 +181,7 @@ snmp_scalar_return(cxobj *xs,
if ((ret = type_xml2snmp(xmlstr, &asn1type, &snmpval, &snmplen, &reason)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "%s %s", __FUNCTION__, reason);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, reason);
if ((ret = netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
@ -210,15 +211,16 @@ snmp_scalar_return(cxobj *xs,
}
/*! Scalar handler, set a value to clixon
*
* get xpath: see yang2api_path_fmt / api_path2xpath
* @param[in] h Clixon handle
* @param[in] ys Yang node
* @param[in] cvk Vector of index/Key variables, if any
* @param[in] defaultval Default value
* @param[in] reqinfo Agent transaction request structure
* @param[in] request The netsnmp request info structure.
* @param[in] request The netsnmp request info structure.
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
static int
snmp_scalar_get(clicon_handle h,
@ -244,7 +246,7 @@ snmp_scalar_get(clicon_handle h,
cxobj *xcache = NULL;
char *body = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* Prepare backend call by constructing namespace context */
if (xml_nsctx_yang(ys, &nsc) < 0)
goto done;
@ -266,7 +268,7 @@ snmp_scalar_get(clicon_handle h,
}
x = xpath_first(xt, nsc, "%s", xpath);
}
/*
/*
* The xml to snmp value conversion is done in two steps:
* 1. From XML to SNMP string, there is a special case for enumeration, and for default value
* 2. From SNMP string to SNMP binary value which invloves parsing
@ -298,7 +300,7 @@ snmp_scalar_get(clicon_handle h,
if ((ret = type_xml2snmp(xmlstr, &asn1type, &snmpval, &snmplen, &reason)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "%s %s", __FUNCTION__, reason);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, reason);
if ((ret = netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
@ -344,7 +346,7 @@ snmp_yang2xml(cxobj *xtop,
int i;
int ret;
yang_stmt *yspec;
yspec = ys_spec(ys);
if (yang2api_path_fmt(ys, 0, &api_path_fmt) < 0)
goto done;
@ -374,15 +376,16 @@ snmp_yang2xml(cxobj *xtop,
return retval;
}
/*! Scalar handler, get a value from clixon
/*! Scalar handler, get a value from clixon
*
* @param[in] h Clixon handle
* @param[in] ys Yang node
* @param[in] cvk Vector of index/Key variables, if any
* @param[in] valstr0 Pre-set value string, ignore requestvb
* @param[in] reqinfo Agent transaction request structure
* @param[in] request The netsnmp request info structure.
* @param[in] request The netsnmp request info structure.
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* @note contains special logic for rowstatus handling
*/
static int
@ -404,13 +407,13 @@ snmp_scalar_set(clicon_handle h,
int asn1_type;
enum operation_type op = OP_MERGE;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((xtop = xml_new(NETCONF_INPUT_CONFIG, NULL, CX_ELMNT)) == NULL)
goto done;
if (snmp_yang2xml(xtop, ys, cvk, &xbot) < 0)
goto done;
if ((xb = xml_new("body", xbot, CX_BODY)) == NULL)
goto done;
goto done;
/* Extended */
if (type_yang2asn1(ys, &asn1_type, 1) < 0)
goto done;
@ -473,7 +476,7 @@ snmp_cache_row_op(clicon_handle h,
cxobj *xbot = NULL;
cxobj *xa;
cxobj *xcache;
if (xml_nsctx_yang(yp, &nsc) < 0)
goto done;
/* Create xpath from yang */
@ -499,7 +502,7 @@ snmp_cache_row_op(clicon_handle h,
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
}
if (clixon_xml2cbuf(cb, xtop, 0, 0, NULL, -1, 0) < 0)
goto done;
if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0)
@ -552,8 +555,8 @@ snmp_cache_set(clicon_handle h,
yang_stmt *yspec;
int isrowstatus = 0;
cxobj *xcache = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
goto done;
@ -563,7 +566,7 @@ snmp_cache_set(clicon_handle h,
if (snmp_yang2xml(xtop, ys, cvk, &xbot) < 0)
goto done;
if ((xb = xml_new("body", xbot, CX_BODY)) == NULL)
goto done;
goto done;
/* Extended */
if (type_yang2asn1(ys, &asn1_type, 1) < 0)
goto done;
@ -596,8 +599,8 @@ snmp_cache_set(clicon_handle h,
if (snmp_cache_row_op(h, yang_parent_get(ys), cvk, "merge", 1) < 0)
goto done;
}
else if (strcmp(valstr, "destroy") == 0){
clicon_debug(1, "%s %d", __FUNCTION__, rowstatus);
else if (strcmp(valstr, "destroy") == 0){
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, rowstatus);
/* Dont send delete to backend if notInService(2) */
if (snmp_cache_row_op(h, yang_parent_get(ys), cvk, "delete", rowstatus!=2) < 0)
goto done;
@ -640,7 +643,7 @@ snmp_cache_set(clicon_handle h,
* @param[in] cvk Vector of index/Key variables, if any
* @param[out] rowstatus Enmu rowstatus: 0 invalid, 1 active, etc
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
static int
snmp_table_rowstatus_get(clicon_handle h,
@ -658,8 +661,8 @@ snmp_table_rowstatus_get(clicon_handle h,
char *body;
char *intstr;
char *reason = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* Prepare backend call by constructing namespace context */
if (xml_nsctx_yang(ys, &nsc) < 0)
goto done;
@ -672,14 +675,14 @@ snmp_table_rowstatus_get(clicon_handle h,
if ((ret = yang_enum2valstr(yrestype, body, &intstr)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "%s %s invalid or not found", __FUNCTION__, body);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s invalid or not found", __FUNCTION__, body);
*rowstatus = 0;
}
else {
if ((ret = parse_int32(intstr, rowstatus, &reason)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "%s parse_int32: %s", __FUNCTION__, reason);
clixon_debug(CLIXON_DBG_DEFAULT, "%s parse_int32: %s", __FUNCTION__, reason);
*rowstatus = 0;
}
}
@ -718,7 +721,7 @@ clixon_snmp_scalar_handler1(netsnmp_mib_handler *handler,
netsnmp_variable_list *requestvb = request->requestvb;
int ret;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (snmp_common_handler(handler, nhreg, reqinfo, request, 0, &sh) < 0)
goto done;
/* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */
@ -740,7 +743,7 @@ clixon_snmp_scalar_handler1(netsnmp_mib_handler *handler,
if (type_yang2asn1(sh->sh_ys, &asn1_type, 0) < 0)
goto done;
if (requestvb->type != asn1_type){
clicon_debug(1, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type);
if ((ret = netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto ok;
@ -753,7 +756,7 @@ clixon_snmp_scalar_handler1(netsnmp_mib_handler *handler,
if (snmp_scalar_set(sh->sh_h, sh->sh_ys, NULL, NULL, reqinfo, request) < 0)
goto done;
/*
* There does not seem to be a separate validation action and commit does not
* There does not seem to be a separate validation action and commit does not
* return an error.
* Therefore validation is done here directly as well as discard if it fails.
*/
@ -781,13 +784,13 @@ clixon_snmp_scalar_handler1(netsnmp_mib_handler *handler,
break;
case MODE_SET_UNDO: /* 5 */
if (clicon_rpc_discard_changes(sh->sh_h) < 0)
goto done;
goto done;
break;
}
ok:
retval = SNMP_ERR_NOERROR;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -797,6 +800,8 @@ clixon_snmp_scalar_handler1(netsnmp_mib_handler *handler,
* @param[in] nhreg Root registration info.
* @param[in] reqinfo Agent transaction request structure
* @param[in] requests The netsnmp request info structure.
* @retval SNMP_ERR_NOERROR OK
* @retval -1 Error
* @see clixon_snmp_table_handler
*/
int
@ -809,7 +814,7 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
netsnmp_request_info *req;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
for (req = requests; req; req = req->next){
ret = clixon_snmp_scalar_handler1(handler, nhreg, reqinfo, req);
if (ret != SNMP_ERR_NOERROR){
@ -836,9 +841,9 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
* @param[in] oidslen OID length of scalar
* @param[in] reqinfo Agent transaction request structure
* @param[in] request The netsnmp request info structure.
* @retval -1 Error
* @retval 0 Object not found
* @retval 1 OK
* @retval 0 Object not found
* @retval -1 Error
*/
static int
snmp_table_get(clicon_handle h,
@ -889,7 +894,7 @@ snmp_table_get(clicon_handle h,
*/
if (yang_extension_value_opt(ys, "smiv2:defval", NULL, &defaultval) < 0)
goto done;
/* Create xpath with right keys from later part of OID
* Inverse of snmp_str2oid
*/
@ -906,12 +911,12 @@ snmp_table_get(clicon_handle h,
oidi = oids+oidtlen+1;
/* Add keys */
for (i=0; i<cvec_len(cvk_val); i++){
cv = cvec_i(cvk_val, i);
cv = cvec_i(cvk_val, i);
if ((yk = yang_find(yt, Y_LEAF, cv_string_get(cv))) == NULL){
clicon_err(OE_YANG, 0, "List key %s not found", cv_string_get(cv));
goto done;
}
if (snmp_oid2str(&oidi, &oidilen, yk, cv) < 0)
if (snmp_oid2str(&oidi, &oidilen, yk, cv) < 0)
goto done;
}
if (oidilen != 0){
@ -938,6 +943,7 @@ snmp_table_get(clicon_handle h,
}
/*! Set value in table
*
* Get yang of leaf from first part of OID
* Create xpath with right keys from later part of OID
* Query clixon if object exists, if so return value
@ -948,9 +954,9 @@ snmp_table_get(clicon_handle h,
* @param[in] reqinfo Agent transaction request structure
* @param[in] request The netsnmp request info structure.
* @param[out] err Error code if failed (retval = 0)
* @retval -1 Error
* @retval 0 Failed, err set
* @retval 1 OK
* @retval 0 Failed, err set
* @retval -1 Error
*/
static int
snmp_table_set(clicon_handle h,
@ -1047,7 +1053,7 @@ snmp_table_set(clicon_handle h,
goto done;
requestvb = request->requestvb;
if (requestvb->type != asn1_type){
clicon_debug(1, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type);
if ((ret = netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto ok;
@ -1069,12 +1075,12 @@ snmp_table_set(clicon_handle h,
oidi = oids+oidtlen+1;
/* Add keys */
for (i=0; i<cvec_len(cvk_val); i++){
cv = cvec_i(cvk_val, i);
cv = cvec_i(cvk_val, i);
if ((yk = yang_find(yt, Y_LEAF, cv_string_get(cv))) == NULL){
clicon_err(OE_YANG, 0, "List key %s not found", cv_string_get(cv));
goto done;
}
if (snmp_oid2str(&oidi, &oidilen, yk, cv) < 0)
if (snmp_oid2str(&oidi, &oidilen, yk, cv) < 0)
goto done;
}
if (oidilen != 0){
@ -1090,7 +1096,7 @@ snmp_table_set(clicon_handle h,
cvk_val,
&rowstatus)) < 0)
goto done;
}
}
else{
/* If no rowstatus object, default to active */
rowstatus = 1;
@ -1152,6 +1158,7 @@ snmp_table_set(clicon_handle h,
}
/*! Find "next" object from oids minus key and return that.
*
* @param[in] h Clixon handle
* @param[in] ylist Yang of table (of list type)
* @param[in] oids OID of ultimate scalar value
@ -1189,12 +1196,12 @@ snmp_table_getnext(clicon_handle h,
size_t oidklen = MAX_OID_LEN;
oid oidnext[MAX_OID_LEN] = {0x7fffffff,}; /* Next oid: start with high value */
size_t oidnextlen = MAX_OID_LEN;
int found = 0;
int found = 0;
cxobj *xnext = NULL;
yang_stmt *ynext = NULL;
cbuf *cb = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((ys = yang_parent_get(ylist)) == NULL ||
yang_keyword_get(ys) != Y_CONTAINER){
clicon_err(OE_YANG, EINVAL, "ylist parent is not list");
@ -1256,7 +1263,7 @@ snmp_table_getnext(clicon_handle h,
goto done;
}
oid_cbuf(cb, oidnext, oidnextlen);
clicon_debug(1, "%s next: %s", __FUNCTION__, cbuf_get(cb));
clixon_debug(CLIXON_DBG_DEFAULT, "%s next: %s", __FUNCTION__, cbuf_get(cb));
}
retval = found;
done:
@ -1267,7 +1274,7 @@ snmp_table_getnext(clicon_handle h,
if (xt)
xml_free(xt);
if (nsc)
xml_nsctx_free(nsc);
xml_nsctx_free(nsc);
return retval;
}
@ -1277,6 +1284,8 @@ snmp_table_getnext(clicon_handle h,
* @param[in] nhreg Root registration info.
* @param[in] reqinfo Agent transaction request structure
* @param[in] request The netsnmp request info structure.
* @retval 0 OK
* @retval -1 Error
*/
static int
clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
@ -1292,12 +1301,12 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
int ret;
netsnmp_variable_list *requestvb;
int err = 0;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if ((ret = snmp_common_handler(handler, nhreg, reqinfo, request, 1, &sh)) < 0)
goto done;
if (sh->sh_ys == NULL){
clicon_debug(1, "%s Error table not registered", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error table not registered", __FUNCTION__);
goto ok;
}
requestvb = request->requestvb;
@ -1306,7 +1315,7 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
/* Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name
*/
if ((ret = snmp_table_get(sh->sh_h, sh->sh_ys,
sh->sh_oid2, sh->sh_oid2len,
sh->sh_oid2, sh->sh_oid2len,
requestvb->name, requestvb->name_length,
reqinfo, request)) < 0)
goto done;
@ -1315,7 +1324,7 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
}
clicon_debug(1, "%s Nosuchinstance", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Nosuchinstance", __FUNCTION__);
}
break;
case MODE_GETNEXT: // 161
@ -1330,13 +1339,13 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
}
clicon_debug(1, "%s No such object", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s No such object", __FUNCTION__);
}
break;
case MODE_SET_RESERVE1: // 0
if (!yang_config_ancestor(sh->sh_ys)){
netsnmp_request_set_error(request, SNMP_ERR_NOTWRITABLE);
goto done;;
goto done;
}
// Check types: compare type in requestvb to yang type (or do later)
break;
@ -1352,7 +1361,7 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
}
clicon_debug(1, "%s Nosuchinstance", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Nosuchinstance", __FUNCTION__);
}
/*
* There does not seem to be a separate validation action and commit does not
@ -1380,7 +1389,7 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
break;
case MODE_SET_UNDO : // 5
if (clicon_rpc_discard_changes(sh->sh_h) < 0)
goto done;
goto done;
break;
}
ok:
@ -1401,6 +1410,8 @@ clixon_snmp_table_handler1(netsnmp_mib_handler *handler,
* @param[in] nhreg Root registration info.
* @param[in] reqinfo Agent transaction request structure
* @param[in] requests The netsnmp request info structure.
* @retval 0 OK
* @retval -1 Error
* @see clixon_snmp_scalar_handler
*/
int
@ -1413,7 +1424,7 @@ clixon_snmp_table_handler(netsnmp_mib_handler *handler,
netsnmp_request_info *req;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
for (req = requests; req; req = req->next){
ret = clixon_snmp_table_handler1(handler, nhreg, reqinfo, req);
if (ret != SNMP_ERR_NOERROR){

View file

@ -217,6 +217,7 @@ yang_type_to_snmp(yang_stmt *ytype,
}
/*! Translate from snmp string to int representation
*
* @note Internal snmpd, maybe find something in netsnmpd?
*/
int
@ -237,8 +238,8 @@ snmp_msg_int2str(int msg)
* @param[in] objid0len Length of first OID vector
* @param[in] objid1 Second OID vector
* @param[in] objid1len Length of second OID vector
* @retval 0 Equal
* @retval !=0 Not equal, see man memcmp
* @retval 0 Equal
* @retval !=0 Not equal, see man memcmp
* Should really be netsnmp lib function, but cant find any?
*/
int
@ -268,6 +269,7 @@ oid_eq(const oid *objid0,
}
/*! Append a second OID to a first
*
* @param[in,out] objid0 First OID vector
* @param[in,out] objid0len Length of first OID vector
* @param[in] objid1 Second OID vector
@ -295,6 +297,7 @@ oid_append(const oid *objid0,
}
/*! Print objid to file
*
* @see fprint_objid but prints symbolic
*/
int
@ -359,7 +362,7 @@ snmp_yang_type_get(yang_stmt *ys,
}
if (yang_path_arg(ys, yang_argument_get(ypath), &yref) < 0)
goto done;
if (yref == NULL){
if (yref == NULL){
clicon_err(OE_YANG, 0, "No referred YANG node found for leafref path %s", yang_argument_get(ypath));
goto done;
}
@ -401,7 +404,7 @@ snmp_yang_type_get(yang_stmt *ys,
* @param[out] exist The extension exists.
* @param[out] value clispec operator (hide/none) - direct pointer into yang, dont free
* @retval 0 OK: Look in exist and value for return value
* @retval -1 Error
* @retval -1 Error
*
* @note This optimizatoin may not work if the unknown statements are augmented in ys.
* @see yang_extension_value for the generic function
@ -443,6 +446,7 @@ yang_extension_value_opt(yang_stmt *ys,
}
/*! Given a YANG node, return SMIv2 oid extension as OID
*
* @param[in] yn Yang node
* @param[out] objid OID vector, assume allocated with MAX_OID_LEN > oidlen
* @param[out] objidlen Length of OID vector on return
@ -461,7 +465,7 @@ yangext_oid_get(yang_stmt *yn,
int exist = 0;
char *oidstr = NULL;
yang_stmt *yref = NULL;
if (yang_keyword_get(yn) == Y_LEAF){
if (snmp_yang_type_get(yn, &yref, NULL, NULL, NULL) < 0)
goto done;
@ -472,7 +476,7 @@ yangext_oid_get(yang_stmt *yn,
if (yang_extension_value_opt(yref, "smiv2:oid", &exist, &oidstr) < 0)
goto done;
if (exist == 0 || oidstr == NULL){
clicon_debug(1, "OID not found as SMIv2 yang extension of %s", yang_argument_get(yref));
clixon_debug(CLIXON_DBG_DEFAULT, "OID not found as SMIv2 yang extension of %s", yang_argument_get(yref));
goto fail;
}
if (snmp_parse_oid(oidstr, objid, objidlen) == NULL){
@ -490,22 +494,23 @@ yangext_oid_get(yang_stmt *yn,
}
/*! Given a YANG node, return 1 if leaf has oid directive in it, otherwise 0
*
* @param[in] yn Yang node
* @retval 1 found
* @retval 0 not found
*/
int
yangext_is_oid_exist(yang_stmt *yn) {
yangext_is_oid_exist(yang_stmt *yn)
{
int exist = 0;
char *oidstr = NULL;
if ((yang_keyword_get(yn) != Y_LEAF) ||
(yang_extension_value_opt(yn, "smiv2:oid", &exist, &oidstr) < 0) ||
(exist == 0) ||
(oidstr == NULL)) {
(yang_extension_value_opt(yn, "smiv2:oid", &exist, &oidstr) < 0) ||
(exist == 0) ||
(oidstr == NULL)) {
return 0;
}
}
else {
return 1;
}
@ -513,6 +518,7 @@ yangext_is_oid_exist(yang_stmt *yn) {
/*! Duplicate clixon snmp handler struct
*
* Use signature of libnetsnmp data_clone field of netsnmp_mib_handler in agent_handler.h
* @param[in] arg
*/
@ -538,6 +544,7 @@ snmp_handle_clone(void *arg)
}
/*! Free clixon snmp handler struct
*
* Use signature of libnetsnmp data_free field of netsnmp_mib_handler in agent_handler.h
* @param[in] arg
*/
@ -564,8 +571,8 @@ snmp_handle_free(void *arg)
* @param[in] ys YANG leaf node
* @param[out] asn1_type ASN.1 type id
* @param[in] extended Special case clixon extended types used in xml<->asn1 data conversions
* @retval 0 OK
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
* @see type_yang2snmp, yang only
* @note there are some special cases where extended clixon asn1-types are used to convey info
* to type_snmpstr2val, these types are prefixed with CLIXON_ASN_
@ -602,7 +609,7 @@ type_yang2asn1(yang_stmt *ys,
char *display_hint = NULL;
yrp = yang_parent_get(yrestype);
if (yang_extension_value_opt(yrp, "smiv2:display-hint", NULL, &display_hint) < 0)
goto done;
goto done;
/* RFC2578/2579 but maybe all strings with display-hint should use this, eg exist>0? */
if (display_hint &&
@ -628,7 +635,7 @@ type_yang2asn1(yang_stmt *ys,
* @param[out] valstr Clixon/yang/xml string value, free after use)
* @retval 1 OK, and valstr set
* @retval 0 Invalid value or type
* @retval -1 Error
* @retval -1 Error
* @see type_xml2snmp for snmpget
*/
int
@ -648,7 +655,7 @@ type_snmp2xml(yang_stmt *ys,
yang_stmt *yrestype = NULL;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (valstr == NULL){
clicon_err(OE_UNIX, EINVAL, "valstr is NULL");
goto done;
@ -668,7 +675,7 @@ type_snmp2xml(yang_stmt *ys,
cvtype = cv_str2type(cvstr);
if ((cv = cv_new(cvtype)) == NULL){
clicon_err(OE_UNIX, errno, "cv_new");
goto done;
goto done;
}
switch (*asn1type){
case CLIXON_ASN_ROWSTATUS:
@ -706,7 +713,7 @@ type_snmp2xml(yang_stmt *ys,
break;
case ASN_IPADDRESS:{
struct in_addr addr;
memcpy(&addr.s_addr, requestvb->val.string, 4);
memcpy(&addr.s_addr, requestvb->val.string, 4);
cv_string_set(cv, inet_ntoa(addr));
break;
}
@ -716,7 +723,7 @@ type_snmp2xml(yang_stmt *ys,
break;
case CLIXON_ASN_PHYS_ADDR:
cv_string_set(cv, ether_ntoa((const struct ether_addr *)requestvb->val.string));
*asn1type = ASN_OCTET_STR;
*asn1type = ASN_OCTET_STR;
break;
case ASN_OCTET_STR: // 4
cv_string_set(cv, (char*)requestvb->val.string);
@ -732,7 +739,7 @@ type_snmp2xml(yang_stmt *ys,
}
default:
assert(0); // XXX
clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype));
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype));
if ((ret = netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
@ -746,7 +753,7 @@ type_snmp2xml(yang_stmt *ys,
}
retval = 1;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (origtype)
free(origtype);
if (cv)
@ -766,7 +773,7 @@ type_snmp2xml(yang_stmt *ys,
* @param[out] xmlstr1 XML string ready for translation
* @retval 1 OK
* @retval 0 Invalid type
* @retval -1 Error
* @retval -1 Error
* @see type_snmp2xml for snmpset
*/
int
@ -793,7 +800,7 @@ type_xml2snmp_pre(char *xmlstr0,
if ((ret = yang_enum2valstr(yrestype, xmlstr0, &str)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "Invalid enum valstr %s", xmlstr0);
clixon_debug(CLIXON_DBG_DEFAULT, "Invalid enum valstr %s", xmlstr0);
goto fail;
}
}
@ -802,7 +809,7 @@ type_xml2snmp_pre(char *xmlstr0,
* 1) there is no code for ASN_BOOLEAN and
* 2) Truthvalue actually translates to enum true(1)/false(2)
*/
else if (strcmp(restype, "boolean") == 0){
else if (strcmp(restype, "boolean") == 0){
if (strcmp(xmlstr0, "false")==0)
str = "2";
else
@ -819,7 +826,7 @@ type_xml2snmp_pre(char *xmlstr0,
if ((ret = parse_dec64(xmlstr0, cv_dec64_n_get(cv), &num, NULL)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "Invalid decimal64 valstr %s", xmlstr0);
clixon_debug(CLIXON_DBG_DEFAULT, "Invalid decimal64 valstr %s", xmlstr0);
goto fail;
}
cv_dec64_i_set(cv, num);
@ -835,7 +842,7 @@ type_xml2snmp_pre(char *xmlstr0,
}
retval = 1;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
@ -904,7 +911,7 @@ type_xml2snmp(char *snmpstr,
oid oid1[MAX_OID_LEN] = {0,};
size_t sz1 = MAX_OID_LEN;
if (snmp_parse_oid(snmpstr, oid1, &sz1) == NULL){
clicon_debug(1, "Failed to parse OID %s", snmpstr);
clixon_debug(CLIXON_DBG_DEFAULT, "Failed to parse OID %s", snmpstr);
goto fail;
}
*snmplen = sizeof(oid)*sz1;
@ -960,7 +967,7 @@ type_xml2snmp(char *snmpstr,
}
memset(*snmpval, 0, *snmplen + 1);
if ((eaddr = ether_aton(snmpstr)) == NULL){
clicon_debug(1, "ether_aton(%s)", snmpstr);
clixon_debug(CLIXON_DBG_DEFAULT, "ether_aton(%s)", snmpstr);
goto fail;
}
memcpy(*snmpval, eaddr, sizeof(*eaddr));
@ -980,7 +987,7 @@ type_xml2snmp(char *snmpstr,
}
retval = 1;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
return retval;
fail:
retval = 0;
@ -988,6 +995,7 @@ type_xml2snmp(char *snmpstr,
}
/*! Construct an xpath from yang statement, internal fn using cb
*
* Recursively construct it to the top.
* @param[in] ys Yang statement
* @param[in] keyvec Cvec of key values
@ -995,9 +1003,9 @@ type_xml2snmp(char *snmpstr,
* @retval 0 OK
* @retval -1 Error
* @see yang2xpath
*/
*/
static int
snmp_yang2xpath_cb(yang_stmt *ys,
snmp_yang2xpath_cb(yang_stmt *ys,
cvec *keyvec,
cbuf *cb)
{
@ -1006,13 +1014,13 @@ snmp_yang2xpath_cb(yang_stmt *ys,
cvec *cvk = NULL; /* vector of index keys */
int retval = -1;
char *prefix = NULL;
if ((yp = yang_parent_get(ys)) == NULL){
clicon_err(OE_YANG, EINVAL, "yang expected parent %s", yang_argument_get(ys));
goto done;
}
if (yp != NULL && /* XXX rm */
yang_keyword_get(yp) != Y_MODULE &&
yang_keyword_get(yp) != Y_MODULE &&
yang_keyword_get(yp) != Y_SUBMODULE){
if (snmp_yang2xpath_cb(yp, keyvec, cb) < 0) /* recursive call */
goto done;
@ -1053,16 +1061,17 @@ snmp_yang2xpath_cb(yang_stmt *ys,
}
/*! Construct an xpath from yang statement, limited to SNMP table translations
*
* Recursively construct it to the top.
* @param[in] ys Yang statement
* @param[in] keyvec Cvec of key values
* @param[out] xpath Malloced xpath string, use free() after use
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* @note
* 1. This should really be in a core .c file, like clixon_yang, BUT
* 2. It is far from complete so maybe keep it here as a special case
*/
*/
int
snmp_yang2xpath(yang_stmt *ys,
cvec *keyvec,
@ -1089,18 +1098,21 @@ snmp_yang2xpath(yang_stmt *ys,
}
/*! Translate from xml body string to SMI OID representation
*
* For ints this is one to one, eg 42 -> 42
* But for eg strings this is more complex, eg foo -> 3.6.22.22 (or something,...)
* @param[in] str XML body string
* @param[in] yi Yang statement
* @param[out] objid OID vector
* @param[out] objidlen Length of OID vector
* @retval 0 OK
* @retval -1 Error
*/
int
snmp_str2oid(char *str,
yang_stmt *yi,
oid *objid,
size_t *objidlen)
size_t *objidlen)
{
int retval = -1;
int asn1_type;
@ -1135,12 +1147,15 @@ snmp_str2oid(char *str,
}
/*! Translate from SMI OID representation to name
*
* For ints this is one to one, eg 42 -> 42
* But for eg strings this is more complex, eg foo -> 3.6.22.22 (or something,...)
* @param[in,out] oidi ObjID vector
* @param[in,out] oidilen Length of ObjID vector
* @param[in] yk Yang statement of key
* @param[out] cv CLIgen variable string notation as "x.y.z"
* @retval 0 OK
* @retval -1 Error
* @see rfc2578 Section 7.7
*/
int
@ -1223,7 +1238,7 @@ clixon_snmp_err_cb(void *handle,
{
const char *errstr;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (suberr < 0){
if (suberr < -CLIXON_ERR_SNMP_MIB){
switch (suberr+CLIXON_ERR_SNMP_MIB){
@ -1262,9 +1277,9 @@ clixon_snmp_err_cb(void *handle,
* @param[in] cvk_name Vector of list keys
* @param[out] cvk_val Vector of XML key values
* @param[out] objidk OID key part, to be appended to node OID
* @retval -1 Error
* @retval 0 Invalid (not all indexes present)
* @retval 1 OK
* @retval 0 Invalid (not all indexes present)
* @retval -1 Error
* Both cvk_val and cvk_oid can be re-used in successive calls but need to be freed w cvec_free after use
*/
int
@ -1281,7 +1296,7 @@ snmp_xmlkey2val_oid(cxobj *xentry,
cg_var *cv0;
oid objid[MAX_OID_LEN] = {0,};
size_t objidlen = MAX_OID_LEN;
*objidklen = 0;
if (cvk_val){
if (*cvk_val){
@ -1297,11 +1312,11 @@ snmp_xmlkey2val_oid(cxobj *xentry,
}
}
for (i=0; i<cvec_len(cvk_name); i++){
cv0 = cvec_i(cvk_name, i);
cv0 = cvec_i(cvk_name, i);
if ((xi = xml_find_type(xentry, NULL, cv_string_get(cv0), CX_ELMNT)) == NULL)
break;
if (cvk_val){
cv = cvec_i(*cvk_val, i);
cv = cvec_i(*cvk_val, i);
if (cv_string_set(cv, xml_body(xi)) < 0){
clicon_err(OE_UNIX, errno, "cv_string_set");
goto done;
@ -1326,6 +1341,7 @@ snmp_xmlkey2val_oid(cxobj *xentry,
* Peeks into internal lib global variables, may be sensitive to library change
*/
/*! Check if netsnmp is connected
*
* @retval 1 yes, running
* @retval 0 No, not running
* XXX: this peeks into the "main_session" global variable in agent/snmp_agent.c
@ -1335,11 +1351,12 @@ int
clixon_snmp_api_agent_check(void)
{
extern netsnmp_session *main_session;
return (main_session != NULL) ? 1 : 0;
}
/*! Cleanup remaining libnetsnmb memory
*
* XXX: this peeks into the "tclist" global variable in snmplib/parse.c
* Tried to find API function but failed
*/
@ -1347,19 +1364,20 @@ int
clixon_snmp_api_agent_cleanup(void)
{
extern void *tclist;
if (tclist)
free(tclist);
return 0;
}
/*! See if oid is registered
*
* This is good enough for add,
* But for delete a more advanced function is needed
* @see netsnmp_subtree_load
* @retval -1 Error
* @retval 0 Not found
* @retval 1 Found
* @retval 0 Not found
* @retval -1 Error
*/
int
clixon_snmp_api_oid_find(oid *oid0,
@ -1367,7 +1385,7 @@ clixon_snmp_api_oid_find(oid *oid0,
{
int retval = -1;
netsnmp_subtree *tree1 = NULL;
if ((tree1 = netsnmp_subtree_find(oid0, oid0len, NULL, "")) != NULL &&
oid_eq(oid0, oid0len, tree1->name_a, tree1->namelen)==0){
retval = 1;

View file

@ -57,7 +57,7 @@ extern "C" {
#define CLIXON_ASN_EXTRAS 253 /* Special case clixon address >= this */
#define CLIXON_ASN_PHYS_ADDR 253 /* Special case phy-address */
#define CLIXON_ASN_FIXED_STRING 254 /* RFC2578 Sec 7.7: String-valued, fixed-length */
#define CLIXON_ASN_ROWSTATUS 255
#define CLIXON_ASN_ROWSTATUS 255
/*
* Types
@ -70,10 +70,10 @@ struct clixon_snmp_handle {
oid sh_oid[MAX_OID_LEN]; /* OID of registered table (list) */
size_t sh_oidlen;
oid sh_oid2[MAX_OID_LEN]; /* OID of registered container */
size_t sh_oid2len;
size_t sh_oid2len;
char *sh_default; /* MIB default value leaf only */
cvec *sh_cvk_orig; /* Index/Key variable values (original) */
netsnmp_table_registration_info *sh_table_info; /* To mimic table-handler in libnetsnmp code
netsnmp_table_registration_info *sh_table_info; /* To mimic table-handler in libnetsnmp code
* save only to free properly */
};
typedef struct clixon_snmp_handle clixon_snmp_handle;

View file

@ -74,7 +74,7 @@
/* Forward */
static int clixon_snmp_input_cb(int s, void *arg);
/*! Return (hardcoded) pid file
*/
static char*
@ -84,22 +84,24 @@ clicon_snmp_pidfile(clicon_handle h)
}
/*! Signal terminates process
*
* Just set exit flag for proper exit in event loop
*/
static void
clixon_snmp_sig_term(int arg)
{
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
__PROGRAM__, __FUNCTION__, getpid(), arg);
/* This should ensure no more accepts or incoming packets are processed because next time eventloop
* is entered, it will terminate.
* However there may be a case of sockets closing rather abruptly for clients
*/
clixon_exit_set(1);
clixon_exit_set(1);
}
/*! Clean and close all state of netconf process (but dont exit).
* Cannot use h after this
/*! Clean and close all state of netconf process (but dont exit).
*
* Cannot use h after this
* @param[in] h Clixon handle
*/
static int
@ -139,10 +141,12 @@ snmp_terminate(clicon_handle h)
/*! Get which sockets are used from SNMP API, the register single sockets into clixon event system
*
* @param[in] h Clixon handle
* @param[in] register if 1 register snmp sockets with event handler. If 0 close and unregister
* @param[in] register If 1 register snmp sockets with event handler. If 0 close and unregister
* @retval 0 OK
* @retval -1 Error
* This is a workaround for netsnmps API usiing fdset:s, instead an fdset is created before calling
* the snmp api
* if you use select(), see snmp_select_info() in snmp_api(3)
* if you use select(), see snmp_select_info() in snmp_api(3)
* snmp_select_info(int *numfds, fd_set *fdset, struct timeval *timeout, int *block)
* @see clixon_snmp_input_cb
*/
@ -166,7 +170,7 @@ clixon_snmp_fdset_register(clicon_handle h,
/* eg 4, 6, 8 */
for (s=0; s<numfds; s++){
if (FD_ISSET(s, &readfds)){
clicon_debug(1, "%s %d", __FUNCTION__, s);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, s);
if (regfd){
if (clixon_event_reg_fd(s, clixon_snmp_input_cb, h, "snmp socket") < 0)
goto done;
@ -183,14 +187,17 @@ clixon_snmp_fdset_register(clicon_handle h,
return retval;
}
/*! Callback for single socket
/*! Callback for single socket
*
* This is a workaround for netsnmps API usiing fdset:s, instead an fdset is created before calling
* the snmp api
* @param[in] s Read socket
* @param[in] arg Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
static int
clixon_snmp_input_cb(int s,
clixon_snmp_input_cb(int s,
void *arg)
{
int retval = -1;
@ -198,7 +205,7 @@ clixon_snmp_input_cb(int s,
clicon_handle h = (clicon_handle)arg;
int ret;
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, s);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, s);
FD_ZERO(&readfds);
FD_SET(s, &readfds);
(void)snmp_read(&readfds);
@ -232,8 +239,11 @@ clixon_snmp_input_cb(int s,
}
/*! Init netsnmp agent connection
*
* @param[in] h Clixon handle
* @param[in] logdst Log destination, see clixon_log.h
* @retval 0 OK
* @retval -1 Error
* @see snmp_terminate
*/
static int
@ -243,7 +253,7 @@ clixon_snmp_init_subagent(clicon_handle h,
int retval = -1;
char *sockpath = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (logdst == CLICON_LOG_SYSLOG)
snmp_enable_calllog();
else
@ -253,11 +263,11 @@ clixon_snmp_init_subagent(clicon_handle h,
/* don't load config and don't load/save persistent file */
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
/* don't load persistent file */
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD, 1);
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD, 1);
/* don't save persistent file */
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE, 1);
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE, 1);
if (clicon_debug_get())
if (clixon_debug_get())
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1);
if ((sockpath = clicon_option_str(h, "CLICON_SNMP_AGENT_SOCK")) == NULL){
@ -277,7 +287,6 @@ clixon_snmp_init_subagent(clicon_handle h,
clicon_err(OE_DAEMON, 0, "Connection to SNMP agent failed");
goto done;
}
if (set_signal(SIGTERM, clixon_snmp_sig_term, NULL) < 0){
clicon_err(OE_DAEMON, errno, "Setting signal");
goto done;
@ -299,6 +308,7 @@ clixon_snmp_init_subagent(clicon_handle h,
}
/*! Usage help routine
*
* @param[in] h Clixon handle
* @param[in] argv0 command line
*/
@ -344,12 +354,12 @@ main(int argc,
int zap = 0;
int config_dump = 0;
enum format_enum config_dump_format = FORMAT_XML;
/* Create handle */
if ((h = clicon_handle_init()) == NULL)
return -1;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Set username to clixon handle. Use in all communication to backend */
if ((pw = getpwuid(getuid())) == NULL){
@ -382,11 +392,11 @@ main(int argc,
break;
}
/*
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(dbg, NULL);
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
clixon_debug_init(dbg, NULL);
/* This is netsnmplib debugging which is quite extensive + only if compiled w debug */
if (dbg > 1)
snmp_set_do_debugging(1);
@ -398,13 +408,10 @@ main(int argc,
clixon_snmp_err_cb /* log fn */
) < 0)
goto done;
yang_init(h);
/* Find, read and parse configfile */
if (clicon_options_main(h) < 0)
goto done;
/* Now rest of options */
optind = 1;
opterr = 0;
@ -455,18 +462,18 @@ main(int argc,
if (pid && pidfile_zapold(pid) < 0)
return -1;
if (lstat(pidfile, &st) == 0)
unlink(pidfile);
unlink(pidfile);
snmp_terminate(h);
exit(0); /* OK */
}
else if (pid){
clicon_err(OE_DAEMON, 0, "Clixon_snmp daemon already running with pid %d\n(Try killing it with %s -z)",
clicon_err(OE_DAEMON, 0, "Clixon_snmp daemon already running with pid %d\n(Try killing it with %s -z)",
pid, argv0);
return -1; /* goto done deletes pidfile */
}
/* Here there is either no old process or we have killed it,.. */
if (lstat(pidfile, &st) == 0)
unlink(pidfile);
unlink(pidfile);
/* Init cligen buffers */
cligen_buflen = clicon_option_int(h, "CLICON_CLI_BUF_START");
@ -488,7 +495,7 @@ main(int argc,
/* Create top-level yang spec and store as option */
if ((yspec = yspec_new()) == NULL)
goto done;
clicon_dbspec_yang_set(h, yspec);
clicon_dbspec_yang_set(h, yspec);
/* Load Yang modules
* 1. Load a yang module as a specific absolute filename */
@ -530,7 +537,7 @@ main(int argc,
goto ok;
}
clicon_option_dump(h, 1);
/* Send hello request to backend to get session-id back
* This is done once at the beginning of the session and then this is
* used by the client, even though new TCP sessions are created for
@ -540,7 +547,6 @@ main(int argc,
if (clicon_hello_req(h, "cl:snmp", NULL, &id) < 0)
goto done;
clicon_session_id_set(h, id);
/* Init snmp as subagent */
if (clixon_snmp_init_subagent(h, logdst) < 0)
goto done;

View file

@ -80,6 +80,7 @@
#include "snmp_handler.h"
/*! Parse smiv2 extensions for YANG leaf
*
* Typical leaf:
* smiv2:oid "1.3.6.1.4.1.8072.2.1.1";
* smiv2:max-access "read-write";
@ -143,7 +144,7 @@ mibyang_leaf_register(clicon_handle h,
if (yang_extension_value_opt(ys, "smiv2:defval", NULL, &default_str) < 0)
goto done;
name = yang_argument_get(ys);
/* Stateless function, just returns ptr */
/* Stateless function, just returns ptr */
if ((handler = netsnmp_create_handler(name, clixon_snmp_scalar_handler)) == NULL){
clicon_err(OE_XML, errno, "netsnmp_create_handler");
goto done;
@ -167,7 +168,7 @@ mibyang_leaf_register(clicon_handle h,
clicon_err(OE_UNIX, errno, "cvec_dup");
goto done;
}
/* Stateless function, just returns ptr */
/* Stateless function, just returns ptr */
if ((nhreg = netsnmp_handler_registration_create(name, handler,
oid1, oid1len,
modes)) == NULL){
@ -180,7 +181,7 @@ mibyang_leaf_register(clicon_handle h,
handler->data_clone = snmp_handle_clone;
handler->data_free = snmp_handle_free;
/*
/*
* XXX: nhreg->agent_data
*/
if ((ret = netsnmp_register_instance(nhreg)) != SNMPERR_SUCCESS){
@ -189,7 +190,7 @@ mibyang_leaf_register(clicon_handle h,
goto done;
}
oid_cbuf(cboid, oid1, oid1len);
clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, cbuf_get(cboid));
clixon_debug(CLIXON_DBG_DEFAULT, "%s register: %s %s", __FUNCTION__, name, cbuf_get(cboid));
ok:
retval = 0;
done:
@ -236,7 +237,7 @@ mibyang_table_register(clicon_handle h,
int asn1type;
yang_stmt *ys;
char *name;
if ((ys = yang_parent_get(ylist)) == NULL ||
yang_keyword_get(ys) != Y_CONTAINER){
clicon_err(OE_YANG, EINVAL, "ylist parent is not list");
@ -247,7 +248,7 @@ mibyang_table_register(clicon_handle h,
* the original and ifXTable for the augmented.
* But the name does not seem to have semantic significance, so I leave it as is.
*/
name = yang_argument_get(ys);
name = yang_argument_get(ys);
/* Userdata to pass around in netsmp callbacks
* XXX: not deallocated
*/
@ -278,7 +279,7 @@ mibyang_table_register(clicon_handle h,
handler->myvoid =(void*)sh;
handler->data_clone = snmp_handle_clone;
handler->data_free = snmp_handle_free;
/* See netsnmp_register_table_data_set */
if ((table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL){
clicon_err(OE_UNIX, errno, "SNMP_MALLOC_TYPEDEF");
@ -294,7 +295,7 @@ mibyang_table_register(clicon_handle h,
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if ((yleaf = yang_find(ylist, Y_LEAF, keyname)) == NULL){
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
yang_argument_get(ylist), keyname);
goto done;
}
@ -315,19 +316,18 @@ mibyang_table_register(clicon_handle h,
/* Count columns */
yleaf = NULL;
table_info->max_column = 0;
table_info->max_column = 0;
while ((yleaf = yn_each(ylist, yleaf)) != NULL) {
if ((yang_keyword_get(yleaf) != Y_LEAF) || (ret = yangext_is_oid_exist(yleaf)) != 1)
continue;
table_info->max_column++;
table_info->max_column++;
}
if ((ret = netsnmp_register_table(nhreg, table_info)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_register_table");
goto done;
}
sh->sh_table_info = table_info; /* Keep to free at exit */
clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, oidstr);
clixon_debug(CLIXON_DBG_DEFAULT, "%s register: %s %s", __FUNCTION__, name, oidstr);
ok:
retval = 0;
done:
@ -375,7 +375,7 @@ mibyang_list_register(clicon_handle h,
goto done;
if (ret == 0)
goto ok;
if (mibyang_table_register(h, ylist,
if (mibyang_table_register(h, ylist,
oid1, oid1len,
oid2, oid2len,
oidstr) < 0)
@ -446,6 +446,7 @@ mibyang_augment_register(clicon_handle h,
}
/*! Register table sub-oid:s of existing entries in clixon
*
* This assumes a table contains a set of keys and a list of leafs only
* The function makes a query to the datastore and registers all table entries that
* currently exists. This means it registers for a static table. If new rows or columns
@ -476,8 +477,8 @@ mibyang_table_poll(clicon_handle h,
int ret;
oid oidk[MAX_OID_LEN] = {0,};
size_t oidklen = MAX_OID_LEN;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((ys = yang_parent_get(ylist)) == NULL ||
yang_keyword_get(ys) != Y_CONTAINER){
clicon_err(OE_YANG, EINVAL, "ylist parent is not list");
@ -509,7 +510,7 @@ mibyang_table_poll(clicon_handle h,
while ((xcol = xml_child_each(xrow, xcol, CX_ELMNT)) != NULL) {
if ((y = xml_spec(xcol)) == NULL)
continue;
if (mibyang_leaf_register(h, y, cvk_val, oidk, oidklen) < 0)
if (mibyang_leaf_register(h, y, cvk_val, oidk, oidklen) < 0)
goto done;
}
}
@ -523,7 +524,7 @@ mibyang_table_poll(clicon_handle h,
if (xt)
xml_free(xt);
if (nsc)
xml_nsctx_free(nsc);
xml_nsctx_free(nsc);
return retval;
}
@ -557,8 +558,8 @@ mibyang_traverse(clicon_handle h,
yang_stmt *yp;
int ret;
static oid zero_oid = 0;
clicon_debug(1, "%s %s", __FUNCTION__, yang_argument_get(yn));
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, yang_argument_get(yn));
switch(yang_keyword_get(yn)){
case Y_AUGMENT:
if (mibyang_augment_register(h, yn) < 0)
@ -588,7 +589,7 @@ mibyang_traverse(clicon_handle h,
ys = NULL;
while ((ys = yn_each(yn, ys)) != NULL) {
/* augment special case of table */
if (!yang_schemanode(ys) && yang_keyword_get(ys) != Y_AUGMENT)
if (!yang_schemanode(ys) && yang_keyword_get(ys) != Y_AUGMENT)
continue;
if ((ret = mibyang_traverse(h, ys)) < 0)
goto done;
@ -601,7 +602,7 @@ mibyang_traverse(clicon_handle h,
retval = 0;
done:
return retval;
}
}
/*! Init mib-translated yangs and register callbacks by traversing the yang
*
@ -631,7 +632,7 @@ clixon_snmp_traverse_mibyangs(clicon_handle h)
continue;
if ((modname = xml_body(x)) == NULL)
continue;
clicon_debug(1, "%s %s: \"%s\"", __FUNCTION__, xml_name(x), modname);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s: \"%s\"", __FUNCTION__, xml_name(x), modname);
/* Note, here we assume the Yang is loaded by some other mechanism and
* error if it not found.
* Alternatively, that YANG could be loaded.

View file

@ -489,7 +489,7 @@ information on added, deleted and changed entries. You access this
information using access functions as defined in clixon_backend_transaction.h
## How do I check what has changed on commit?
You use XPATHs on the XML trees in the transaction commit callback.
You use XPaths on the XML trees in the transaction commit callback.
Suppose you want to print all added interfaces:
```
cxobj *target = transaction_target(td); # wanted XML tree
@ -500,7 +500,7 @@ Suppose you want to print all added interfaces:
You can look for added, deleted and changed entries in this way.
## How do I access the XML tree?
Using XPATH, find and iteration functions defined in the XML library. Example library functions:
Using XPath, find and iteration functions defined in the XML library. Example library functions:
```
xml_child_each(),
xml_find(),

View file

@ -67,7 +67,7 @@
#include <clixon/clixon.h>
/* These include signatures for plugin and transaction callbacks. */
#include <clixon/clixon_backend.h>
#include <clixon/clixon_backend.h>
/* Command line options to be passed to getopt(3) */
#define BACKEND_EXAMPLE_OPTS "a:m:M:nrsS:x:iuUtV:"
@ -123,7 +123,7 @@ static int _state = 0;
*/
static char *_state_file = NULL;
/*! XPath to register for pagination state XML from file,
/*! XPath to register for pagination state XML from file,
*
* if _state is true -- -sS <file> -x <xpath>
* Primarily for testing
@ -185,7 +185,7 @@ static int _validate_fail_toggle = 0; /* fail at validate and commit */
static int example_stream_timer_setup(clicon_handle h);
int
main_begin(clicon_handle h,
main_begin(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -196,7 +196,7 @@ main_begin(clicon_handle h,
/*! This is called on validate (and commit). Check validity of candidate
*/
int
main_validate(clicon_handle h,
main_validate(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -213,7 +213,7 @@ main_validate(clicon_handle h,
}
int
main_complete(clicon_handle h,
main_complete(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -224,7 +224,7 @@ main_complete(clicon_handle h,
/*! This is called on commit. Identify modifications and adjust machine state
*/
int
main_commit(clicon_handle h,
main_commit(clicon_handle h,
transaction_data td)
{
cxobj *target = transaction_target(td); /* wanted XML tree */
@ -251,7 +251,7 @@ main_commit(clicon_handle h,
/* Get all added i/fs */
if (xpath_vec_flag(target, nsc, "//interface", XML_FLAG_ADD, &vec, &len) < 0)
return -1;
if (clicon_debug_get())
if (clixon_debug_get())
for (i=0; i<len; i++) /* Loop over added i/fs */
xml_print(stdout, vec[i]); /* Print the added interface */
done:
@ -263,7 +263,7 @@ main_commit(clicon_handle h,
}
int
main_commit_done(clicon_handle h,
main_commit_done(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -272,7 +272,7 @@ main_commit_done(clicon_handle h,
}
int
main_revert(clicon_handle h,
main_revert(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -281,7 +281,7 @@ main_revert(clicon_handle h,
}
int
main_end(clicon_handle h,
main_end(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -290,7 +290,7 @@ main_end(clicon_handle h,
}
int
main_abort(clicon_handle h,
main_abort(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -301,7 +301,7 @@ main_abort(clicon_handle h,
/*! Routing example notification timer handler. Here is where the periodic action is
*/
static int
example_stream_timer(int fd,
example_stream_timer(int fd,
void *arg)
{
int retval = -1;
@ -337,8 +337,8 @@ example_stream_timer_setup(clicon_handle h)
* are returned, the <rpc-reply> contains a single <ok/> element defined
* in [RFC6241].
*/
static int
empty_rpc(clicon_handle h, /* Clicon handle */
static int
empty_rpc(clicon_handle h, /* Clixon handle */
cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* client_entry */
@ -352,8 +352,8 @@ empty_rpc(clicon_handle h, /* Clicon handle */
*
* The RPC returns the incoming parameters
*/
static int
example_rpc(clicon_handle h, /* Clicon handle */
static int
example_rpc(clicon_handle h, /* Clixon handle */
cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* client_entry */
@ -394,8 +394,8 @@ example_rpc(clicon_handle h, /* Clicon handle */
/*! This will be called as a hook right after the original system copy-config
*/
static int
example_copy_extra(clicon_handle h, /* Clicon handle */
static int
example_copy_extra(clicon_handle h, /* Clixon handle */
cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* client_entry */
@ -413,8 +413,8 @@ example_copy_extra(clicon_handle h, /* Clicon handle */
*
* @note callback is hardcoded C, while registration is controlled by -- -a option
*/
static int
example_action_reset(clicon_handle h, /* Clicon handle */
static int
example_action_reset(clicon_handle h, /* Clixon handle */
cxobj *xe, /* Request: <rpc><xn></rpc> */
cbuf *cbret, /* Reply eg <rpc-reply>... */
void *arg, /* client_entry */
@ -434,7 +434,7 @@ example_action_reset(clicon_handle h, /* Clicon handle */
/*! Called to get state data from plugin by programmatically adding state
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xstate XML tree, <config/> on entry.
@ -452,8 +452,8 @@ example_action_reset(clicon_handle h, /* Clicon handle */
* This yang snippet is present in clixon-example.yang for example.
* @see example_statefile where state is read from file and also pagination
*/
int
example_statedata(clicon_handle h,
int
example_statedata(clicon_handle h,
cvec *nsc,
char *xpath,
cxobj *xstate)
@ -539,7 +539,7 @@ example_statedata(clicon_handle h,
*
* The example shows how to read and parse a state XML file, (which is cached in the -i case).
* Return the requested xpath / pagination xstate by copying from the parsed state XML file
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xstate XML tree, <config/> on entry. Copy to this
@ -548,8 +548,8 @@ example_statedata(clicon_handle h,
* @see xmldb_get
* @see example_statefile where state is programmatically added
*/
int
example_statefile(clicon_handle h,
int
example_statefile(clicon_handle h,
cvec *nsc,
char *xpath,
cxobj *xstate)
@ -587,8 +587,8 @@ example_statefile(clicon_handle h,
if (_state_file_cached)
xt = _state_xml_cache;
#ifdef _STATEFILTER
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath) < 0)
goto done;
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath) < 0)
goto done;
/* Mark elements to copy:
* For every node found in x0, mark the tree as changed
*/
@ -601,7 +601,7 @@ example_statefile(clicon_handle h,
/* Copy the marked elements:
* note is yang-aware for copying of keys which means XML must be bound
*/
if (xml_copy_marked(xt, xstate) < 0)
if (xml_copy_marked(xt, xstate) < 0)
goto done;
/* Unmark original tree */
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)) < 0)
@ -610,7 +610,7 @@ example_statefile(clicon_handle h,
if (xml_apply(xstate, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)) < 0)
goto done;
#else
if (xml_copy(xt, xstate) < 0)
if (xml_copy(xt, xstate) < 0)
goto done;
#endif
if (_state_file_cached)
@ -634,7 +634,7 @@ example_statefile(clicon_handle h,
* @param[in] userargs Per-call user arguments
* @param[in] arg Per-path user argument (at register time)
*/
int
int
example_pagination(void *h0,
char *xpath,
pagination_data pd,
@ -657,16 +657,16 @@ example_pagination(void *h0,
uint32_t upper;
int ret;
cvec *nsc = NULL;
/* If -S is set, then read state data from file */
if (!_state || !_state_file)
goto ok;
locked = pagination_locked(pd);
offset = pagination_offset(pd);
limit = pagination_limit(pd);
xstate = pagination_xstate(pd);
locked = pagination_locked(pd);
offset = pagination_offset(pd);
limit = pagination_limit(pd);
xstate = pagination_xstate(pd);
/* Get canonical namespace context */
if (xml_nsctx_yangspec(yspec, &nsc) < 0)
goto done;
@ -687,8 +687,8 @@ example_pagination(void *h0,
}
if (_state_file_cached)
xt = _state_xml_cache;
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath) < 0)
goto done;
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath) < 0)
goto done;
lower = offset;
if (limit == 0)
upper = xlen;
@ -732,7 +732,7 @@ example_pagination(void *h0,
free(xvec);
if (nsc)
cvec_free(nsc);
return retval;
return retval;
}
/*! Lock databse status has changed status
@ -752,7 +752,7 @@ example_lockdb(clicon_handle h,
{
int retval = -1;
clicon_debug(1, "%s Lock callback: db%s: locked:%d", __FUNCTION__, db, lock);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Lock callback: db%s: locked:%d", __FUNCTION__, db, lock);
/* Part of cached pagination example
*/
if (strcmp(db, "running") == 0 && lock == 0 &&
@ -769,15 +769,15 @@ example_lockdb(clicon_handle h,
}
/*! Callback for yang extensions example:e4
*
*
* @param[in] h Clixon handle
* @param[in] yext Yang node of extension
* @param[in] ys Yang node of (unknown) statement belonging to extension
* @retval 0 OK, all callbacks executed OK
* @retval -1 Error in one callback
* @retval 0 OK, all callbacks executed OK
* @retval -1 Error in one callback
*/
int
example_extension(clicon_handle h,
example_extension(clicon_handle h,
yang_stmt *yext,
yang_stmt *ys)
{
@ -787,13 +787,13 @@ example_extension(clicon_handle h,
yang_stmt *ymod;
yang_stmt *yc;
yang_stmt *yn = NULL;
ymod = ys_module(yext);
modname = yang_argument_get(ymod);
extname = yang_argument_get(yext);
if (strcmp(modname, "example") != 0 || strcmp(extname, "e4") != 0)
goto ok;
clicon_debug(1, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
if ((yc = yang_find(ys, 0, NULL)) == NULL)
goto ok;
if ((yn = ys_dup(yc)) == NULL)
@ -833,7 +833,7 @@ static const map_str2str namespace_map[] = {
*
* Gets called on startup after initial XML parsing, but before module-specific upgrades
* and before validation.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
* @param[in] xt XML tree. Upgrade this "in place"
* @param[in] msd Info on datastore module-state, if any
@ -848,10 +848,10 @@ example_upgrade(clicon_handle h,
{
int retval = -1;
cvec *nsc = NULL; /* Canonical namespace */
yang_stmt *yspec;
yang_stmt *yspec;
const struct map_str2str *ms; /* map iterator */
cxobj **xvec = NULL; /* vector of result nodes */
size_t xlen;
size_t xlen;
int i;
const char **pp;
@ -868,7 +868,7 @@ example_upgrade(clicon_handle h,
/* 1. Remove paths */
for (pp = remove_map; *pp; ++pp){
/* Find all nodes matching n */
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, *pp) < 0)
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, *pp) < 0)
goto done;
/* Remove them */
/* Loop through all nodes matching mypath and change theoir namespace */
@ -896,11 +896,11 @@ example_upgrade(clicon_handle h,
goto done;
}
/* Find all nodes matching mypath */
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, mypath) < 0)
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, mypath) < 0)
goto done;
/* Loop through all nodes matching mypath and change theoir namespace */
for (i=0; i<xlen; i++){
/* Change namespace of this node (using myprefix) */
/* Change namespace of this node (using myprefix) */
if (xml_namespace_change(xvec[i], mynamespace, myprefix) < 0)
goto done;
}
@ -977,7 +977,7 @@ main_yang_mount(clicon_handle h,
/*! Testcase module-specific upgrade function moving interfaces-state to interfaces
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xn XML tree to be updated
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
@ -999,13 +999,13 @@ main_yang_mount(clicon_handle h,
* - Rename /interfaces/interface/description to descr
*/
static int
upgrade_2014_to_2016(clicon_handle h,
cxobj *xt,
upgrade_2014_to_2016(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
void *arg,
cbuf *cbret)
{
int retval = -1;
@ -1020,11 +1020,11 @@ upgrade_2014_to_2016(clicon_handle h,
int i;
char *name;
clicon_debug(1, "%s from:%d to:%d", __FUNCTION__, from, to);
clixon_debug(CLIXON_DBG_DEFAULT, "%s from:%d to:%d", __FUNCTION__, from, to);
if (op != XML_FLAG_CHANGE) /* Only treat fully present modules */
goto ok;
/* Get Yang module for this namespace. Note it may not exist (if obsolete) */
yspec = clicon_dbspec_yang(h);
yspec = clicon_dbspec_yang(h);
if ((ym = yang_find_module_by_namespace(yspec, ns)) == NULL)
goto ok; /* shouldnt happen */
/* Get all XML nodes with that namespace */
@ -1045,7 +1045,7 @@ upgrade_2014_to_2016(clicon_handle h,
continue; /* shouldnt happen */
/* Get corresponding /interfaces/interface entry */
xif = xpath_first(xt, NULL, "/interfaces/interface[name=\"%s\"]", name);
/* - Move /if:interfaces-state/if:interface/if:admin-status to
/* - Move /if:interfaces-state/if:interface/if:admin-status to
* /if:interfaces/if:interface/ */
if ((x = xml_find(xi, "admin-status")) != NULL && xif){
if (xml_addsub(xif, x) < 0)
@ -1082,7 +1082,7 @@ upgrade_2014_to_2016(clicon_handle h,
/*! Testcase upgrade function removing interfaces-state
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xn XML tree to be updated
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
@ -1103,13 +1103,13 @@ upgrade_2014_to_2016(clicon_handle h,
* fraction-digits 3 and divide all values with 1000
*/
static int
upgrade_2016_to_2018(clicon_handle h,
cxobj *xt,
upgrade_2016_to_2018(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
void *arg,
cbuf *cbret)
{
int retval = -1;
@ -1123,14 +1123,14 @@ upgrade_2016_to_2018(clicon_handle h,
size_t vlen;
int i;
clicon_debug(1, "%s from:%d to:%d", __FUNCTION__, from, to);
clixon_debug(CLIXON_DBG_DEFAULT, "%s from:%d to:%d", __FUNCTION__, from, to);
if (op != XML_FLAG_CHANGE) /* Only treat fully present modules */
goto ok;
/* Get Yang module for this namespace. Note it may not exist (if obsolete) */
yspec = clicon_dbspec_yang(h);
yspec = clicon_dbspec_yang(h);
if ((ym = yang_find_module_by_namespace(yspec, ns)) == NULL)
goto ok; /* shouldnt happen */
clicon_debug(1, "%s module %s", __FUNCTION__, ym?yang_argument_get(ym):"none");
clixon_debug(CLIXON_DBG_DEFAULT, "%s module %s", __FUNCTION__, ym?yang_argument_get(ym):"none");
/* Get all XML nodes with that namespace */
if (xml_namespace_vec(h, xt, ns, &vec, &vlen) < 0)
goto done;
@ -1182,7 +1182,7 @@ upgrade_2016_to_2018(clicon_handle h,
/*! Testcase module-specific upgrade function moving interfaces-state to interfaces
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xn XML tree to be updated
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
@ -1204,13 +1204,13 @@ upgrade_2016_to_2018(clicon_handle h,
* - Rename /interfaces/interface/description to descr
*/
static int
upgrade_interfaces(clicon_handle h,
cxobj *xt,
upgrade_interfaces(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
void *arg,
cbuf *cbret)
{
int retval = -1;
@ -1247,8 +1247,10 @@ upgrade_interfaces(clicon_handle h,
* is well defined.
* This involves creating default configuration files for various daemons, set interface
* flags etc.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of database. Not3 may be other than "running"
* @retval 0 OK
* @retval -1 Error
* In this example, a loopback parameter is added
*/
int
@ -1264,15 +1266,14 @@ example_reset(clicon_handle h,
if (!_reset)
goto ok; /* Note not enabled by default */
yspec = clicon_dbspec_yang(h);
yspec = clicon_dbspec_yang(h);
/* Parse extra XML */
if ((ret = clixon_xml_parse_string("<table xmlns=\"urn:example:clixon\">"
"<parameter><name>loopback</name><value>99</value></parameter>"
"</table>", YB_MODULE, yspec, &xt, &xerr)) < 0)
goto done;
if (ret == 0){
clicon_debug_xml(1, xerr, "Error when parsing XML");
clixon_debug_xml(CLIXON_DBG_DEFAULT, xerr, "Error when parsing XML");
goto ok;
}
/* xmldb_put requires modification tree to be: <config>... */
@ -1306,7 +1307,9 @@ example_reset(clicon_handle h,
* Called when application is "started", (almost) all initialization is complete
* Backend: daemon is in the background. If daemon privileges are dropped
* this callback is called *before* privileges are dropped.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
int
example_start(clicon_handle h)
@ -1338,7 +1341,9 @@ example_start(clicon_handle h)
/*! Plugin daemon.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* plugin_daemon is called once after daemonization has been made but before lowering of privileges
* the main event loop is entered.
*/
@ -1376,7 +1381,7 @@ example_daemon(clicon_handle h)
return retval;
}
int
int
example_exit(clicon_handle h)
{
if (_state_xml_cache){
@ -1390,7 +1395,7 @@ example_exit(clicon_handle h)
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
static clixon_plugin_api api = {
"example", /* name */
"example", /* name */
clixon_plugin_init, /* init - must be called clixon_plugin_init */
example_start, /* start */
example_exit, /* exit */
@ -1427,7 +1432,7 @@ clixon_plugin_init(clicon_handle h)
char **argv;
int c;
clicon_debug(1, "%s backend", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s backend", __FUNCTION__);
/* Get user command-line options (after --) */
if (clicon_argv_get(h, &argc, &argv) < 0)
@ -1491,7 +1496,7 @@ clixon_plugin_init(clicon_handle h)
goto done;
}
}
if (_notification_stream){
/* Example stream initialization:
* 1) Register EXAMPLE stream
@ -1514,22 +1519,22 @@ clixon_plugin_init(clicon_handle h)
/* Register callback for routing rpc calls
*/
/* From example.yang (clicon) */
if (rpc_callback_register(h, empty_rpc,
NULL,
if (rpc_callback_register(h, empty_rpc,
NULL,
"urn:example:clixon",
"empty"/* Xml tag when callback is made */
) < 0)
goto done;
/* Same as example but with optional input/output */
if (rpc_callback_register(h, example_rpc,
NULL,
if (rpc_callback_register(h, example_rpc,
NULL,
"urn:example:clixon",
"optional"/* Xml tag when callback is made */
) < 0)
goto done;
/* Same as example but with optional input/output */
if (rpc_callback_register(h, example_rpc,
NULL,
if (rpc_callback_register(h, example_rpc,
NULL,
"urn:example:clixon",
"example"/* Xml tag when callback is made */
) < 0)
@ -1538,8 +1543,8 @@ clixon_plugin_init(clicon_handle h)
* If you want to have it called _after_ the system callback, place this call in
* the _start function.
*/
if (rpc_callback_register(h, example_copy_extra,
NULL,
if (rpc_callback_register(h, example_copy_extra,
NULL,
NETCONF_BASE_NAMESPACE,
"copy-config"
) < 0)

View file

@ -56,18 +56,20 @@
#include <clixon/clixon.h>
/* These include signatures for plugin and transaction callbacks. */
#include <clixon/clixon_backend.h>
#include <clixon/clixon_backend.h>
/* Command line options to be passed to getopt(3) */
#define BACKEND_NACM_OPTS "tv:"
/*! Variable to control transaction logging (for debug)
*
* If set, call syslog for every transaction callback
* Start backend with -- -t
*/
static int _transaction_log = 0;
/*! Variable to trigger validation/commit errors (synthetic errors) for tests
*
* XPath to trigger validation error, ie if the XPath matches, then validate fails
* This is to make tests where a transaction fails midway and aborts/reverts the transaction.
* Start backend with -- -v <xpath>
@ -76,12 +78,13 @@ static int _transaction_log = 0;
static char *_validate_fail_xpath = NULL;
/*! Sub state variable to fail on validate/commit (not configured)
*
* Obscure, but a way to first trigger a validation error, next time to trigger a commit error
*/
static int _validate_fail_toggle = 0; /* fail at validate and commit */
int
nacm_begin(clicon_handle h,
nacm_begin(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -91,7 +94,7 @@ nacm_begin(clicon_handle h,
/*! This is called on validate (and commit). Check validity of candidate
*/
int
nacm_validate(clicon_handle h,
nacm_validate(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -108,7 +111,7 @@ nacm_validate(clicon_handle h,
}
int
nacm_complete(clicon_handle h,
nacm_complete(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -119,7 +122,7 @@ nacm_complete(clicon_handle h,
/*! This is called on commit. Identify modifications and adjust machine state
*/
int
nacm_commit(clicon_handle h,
nacm_commit(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -136,7 +139,7 @@ nacm_commit(clicon_handle h,
}
int
nacm_commit_done(clicon_handle h,
nacm_commit_done(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -145,7 +148,7 @@ nacm_commit_done(clicon_handle h,
}
int
nacm_revert(clicon_handle h,
nacm_revert(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -154,7 +157,7 @@ nacm_revert(clicon_handle h,
}
int
nacm_end(clicon_handle h,
nacm_end(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -163,7 +166,7 @@ nacm_end(clicon_handle h,
}
int
nacm_abort(clicon_handle h,
nacm_abort(clicon_handle h,
transaction_data td)
{
if (_transaction_log)
@ -172,9 +175,10 @@ nacm_abort(clicon_handle h,
}
/*! Called to get NACM state data
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] xpath String with XPath syntax. or NULL for all
* @param[in] xtop XML tree, <config/> on entry.
* @retval 0 OK
* @retval -1 Error
@ -182,8 +186,8 @@ nacm_abort(clicon_handle h,
* @note this example code returns a static statedata used in testing.
* Real code would poll state
*/
int
nacm_statedata(clicon_handle h,
int
nacm_statedata(clicon_handle h,
cvec *nsc,
char *xpath,
cxobj *xstate)
@ -224,6 +228,7 @@ static clixon_plugin_api api = {
};
/*! Backend plugin initialization
*
* @param[in] h Clixon handle
* @retval NULL Error with clicon_err set
* @retval api Pointer to API struct
@ -235,8 +240,8 @@ clixon_plugin_init(clicon_handle h)
int argc; /* command-line options (after --) */
char **argv;
int c;
clicon_debug(1, "%s backend nacm", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s backend nacm", __FUNCTION__);
/* Get user command-line options (after --) */
if (clicon_argv_get(h, &argc, &argv) < 0)
goto done;
@ -256,7 +261,7 @@ clixon_plugin_init(clicon_handle h)
if (nacm_mode==NULL || strcmp(nacm_mode, "disabled") == 0){
clicon_log(LOG_DEBUG, "%s CLICON_NACM_MODE not enabled: example nacm module disabled", __FUNCTION__);
/* Skip nacm module if not enabled _unless_ we use transaction tests */
if (_transaction_log == 0)
if (_transaction_log == 0)
return NULL;
}
/* Return plugin API */

View file

@ -64,7 +64,8 @@
static char *_mount_yang = NULL;
static char *_mount_namespace = NULL;
/*! Example cli function */
/*! Example cli function
*/
int
mycallback(clicon_handle h, cvec *cvv, cvec *argv)
{
@ -80,10 +81,10 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
if ((nsc = xml_nsctx_init(NULL, "urn:example:clixon")) == NULL)
goto done;
/* Show eth0 interfaces config using XPATH */
/* Show eth0 interfaces config using XPath */
if (clicon_rpc_get_config(h, NULL, "running",
"/interfaces/interface[name='eth0']",
nsc, NULL,
nsc, NULL,
&xret) < 0)
goto done;
if (clixon_xml2file(stdout, xret, 0, 1, NULL, cligen_output, 0, 1) < 0)
@ -97,10 +98,11 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
return retval;
}
/*! Example "downcall", ie initiate an RPC to the backend */
/*! Example "downcall", ie initiate an RPC to the backend
*/
int
example_client_rpc(clicon_handle h,
cvec *cvv,
example_client_rpc(clicon_handle h,
cvec *cvv,
cvec *argv)
{
int retval = -1;
@ -148,7 +150,11 @@ example_client_rpc(clicon_handle h,
}
/*! Translate function from an original value to a new.
*
* In this case, assume string and increment characters, eg HAL->IBM
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
int
cli_incstr(cligen_handle h,
@ -156,8 +162,8 @@ cli_incstr(cligen_handle h,
{
char *str;
int i;
/* Filter out other than strings
/* Filter out other than strings
* this is specific to this example, one can do translation */
if (cv == NULL || cv_type_get(cv) != CGV_STRING)
return 0;
@ -239,6 +245,7 @@ static clixon_plugin_api api = {
};
/*! CLI plugin initialization
*
* @param[in] h Clixon handle
* @retval NULL Error with clicon_err set
* @retval api Pointer to API struct

View file

@ -49,8 +49,10 @@
#include <clixon/clixon_netconf.h>
/*! Plugin start
*
* Called once everything has been initialized, right before
* the main event loop is entered.
* @param[in] h Clixon handle
*/
int
plugin_start(clicon_handle h)
@ -67,9 +69,9 @@ plugin_exit(clicon_handle h)
/*! Local example netconf rpc callback
*/
int
netconf_client_rpc(clicon_handle h,
cxobj *xe,
cbuf *cbret,
netconf_client_rpc(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
@ -111,6 +113,7 @@ static struct clixon_plugin_api api = {
};
/*! Netconf plugin initialization
*
* @param[in] h Clixon handle
* @retval NULL Error with clicon_err set
* @retval api Pointer to API struct
@ -118,7 +121,7 @@ static struct clixon_plugin_api api = {
clixon_plugin_api *
clixon_plugin_init(clicon_handle h)
{
clicon_debug(1, "%s restconf", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s restconf", __FUNCTION__);
/* Register local netconf rpc client (note not backend rpc client) */
if (rpc_callback_register(h, netconf_client_rpc, NULL,
"urn:example:clixon", "client-rpc") < 0)

View file

@ -64,8 +64,8 @@ static const char Pad64 = '=';
@note what is copyright of this?
*/
int
b64_decode(const char *src,
char *target,
b64_decode(const char *src,
char *target,
size_t targsize)
{
int tarindex, state, ch;
@ -185,14 +185,15 @@ b64_decode(const char *src,
}
/*! HTTP basic authentication example (note hardwired)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] req Per-message request www handle to use with restconf_api.h
* @param[out] authp NULL: Credentials failed, no user set (401 returned).
* String: Credentials OK, the associated user, must be mallloc:ed
* Parameter signtificant only if retval is 1/OK
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see authp parameter for result.
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval -1 Fatal error
* @note authp should be malloced
* @note: Three hardwired users: andy, wilma, guest w password "bar".
*/
@ -211,14 +212,14 @@ example_basic_auth(clicon_handle h,
size_t authlen;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (authp == NULL){
clicon_err(OE_PLUGIN, EINVAL, "Authp output parameter is NULL");
goto done;
}
}
/* At this point in the code we must use HTTP basic authentication */
if ((auth = restconf_param_get(h, "HTTP_AUTHORIZATION")) == NULL)
goto fail;
goto fail;
if (strlen(auth) < strlen("Basic "))
goto fail;
if (strncmp("Basic ", auth, strlen("Basic ")))
@ -237,7 +238,7 @@ example_basic_auth(clicon_handle h,
goto fail;
*passwd = '\0';
passwd++;
clicon_debug(1, "%s http user:%s passwd:%s", __FUNCTION__, user, passwd);
clixon_debug(CLIXON_DBG_DEFAULT, "%s http user:%s passwd:%s", __FUNCTION__, user, passwd);
/* Here get auth sub-tree where all the users are */
if ((cb = cbuf_new()) == NULL)
goto done;
@ -252,7 +253,7 @@ example_basic_auth(clicon_handle h,
user=NULL; /* to avoid free below */
retval = 1;
done: /* error */
clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, authp?"":*authp);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d authp:%s", __FUNCTION__, retval, authp?"":*authp);
if (user)
free(user);
if (cb)
@ -267,15 +268,16 @@ example_basic_auth(clicon_handle h,
}
/*! Authentication callback
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] req Per-message request www handle to use with restconf_api.h
* @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @param[out] authp NULL: Credentials failed, no user set (401 returned).
* String: Credentials OK, the associated user, must be mallloc:ed
* Parameter signtificant only if retval is 1/OK
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see authp parameter for result.
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval -1 Fatal error
* @note authp should be malloced
*/
int
@ -285,8 +287,8 @@ example_restconf_credentials(clicon_handle h,
char **authp)
{
int retval = -1;
clicon_debug(1, "%s auth:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
clixon_debug(CLIXON_DBG_DEFAULT, "%s auth:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
switch (auth_type){
case CLIXON_AUTH_NONE: /* FEATURE clixon-restconf:allow-auth-none must be enabled */
retval = 0;
@ -300,16 +302,16 @@ example_restconf_credentials(clicon_handle h,
break;
}
done:
clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp);
return retval;
}
/*! Local example restconf rpc callback
*/
int
restconf_client_rpc(clicon_handle h,
cxobj *xe,
cbuf *cbret,
restconf_client_rpc(clicon_handle h,
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
{
@ -344,7 +346,7 @@ restconf_client_rpc(clicon_handle h,
int
example_restconf_start(clicon_handle h)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
return 0;
}
@ -359,6 +361,7 @@ static clixon_plugin_api api = {
};
/*! Restconf plugin initialization
*
* @param[in] h Clixon handle
* @retval NULL Error with clicon_err set
* @retval api Pointer to API struct
@ -370,8 +373,8 @@ clixon_plugin_init(clicon_handle h)
int argc; /* command-line options (after --) */
char **argv = NULL;
int c;
clicon_debug(1, "%s restconf", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s restconf", __FUNCTION__);
/* Get user command-line options (after --) */
if (clicon_argv_get(h, &argc, &argv) < 0)
return NULL;

View file

@ -39,7 +39,7 @@
or apps
*/
#ifndef HAVE_STRNDUP
#ifndef HAVE_STRNDUP
#define strndup(s, n) clicon_strndup(s, n)
#endif
@ -48,6 +48,7 @@
#undef RPC_USERNAME_ASSERT
/*! Tag for wrong handling of identityref prefixes (XML encoding)
*
* See https://github.com/clicon/clixon/issues/90
* Instead of using generic xmlns prefix bindings, the module's own prefix
* is used.
@ -60,7 +61,8 @@
*/
#undef IDENTITYREF_KLUDGE
/*! Optimize special list key searches in XPATH finds
/*! Optimize special list key searches in XPath finds
*
* Identify xpaths that search for exactly a list key, eg: "y[k='3']" and then call
* binary search. This only works if "y" has proper yang binding and is sorted by system
* Dont optimize on "hierarchical" lists such as: a/y[k='3'], where a is another list.
@ -68,6 +70,7 @@
#define XPATH_LIST_OPTIMIZE
/*! Add explicit search indexes, so that binary search can be made for non-key list indexes
*
* This also applies if there are multiple keys and you want to search on only the second for
* example.
* There may be some cases where the index vector is not updated, need to verify before
@ -76,6 +79,7 @@
#define XML_EXPLICIT_INDEX
/*! Let state data be ordered-by system
*
* RFC 7950 is cryptic about this
* It says in 7.7.7:
* This statement (red:The "ordered-by" Statement) is ignored if the list represents
@ -87,6 +91,7 @@
#define STATE_ORDERED_BY_SYSTEM
/*! Top-symbol in clixon datastores
*
* This is traditionally same as NETCONF_INPUT_CONFIG ("config") but can be different
* If you change this, you need to change test shell variable in lib.sh: DATASTORE_TOP
* Consider making this an option (but this has bootstrap problems) or configure option
@ -94,12 +99,14 @@
#define DATASTORE_TOP_SYMBOL "config"
/*! If set make an internal redirect if URI path indetifies a directory
*
* For example, path is /local, and redirect is 'index.html, the request
* will be redirected to /local/index.html
*/
#define HTTP_DATA_INTERNAL_REDIRECT "index.html"
/*! Set a temporary parent for use in special case "when" xpath calls
*
* Problem is when changing an existing (candidate) in-memory datastore that yang "when" conditionals
* should be changed in clixon_datastore_write.c:text_modify().
* Problem is that the tree is in an intermediate state so that a when condition may not see the
@ -115,16 +122,19 @@
#define XML_PARENT_CANDIDATE
/*! Enable "remaining" attribute (sub-feature of list pagination)
*
* As defined in draft-wwlh-netconf-list-pagination-00 using Yang metadata value [RFC7952]
*/
#undef LIST_PAGINATION_REMAINING
/*! Use Ancestor config cache
*
* The cache uses two yang stmt flag bits. One to say it is active, the second its value
*/
#define USE_CONFIG_FLAG_CACHE
/*! If backend is restarted, cli and netconf client will retry (once) and reconnect
*
* Note, if client has locked or had edits in progress, these will be lost
* A warning will be printed
* If not set, client will exit
@ -132,12 +142,14 @@
#define PROTO_RESTART_RECONNECT
/*! Disable top-level prefix for text syntax printing and parsing introduced in 5.8
*
* Note this is for showing/saving/printing, it is NOT for parsing/loading.
* This means that text output can not be parsed and loaded.
*/
#undef TEXT_SYNTAX_NOPREFIX
/*! Reply with HTTP error when HTTP request on HTTPS socket
*
* If not set, just close socket and return with TCP reset.
* If set: Incoming request on an SSL socket is known to be non-TLS.
* Problematic part is it is not known it is proper non-TLS HTTP, for that it
@ -153,6 +165,7 @@
#define HTTP_ON_HTTPS_REPLY
/*! Indentation number of spaces for XML, JSON and TEXT pretty-printed output.
*
* Consider moving to configure.ac(compile-time) or to clixon-config.yang(run-time)
*/
#define PRETTYPRINT_INDENT 3

View file

@ -50,17 +50,17 @@ typedef enum {
* see https://clixon-docs.readthedocs.io/en/latest/netconf.html#ipc
* Must be local on device
*/
CLIXON_CLIENT_IPC,
CLIXON_CLIENT_IPC,
/* Regular NETCONF via local netconf binary
* Fork clixon_netconf locally which in turn communicates with backend
* Must be local on device
*/
CLIXON_CLIENT_NETCONF,
CLIXON_CLIENT_NETCONF,
/* Regular NETCONF using ssh sub-system via local SSH (openssh) client binary
* Fork ssh locally which in turn communicates remotely to device
* Must have openssh installed locally and device must have ssh sub-subsystem
*/
CLIXON_CLIENT_SSH
CLIXON_CLIENT_SSH
} clixon_client_type;
/*
@ -70,7 +70,7 @@ typedef enum {
#ifdef __cplusplus
extern "C" {
#endif
clixon_handle clixon_client_init(const char *config_file);
int clixon_client_terminate(clixon_handle h);
int clixon_client_lock(int sock, const char *descr, const int lock, const char *db);
@ -83,7 +83,7 @@ int clixon_client_get_uint8(clixon_client_handle ch, uint8_t *rval, const char
int clixon_client_get_uint16(clixon_client_handle ch, uint16_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);
/* Access functions */
int clixon_client_socket_get(clixon_client_handle ch);

View file

@ -125,19 +125,19 @@ int clicon_socket_set(clicon_handle h, int s);
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);
int clicon_modst_cache_set(clicon_handle h, int brief, cxobj *xms);
/*! Set and get yang/xml module revision changelog */
/* Set and get yang/xml module revision changelog */
cxobj *clicon_xml_changelog_get(clicon_handle h);
int clicon_xml_changelog_set(clicon_handle h, cxobj *xchlog);
/*! Set and get user command-line options (after --) */
/* Set and get user command-line options (after --) */
int clicon_argv_get(clicon_handle h, int *argc, char ***argv);
int clicon_argv_set(clicon_handle h, char *argv0, int argc, char **argv);
/*! Set and get (client/backend) session id */
/* Set and get (client/backend) session id */
int clicon_session_id_set(clicon_handle h, uint32_t id);
int clicon_session_id_get(clicon_handle h, uint32_t *id);
int clicon_session_id_del(clicon_handle h);

View file

@ -52,7 +52,7 @@ int xmldb_disconnect(clicon_handle h);
int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop);
int xmldb_get0(clicon_handle h, const char *db, yang_bind yb,
cvec *nsc, const char *xpath, int copy, withdefaults_type wdef,
cxobj **xtop, modstate_diff_t *msd, cxobj **xerr);
cxobj **xtop, modstate_diff_t *msd, cxobj **xerr);
int xmldb_get0_clear(clicon_handle h, cxobj *x);
int xmldb_get0_free(clicon_handle h, cxobj **xp);
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */

View file

@ -38,6 +38,7 @@
#define _CLIXON_DISPATCH_DISPATCHER_H
/*! Prototype for a function to handle a path
*
* minimally needs the path it's working on, but probably
* we want to hand down cached data somehow
* @param[in] h Generic handler

View file

@ -45,7 +45,7 @@
/*
* Constants
*/
*/
#define ERR_STRLEN 256
/* Special error number for clicon_suberrno
@ -57,9 +57,9 @@
* Types
* Add error category here,
* @see EV variable in clixon_err.c but must also add an entry there
*/
*/
enum clicon_err{
/* 0 means error not set) */
/* 0 means error not set) */
OE_DB = 1, /* database registries */
OE_DAEMON, /* daemons: pidfiles, etc */
OE_EVENTS, /* events, filedescriptors, timeouts */
@ -79,11 +79,12 @@ enum clicon_err{
OE_UNDEF,
/*-- From here error extensions using clixon_err_cat_reg, XXX register dynamically? --*/
OE_SSL, /* Openssl errors, see eg ssl_get_error and clixon_openssl_log_cb */
OE_SNMP , /* Netsnmp error */
OE_SNMP , /* Netsnmp error */
OE_NGHTTP2, /* nghttp2 errors, see HAVE_LIBNGHTTP2 */
};
/* Clixon error category log callback
/*! Clixon error category log callback
*
* @param[in] handle Application-specific handle
* @param[in] suberr Application-specific handle
* @param[out] cb Read log/error string into this buffer

View file

@ -59,7 +59,7 @@ int clixon_event_reg_fd(int fd, int (*fn)(int, void*), void *arg, char *str);
int clixon_event_unreg_fd(int s, int (*fn)(int, void*));
int clixon_event_reg_timeout(struct timeval t, int (*fn)(int, void*),
int clixon_event_reg_timeout(struct timeval t, int (*fn)(int, void*),
void *arg, char *str);
int clixon_event_unreg_timeout(int (*fn)(int, void*), void *arg);

View file

@ -40,7 +40,7 @@
#define _CLIXON_FILE_H_
int clicon_file_dirent(const char *dir, struct dirent **ent,
int clicon_file_dirent(const char *dir, struct dirent **ent,
const char *regexp, mode_t type);
int clicon_files_recursive(const char *dir, const char *regexp, cvec *cvv);
int clicon_file_copy(char *src, char *target);

View file

@ -60,7 +60,7 @@ typedef void *plghndl_t;
*/
typedef int (clicon_output_cb)(
FILE *f,
const char *templ, ...
const char *templ, ...
) __attribute__ ((format (printf, 2, 3)));
/*

View file

@ -67,10 +67,15 @@ size_t clicon_log_string_limit_get(void);
int clicon_get_logflags(void);
int clicon_log_str(int level, char *msg);
int clicon_log(int level, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int clicon_debug(int dbglevel, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int clicon_debug_init(int dbglevel, FILE *f);
int clicon_debug_get(void);
int clixon_debug(int dbglevel, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int clixon_debug_init(int dbglevel, FILE *f);
int clixon_debug_get(void);
char *mon2name(int md);
/* 6.4 backward compatability */
#if 1
#define clicon_debug clixon_debug
#define clicon_debug_init clixon_debug_init
#define clicon_debug_get clixon_debug_get
#endif
#endif /* _CLIXON_LOG_H_ */

View file

@ -49,7 +49,7 @@ extern "C" {
#endif
ssize_t netconf_input_read2(int s, unsigned char *buf, ssize_t buflen, int *eof);
int netconf_input_msg2(unsigned char **bufp, size_t *lenp, cbuf *cbmsg,
int netconf_input_msg2(unsigned char **bufp, size_t *lenp, cbuf *cbmsg,
netconf_framing_type framing, int *frame_state, size_t *frame_size,
int *eom);
int netconf_input_frame2(cbuf *cb, yang_bind yb, yang_stmt *yspec, cxobj **xrecv, cxobj **xerr);

View file

@ -97,7 +97,8 @@
/*
* Types
*/
/*! Content query parameter RFC 8040 Sec 4.8.1
/*! Content query parameter RFC 8040 Sec 4.8.1
*
* Clixon extention: content so that RFC8040 content attribute can be conveyed
* internally used in <get>
*/
@ -111,7 +112,7 @@ typedef enum netconf_content netconf_content;
enum target_type{ /* netconf */
RUNNING,
CANDIDATE
};
};
enum test_option{ /* edit-config */
SET,
@ -126,7 +127,7 @@ enum error_option{ /* edit-config */
/* NETCONF framing
*/
enum framing_type{
enum framing_type{
NETCONF_SSH_EOM=0, /* RFC 4742, RFC 6242 hello msg (end-of-msg: ]]>]]>)*/
NETCONF_SSH_CHUNKED, /* RFC 6242 Chunked framing */
};
@ -135,7 +136,7 @@ typedef enum framing_type netconf_framing_type;
/* NETCONF with-defaults
* @see RFC 6243
*/
enum withdefaults_type{
enum withdefaults_type{
WITHDEFAULTS_REPORT_ALL = 0, /* default behavior: <= Clixon 6.0 */
WITHDEFAULTS_TRIM,
WITHDEFAULTS_EXPLICIT, /* default behavior: > Clixon 6.0 */
@ -147,6 +148,7 @@ typedef enum withdefaults_type withdefaults_type;
* Macros
*/
/*! Generate textual error log from Netconf error message
*
* @param[in] xerr Netconf error xml tree on the form: <rpc-error>
* @param[in] format Format string
* @param[in] arg String argument to format (optional)

View file

@ -46,6 +46,7 @@
* Constants
*/
/*! Clixon configuration namespace
*
* Probably should be defined somewhere else or extracted from yang
* @see clixon-config.yang
* @see clixon-lib.yang
@ -85,6 +86,7 @@ enum nacm_credentials_t{
};
/*! Datastore cache behaviour, see clixon_datastore.[ch]
*
* See config option type datastore_cache in clixon-config.yang
*/
enum datastore_cache{
@ -94,6 +96,7 @@ enum datastore_cache{
};
/*! yang clixon regexp engine
*
* @see regexp_mode in clixon-config.yang
*/
enum regexp_mode{

View file

@ -65,7 +65,7 @@ typedef struct {
qelem_t cp_qelem; /* List header */
char *cp_prefix; /* Prefix or module name, should be resolved + id to cp_yang */
char *cp_id; /* Identifier */
cvec *cp_cvk; /* Key values: list of (name:value) pairs alt (NULL:value)
cvec *cp_cvk; /* Key values: list of (name:value) pairs alt (NULL:value)
* Can also be single uint32, if so positional eg x/y[42]
* This seems kludgy but follows RFC 7950 Sec 9.13
*/
@ -81,7 +81,7 @@ int yang2api_path_fmt(yang_stmt *ys, int inclkey, char **api_path_fmt);
int api_path_fmt2api_path(const char *api_path_fmt, cvec *cvv, char **api_path, int *cvvi);
int api_path_fmt2xpath(char *api_path_fmt, cvec *cvv, char **xpath);
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, cvec **nsc, cxobj **xerr);
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
yang_class nodeclass, int strict,
cxobj **xpathp, yang_stmt **ypathp, cxobj **xerr);
int xml2api_path_1(cxobj *x, cbuf *cb);

View file

@ -50,7 +50,7 @@
/*
* Types
*/
/*! Registered RPC callback function
*
* @param[in] h Clicon handle
@ -62,11 +62,11 @@
* @retval -1 Error
*/
typedef int (*clicon_rpc_cb)(
clicon_handle h,
cxobj *xn,
cbuf *cbret,
void *arg,
void *regarg
clicon_handle h,
cxobj *xn,
cbuf *cbret,
void *arg,
void *regarg
);
/*! Registered Upgrade callback function
@ -84,22 +84,22 @@ typedef int (*clicon_rpc_cb)(
* @retval -1 Error
*/
typedef int (*clicon_upgrade_cb)(
clicon_handle h,
cxobj *xn,
clicon_handle h,
cxobj *xn,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
void *arg,
cbuf *cbret
);
);
/* Clixon authentication type
* @see http-auth-type in clixon-restconf.yang
* For now only used by restconf frontend
*/
enum clixon_auth_type {
CLIXON_AUTH_NONE = 0, /* Message is authenticated automatically to
CLIXON_AUTH_NONE = 0, /* Message is authenticated automatically to
anonymous user, maye be changed by ca-auth callback
FEATURE clixon-restconf:allow-auth-none must be enabled */
CLIXON_AUTH_CLIENT_CERTIFICATE, /* TLS Client certification authentication */
@ -108,13 +108,15 @@ enum clixon_auth_type {
};
typedef enum clixon_auth_type clixon_auth_type_t;
/* Common plugin function names, function types and signatures.
/*! Common plugin function names, function types and signatures.
*
* This plugin code is exytended by backend, cli, netconf, restconf plugins
* Cli see cli_plugin.c
* Backend see config_plugin.c
*/
/* Called when application is "started", (almost) all initialization is complete
/*! Called when application is "started", (almost) all initialization is complete
*
* Backend: daemon is in the background. If daemon privileges are dropped
* this callback is called *before* privileges are dropped.
* @param[in] h Clixon handle
@ -203,7 +205,7 @@ typedef int (plgauth_t)(clicon_handle h, void *req, clixon_auth_type_t auth_type
* @retval 0 OK
* @retval -1 Fatal error
*/
typedef int (plgreset_t)(clicon_handle h, const char *db);
typedef int (plgreset_t)(clicon_handle h, const char *db);
/* Provide state data from plugin
*
@ -215,7 +217,7 @@ typedef int (plgreset_t)(clicon_handle h, const char *db);
*
* @param[in] h Clicon handle
* @param[in] xpath Part of state requested
* @param[in] nsc XPATH namespace context.
* @param[in] nsc XPath namespace context.
* @param[out] xtop XML tree where statedata is added
* @retval 0 OK
* @retval -1 Fatal error
@ -226,7 +228,8 @@ typedef int (plgreset_t)(clicon_handle h, const char *db);
*/
typedef int (plgstatedata_t)(clicon_handle h, cvec *nsc, char *xpath, cxobj *xtop);
/* Pagination-data type
/*! Pagination-data type
*
* @see pagination_data_t in for full pagination data structure
* @see pagination_offset() and other accessor functions
*/
@ -243,7 +246,8 @@ typedef void *pagination_data;
*/
typedef int (plglockdb_t)(clicon_handle h, char *db, int lock, int id);
/* Transaction-data type
/*! Transaction-data type
*
* @see transaction_data_t and clixon_backend_transaction.h for full transaction API
*/
typedef void *transaction_data;
@ -252,6 +256,7 @@ typedef void *transaction_data;
typedef int (trans_cb_t)(clicon_handle h, transaction_data td);
/*! Hook to override default prompt with explicit function
*
* Format prompt before each getline
* @param[in] h Clicon handle
* @param[in] mode Cligen syntax mode
@ -311,6 +316,7 @@ typedef int (yang_mount_t)(clicon_handle h, cxobj *xt, int *config,
typedef int (yang_patch_t)(clicon_handle h, yang_stmt *ymod);
/*! Startup status for use in startup-callback
*
* Note that for STARTUP_ERR and STARTUP_INVALID, running runs in failsafe mode
* and startup contains the erroneous or invalid database.
* The user should repair the startup and
@ -400,6 +406,7 @@ typedef struct clixon_plugin_api clixon_plugin_api;
typedef struct clixon_plugin clixon_plugin_t;
/*! Structure for checking status before and after a plugin call
*
* The internal struct is defined in clixon_plugin.c */
typedef struct plugin_context plugin_context_t;

View file

@ -40,7 +40,7 @@
/*
* Types
*/
*/
typedef struct process_entry_t process_entry_t;
/* Process operations */
@ -52,7 +52,7 @@ typedef enum proc_operation {
PROC_OP_STATUS
} proc_operation;
/*! Process RPC callback function
/*! Process RPC callback function
*
* @param[in] h Clixon handle
* @param[in] pe Process entry
@ -64,7 +64,7 @@ typedef int (proc_cb_t)(clicon_handle h,
/*
* Prototypes
*/
*/
int clixon_proc_socket(char **argv, int sock_flags, pid_t *pid, int *sock);
int clixon_proc_socket_close(pid_t pid, int sock);
int clixon_process_pid(clicon_handle h, const char *name, pid_t *pid);

View file

@ -53,7 +53,7 @@ struct clicon_msg {
/*
* Prototypes
*/
*/
char *format_int2str(enum format_enum showas);
enum format_enum format_str2int(char *str);
@ -68,7 +68,7 @@ int clicon_rpc_connect_unix(clicon_handle h,
int *sock0);
int clicon_rpc_connect_inet(clicon_handle h,
char *dst,
char *dst,
uint16_t port,
int *sock0);

View file

@ -48,7 +48,7 @@ int clicon_rpc_msg_persistent(clicon_handle h, struct clicon_msg *msg, cxobj **x
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, char *defaults, cxobj **xret);
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
char *xml);
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
int clicon_rpc_delete_config(clicon_handle h, char *db);
@ -56,7 +56,7 @@ int clicon_rpc_lock(clicon_handle h, char *db);
int clicon_rpc_unlock(clicon_handle h, char *db);
int clicon_rpc_get2(clicon_handle h, char *xpath, cvec *nsc, netconf_content content, int32_t depth, char *defaults, int bind, cxobj **xret);
int clicon_rpc_get(clicon_handle h, char *xpath, cvec *nsc, netconf_content content, int32_t depth, char *defaults, cxobj **xret);
int clicon_rpc_get_pageable_list(clicon_handle h, char *datastore, char *xpath,
int clicon_rpc_get_pageable_list(clicon_handle h, char *datastore, char *xpath,
cvec *nsc, netconf_content content, int32_t depth, char *defaults,
uint32_t offset, uint32_t limit,
char *direction, char *sort, char *where,

View file

@ -40,6 +40,7 @@
#define _CLIXON_QUEUE_H_
/*! Circular queue structure for use as first entry in a parent structure.
*
* Add qelem_t as first element in struct
* @code
* struct a{
@ -55,6 +56,7 @@ typedef struct _qelem_t {
} qelem_t;
/*! Append element 'elem' to queue.
*
* @param[in] elem Element to be added
* @param[in,out] pred Add element after this
* @code
@ -78,6 +80,7 @@ typedef struct _qelem_t {
}
/*! Insert element 'elem' in queue after 'pred'
*
* @param[in] elem Element to be added
* @param[in,out] pred Add element after this
* @code
@ -100,7 +103,8 @@ typedef struct _qelem_t {
pred = elem; \
}
/*! Remove element 'elem' from queue. 'head' is the pointer to the queue and
/*! Remove element 'elem' from queue. 'head' is the pointer to the queue and
*
* is of 'type'.
* @param[in] elem
* @param[in] head
@ -121,6 +125,7 @@ typedef struct _qelem_t {
}
/*! Get next entry in list
*
* @param[in] type Type of element
* @param[in] el Return next element after elem.
* @code

View file

@ -40,7 +40,7 @@
/*
* Prototypes
*/
*/
int regexp_xsd2posix(char *xsd, char **posix);
int regex_compile(clicon_handle h, char *regexp, void **recomp);
int regex_exec(clicon_handle h, void *recomp, char *string);

View file

@ -45,7 +45,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]);

View file

@ -45,7 +45,8 @@
/*
* Types
*/
/* Subscription callback
/*! Subscription callback
*
* @param[in] h Clicon handle
* @param[in] op Operation: 0 OK, 1 Close
* @param[in] event Event as XML

View file

@ -39,12 +39,13 @@
#define _CLIXON_STRING_H_
/*! Struct used to map between int and strings. Typically used to map between
*
* values and their names. Note NULL terminated
* Example:
* @code
static const map_str2int atmap[] = {
{"One", 1},
{"Two", 2},
{"One", 1},
{"Two", 2},
{NULL, -1}
};
* @endcode
@ -73,7 +74,7 @@ typedef struct map_str2str map_str2str;
#include <string.h>
/*! A strdup version that aligns on 4 bytes. To avoid warning from valgrind */
static inline char * strdup4(char *str)
static inline char * strdup4(char *str)
{
char *dup;
size_t len;
@ -86,7 +87,7 @@ static inline char * strdup4(char *str)
/*
* Prototypes
*/
*/
char **clicon_strsep(char *string, char *delim, int *nvec0);
char *clicon_strjoin (int argc, char **argv, char *delim);
char *clixon_string_del_join(char *str1, char *del, char *str2);

View file

@ -41,7 +41,7 @@
/*
* Prototypes
*/
*/
int group_name2gid(const char *name, gid_t *gid);
int name2uid(const char *name, uid_t *uid);
int uid2name(const uid_t uid, char **name);

View file

@ -85,7 +85,7 @@
* This is a "neutral" symbol without any meaning as opposed to the previous symbols ^
* @see DATASTORE_TOP_SYMBOL which should be used for clixon top-level config trees
*/
#define XML_TOP_SYMBOL "top"
#define XML_TOP_SYMBOL "top"
/*
* Types
@ -102,16 +102,16 @@ enum operation_type{ /* edit-config operation */
/* Netconf insert type (see RFC7950 Sec 7.8.6) */
enum insert_type{ /* edit-config insert */
INS_FIRST,
INS_LAST,
INS_BEFORE,
INS_AFTER,
INS_FIRST,
INS_LAST,
INS_BEFORE,
INS_AFTER,
};
/* XML object types */
enum cxobj_type {CX_ERROR=-1,
CX_ELMNT,
CX_ATTR,
enum cxobj_type {CX_ERROR=-1,
CX_ELMNT,
CX_ATTR,
CX_BODY};
/* How to bind yang to XML top-level when parsing
@ -145,7 +145,7 @@ enum cxobj_type {CX_ERROR=-1,
* / \ / \
* x1 x2 - - y1 y2
*/
enum yang_bind{
enum yang_bind{
YB_NONE=0, /* Dont do Yang binding */
YB_MODULE, /* Search for matching yang binding among top-level symbols of Yang modules of direct
* children
@ -165,7 +165,7 @@ typedef enum yang_bind yang_bind;
typedef struct xml cxobj; /* struct defined in clicon_xml.c */
/*! Callback function type for xml_apply
/*! Callback function type for xml_apply
*
* @param[in] x XML node
* @param[in] arg General-purpose argument
@ -182,9 +182,9 @@ typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c
* @see format_int2str, format_str2int
*/
enum format_enum{
FORMAT_XML,
FORMAT_JSON,
FORMAT_TEXT,
FORMAT_XML,
FORMAT_JSON,
FORMAT_TEXT,
FORMAT_CLI,
FORMAT_NETCONF
};
@ -304,7 +304,7 @@ char *xml_operation2str(enum operation_type op);
int xml_attr_insert2val(char *instr, enum insert_type *ins);
int xml_add_attr(cxobj *xn, char *name, char *value, char *prefix, char *ns);
int clicon_log_xml(int level, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
int clicon_debug_xml(int dbglevel, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
int clixon_debug_xml(int dbglevel, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
#ifdef XML_EXPLICIT_INDEX
int xml_search_index_p(cxobj *x);

View file

@ -50,7 +50,7 @@ int clixon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, char *pref
int xmltree2cbuf(cbuf *cb, cxobj *x, int level);
int clixon_xml_parse_file(FILE *f, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr);
int clixon_xml_parse_string(const char *str, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr);
int clixon_xml_parse_va(yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr,
int clixon_xml_parse_va(yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr,
const char *format, ...) __attribute__ ((format (printf, 5, 6)));
int clixon_xml_attr_copy(cxobj *xin, cxobj *xout, char *name);
int clixon_xml_diff2cbuf(cbuf *cb, cxobj *x0, cxobj *x1);

View file

@ -53,9 +53,9 @@ int isxmlns(cxobj *x);
int xmlns_assign(cxobj *x);
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
int xml_diff(cxobj *x0, cxobj *x1,
cxobj ***first, int *firstlen,
cxobj ***second, int *secondlen,
int xml_diff(cxobj *x0, cxobj *x1,
cxobj ***first, int *firstlen,
cxobj ***second, int *secondlen,
cxobj ***changed_x0, cxobj ***changed_x1, int *changedlen);
int xml_tree_equal(cxobj *x0, cxobj *x1);
int xml_tree_prune_flagged_sub(cxobj *xt, int flag, int test, int *upmark);

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
*/
#ifndef _CLIXON_XPATH_H
#define _CLIXON_XPATH_H
@ -66,10 +66,10 @@ enum axis_type{
A_ANCESTOR_OR_SELF,
A_ATTRIBUTE,
A_CHILD,
A_DESCENDANT,
A_DESCENDANT,
A_DESCENDANT_OR_SELF,
A_FOLLOWING,
A_FOLLOWING_SIBLING,
A_FOLLOWING_SIBLING,
A_NAMESPACE,
A_PARENT,
A_PRECEDING,
@ -103,9 +103,10 @@ enum xp_type{
};
/*! XPATH Parsing generates a tree of nodes that is later traversed
* That is, a tree-structured XPATH.
* Note that the structure follows XPATH 1.0 closely. The drawback wit this is that the tree gets
* very deep very quickly, even for simple XPATHs.
*
* That is, a tree-structured XPath.
* Note that the structure follows XPath 1.0 closely. The drawback wit this is that the tree gets
* very deep very quickly, even for simple XPaths.
*/
struct xpath_tree{
enum xp_type xs_type;
@ -136,7 +137,7 @@ int xpath_parse(const char *xpath, xpath_tree **xptree);
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, const char *xpath, int localonly, xp_ctx **xrp);
int xpath_vec_bool(cxobj *xcur, cvec *nsc, const char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec_flag(cxobj *xcur, cvec *nsc, const char *xpformat, uint16_t flags,
int xpath_vec_flag(cxobj *xcur, cvec *nsc, const char *xpformat, uint16_t flags,
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 7)));
/* Functions with explicit namespace context (nsc) set. If you do not need

Some files were not shown because too many files have changed in this diff Show more