example-system.c
The following example code can be found in the libsystem/src directory.
/*
* Copyright (c) 2012 - 2024, YumaWorks, Inc., All Rights Reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* FILE: example-system.c
Example External System Library
*********************************************************************
* *
* I N C L U D E F I L E S *
* *
*********************************************************************/
#include <stdlib.h>
#include <xmlstring.h>
#include "procdefs.h"
#include "agt.h"
#include "agt_acm.h"
#include "agt_acm_ietf.h"
#include "agt_acm_extern.h"
#include "agt_util.h"
#include "agt_cfg.h"
#include "agt_cb.h"
#include "agt_commit_complete.h"
#include "agt_glob.h"
#include "agt_hook_util.h"
#include "dlq.h"
#include "example-system.h"
#include "getcb.h"
#include "log.h"
#include "log_vendor.h"
#include "log_vendor_extern.h"
#include "ncx.h"
#include "ncxconst.h"
#include "ncxmod.h"
#include "ncxtypes.h"
#include "obj.h"
#include "ses.h"
#include "status.h"
#include "typ_userdef.h"
#include "val.h"
#include "val_util.h"
#include "xml_util.h"
/********************************************************************
* *
* C O N S T A N T S *
* *
*********************************************************************/
/* this flag is used to enable the NACM external group examples */
// #define ADD_NACM_GROUP 1
/* this flag is used to enable the Session Hook callback examples */
// #define ADD_SESSION_HOOK 1
/* this flag is used to enable the canonical callback for an IPv6
* address examples
*/
// #define ADD_IPV6_FN 1
/* this flag is used to enable the External ACM Hooks examples */
// #define ADD_ACM_EXTERN 1
/* this flag is used to enable Vendor log functions examples */
// #define ADD_VENDOR_LOG 1
/* this flag is used to enable External NV-Storage Handler Hooks examples */
// #define ADD_NV_STORE_HOOK 1
/* this flag is used to enable Transaction Management Hooks examples */
// #define ADD_TRANS_HOOK 1
/* this flag is used to enable Commit Completeness Hooks examples */
// #define ADD_CC_HOOK 1
/* this flag is used to enable Edit Phase Complete Callback examples */
// #define ADD_EPC_HOOK 1
/* this flag is used to enable YANG Object Template Callback examples */
// #define ADD_YANG_OBJ_TEMP 1
/* this flag is used to enable YANG Extension Handler Callback examples */
// #define ADD_YANG_EXTEN 1
/* this flag is used to enable RPC Command Complete examples */
// #define ADD_RPC_COMPLETE 1
/* this flag is used to enable the user-type callback examples */
// #define ADD_USER_TYPE 1
#define USERTYPE_MODULE (const xmlChar *)"iana-crypt-hash"
#define USERTYPE_TYPE (const xmlChar *)"crypt-hash"
/* The Commit Complete Callback needs a module name
* It just needs to be the same in the register and unregister call
*/
#define CC_HOOK_MODULE (const xmlChar *)"my-module"
/* this flag is used to enable Global EDIT3 callback examples */
// #define ADD_GLOBAL_EDIT 1
/* this flag is used to enable Global GET2 callback examples */
// #define ADD_GLOBAL_GET 1
/* this flag is used to enable Global RPC callback examples */
// #define ADD_GLOBAL_RPC 1
/* this flag is used to enable Global Action callback examples */
// #define ADD_GLOBAL_ACTION 1
/********************************************************************
* *
* F U N C T I O N S *
* *
*********************************************************************/
static uint32 cb_trace = 0;
/**************** Example Callback for Global EDIT3 *******************/
#ifdef ADD_GLOBAL_EDIT
/*
* @brief Edit database object callback (agt_edit3_fn_t)\n
*
* @param editcb Edit Control Block that contains
* EDIT3 callback information
*
* @return return status for the phase.
*/
status_t
sample_global_edit3 (agt_editcb_t *editcb)
{
status_t res = NO_ERR;
/* Callback information available in the callback */
ses_cb_t *scb = editcb->scb;
rpc_msg_t *msg = editcb->msg;
agt_cbtyp_t cbtyp = editcb->cbtyp;
op_editop_t editop = editcb->editop;
/* Node related information available in the callback */
val_value_t *newval = editcb->newval;
val_value_t *curval = editcb->curval;
val_value_t *update = editcb->update;
obj_template_t *obj = editcb->obj;
const xmlChar *modname = editcb->modname;
/* Transaction information available in the callback */
agt_cfg_transaction_t *txcb = editcb->txcb;
boolean isvalidate = editcb->isvalidate;
boolean isrunning = editcb->isrunning;
const xmlChar *user_id = editcb->user_id;
const xmlChar *client_addr = editcb->client_addr;
const xmlChar *target = editcb->target;
const xmlChar *txid_str = editcb->txid_str;
const xmlChar *instance_id = editcb->instance_id;
val_value_t *errorval = (curval) ? curval : newval;
/* Invoke callbacks only for specific nodes from a
* specific module. Skip callback for any nodes
* that are not from 'sample' YANG module
*/
if (xml_strcmp(modname, (const xmlChar *)"sample")) {
if (LOGDEBUG) {
log_debug("\n Skipping callback for module '%s'",
modname);
}
return res;
} else {
if (LOGDEBUG) {
log_debug("\n (%s) Enter GLOBAL EDIT-3 callback"
"\n ------PHASE:%s;EDITOP:%s"
"\n ------Instance ID:%s\n",
errorval ? VAL_NAME(errorval) : NCX_NT_NONE,
agt_cbtype_name(cbtyp),
op_editop_name(editop),
instance_id);
}
}
switch (cbtyp) {
case AGT_CB_VALIDATE:
/* description-stmt validation here */
break;
case AGT_CB_APPLY:
/* database manipulation are performed by the server here */
break;
case AGT_CB_COMMIT:
/* device instrumentation done here */
if (op_editop_is_delete(editop)) {
/* Delete all data from the device */
} else {
/* Use update value to update your device data
*
* The technique here is to replace the existing data
* with this composite Update value.
*/
}
break;
case AGT_CB_ROLLBACK:
/* undo device instrumentation done in Apply Phase */
break;
default:
FLAG_INT_ERROR;
res = ERR_INTERNAL_VAL;
}
return res;
} /* sample_global_edit3 */
#endif // ADD_GLOBAL_EDIT
/**************** Example Callback for Global GET2 *******************/
#ifdef ADD_GLOBAL_GET
/* GET2 TEST
*
* see ncx/getcb.h (getcb_fn2_t)
*/
static status_t
sample_global_get2 (ses_cb_t *scb,
xml_msg_hdr_t *msg,
getcb_get2_t *get2cb)
{
(void)scb;
(void)msg;
/* check the callback mode type */
getcb_mode_t cbmode = GETCB_GET2_CBMODE(get2cb);
switch (cbmode) {
case GETCB_GET_VALUE:
break;
case GETCB_GETNEXT_VALUE:
return ERR_NCX_NO_INSTANCE;
default:
return SET_ERROR(ERR_INTERNAL_VAL);
}
status_t res = NO_ERR;
obj_template_t *obj = GETCB_GET2_OBJ(get2cb);
const xmlChar *modname = obj_get_mod_name(obj);
/* Invoke callbacks only for specific nodes from a
* specific module. Skip callback for any nodes
* that are not from 'sample' YANG module
*/
if (xml_strcmp(modname, (const xmlChar *)"sample")) {
if (LOGDEBUG) {
log_debug("\n Skipping callback for module '%s'",
modname);
}
return res;
} else {
getcb_dump_get2cb(get2cb);
}
return res;
} /* sample_global_get2 */
#endif // ADD_GLOBAL_GET
/**************** Example Callback for Global RPC *******************/
#ifdef ADD_GLOBAL_RPC
/*
* @brief Validation phase callback for Global RPC\n
*
* All YANG constraints have passed at this point.
* Add description-stmt checks in this function.
*
* @param scb session invoking the RPC operation.
* @param msg message in progress for this <rpc> request.
* The msg->rpc_input value node contains the input (if any).
* It is a container matching the rpc/input node for the YANG rpc.
* @param methnode XML node for the operation, which can be used
* in error reporting (or ignored).
* @return return status for the phase.
* - An error in validate phase will cancel invoke phase
* - An rpc-error will be added if an error is returned and
* the msg error Q is empty
*/
static status_t
global_rpc_validate (ses_cb_t *scb,
rpc_msg_t *msg,
xml_node_t *methnode)
{
status_t res = NO_ERR;
/* YANG module found for this node */
const xmlChar *modname = methnode->module;
/* qualified name of element */
const xmlChar *qname = methnode->qname;
/* element name without any prefix */
const xmlChar *elname = methnode->elname;
/* Invoke Global RPC callbacks only for module with a name sample */
if (xml_strcmp(modname, (const xmlChar *)"sample")) {
if (LOGDEBUG) {
log_debug("\n Skipping VALIDATE callback for module '%s'",
modname);
}
return res;
} else {
if (LOGDEBUG) {
log_debug("\n\nEnter GLOBAL RPC VALIDATE callback"
"\n modname=%s"
"\n RPC Qualified Name=%s"
"\n RPC Name=%s",
modname,
qname ? qname : NCX_NT_NONE,
elname ? elname : NCX_NT_NONE);
}
}
/* Check RPC input to ensure it is required */
val_value_t *inputval = agt_get_rpc_input(msg);
if (inputval == NULL) {
return ERR_NCX_OPERATION_FAILED;
}
/* Assign an error value in case any errors occur */
val_value_t *errorval = NULL;
/* Handle Input parameter here */
if (res != NO_ERR) {
agt_record_error(scb,
&msg->mhdr,
NCX_LAYER_OPERATION,
res,
methnode,
(errorval) ? NCX_NT_VAL : NCX_NT_NONE,
errorval,
(errorval) ? NCX_NT_VAL : NCX_NT_NONE,
errorval);
}
return res;
} /* global_rpc_validate */
/*
* @brief Invocation phase callback for GLOBAL RPC\n
*
* Validation callback has passed at this point.
* Call device instrumentation code in this function.
*
* @param scb session invoking the RPC operation.
* @param msg message in progress for this <rpc> request.
* The msg->rpc_input value node contains the input (if any).
* It is a container matching the rpc/input node for the YANG rpc.
* @param methnode XML node for the operation, which can be used
* in error reporting (or ignored).
* @return return status for the phase.
* - An error in validate phase will cancel invoke phase
* - An rpc-error will be added if an error is returned and
* the msg error Q is empty
*/
static status_t
global_rpc_invoke (ses_cb_t *scb,
rpc_msg_t *msg,
xml_node_t *methnode)
{
status_t res = NO_ERR;
/* YANG module found for this node */
const xmlChar *modname = methnode->module;
/* qualified name of element */
const xmlChar *qname = methnode->qname;
/* element name without any prefix */
const xmlChar *elname = methnode->elname;
/* Invoke Global RPC callbacks only for module with a name sample */
if (xml_strcmp(modname, (const xmlChar *)"sample")) {
if (LOGDEBUG) {
log_debug("\n Skipping INVOKE callback for module '%s'",
modname);
}
return res;
} else {
if (LOGDEBUG) {
log_debug("\n\nEnter GLOBAL RPC INVOKE callback"
"\n modname=%s"
"\n RPC Qualified Name=%s"
"\n RPC Name=%s",
modname,
qname ? qname : NCX_NT_NONE,
elname ? elname : NCX_NT_NONE);
}
}
/* Check RPC input to ensure it is required */
val_value_t *inputval = agt_get_rpc_input(msg);
if (inputval == NULL) {
return ERR_NCX_OPERATION_FAILED;
}
/* remove the next line if scb is used */
(void)scb;
/* invoke your device instrumentation code here */
obj_template_t *outputobj = agt_get_rpc_output_obj(msg);
if (outputobj == NULL) {
return ERR_NCX_OPERATION_FAILED;
}
/* Handle Output parameters here */
return res;
} /* global_rpc_invoke */
#endif // ADD_GLOBAL_RPC
/**************** Example Callback for Global Action *******************/
#ifdef ADD_GLOBAL_ACTION
/*
* @brief YANG 1.1 global action validate callback. (agt_action_cb_t)\n
*
* @param scb session invoking the "<action>" RPC
* @param msg message in progress for this "<rpc>" request
* @param methnode XML node for the operation, which can be used
* in error reporting (or ignored).
* @param actionval the nested 'action-method-name' node that was parsed
* within the topval subtree, in the RPC "<action>" request.
* This is used to help derive the list keys.
* @return return status for the phase.
* - An error in validate phase will cancel invoke phase
* - An rpc-error will be added if an error is returned and
* the msg error Q is empty
*/
static status_t
global_action_validate (ses_cb_t *scb,
rpc_msg_t *msg,
xml_node_t *methnode,
val_value_t *actionval)
{
status_t res = NO_ERR;
/* YANG module found for this node */
const xmlChar *modname = methnode->module;
/* qualified name of element */
const xmlChar *qname = methnode->qname;
/* element name without any prefix */
const xmlChar *elname = methnode->elname;
/* Invoke Global Action callbacks only for module with a name sample */
if (xml_strcmp(modname, (const xmlChar *)"sample")) {
if (LOGDEBUG) {
log_debug("\n Skipping VALIDATE callback for module '%s'",
modname);
}
return res;
} else {
if (LOGDEBUG) {
log_debug("\n\nEnter GLOBAL ACTION VALIDATE callback"
"\n modname=%s"
"\n Action Qualified Name=%s"
"\n Action Name=%s",
modname,
qname ? qname : NCX_NT_NONE,
elname ? elname : NCX_NT_NONE);
}
}
/* Assign an error value in case any errors occur */
val_value_t *errorval = NULL;
/* Handle Action Input parameter here */
(void)actionval;
if (res != NO_ERR) {
agt_record_error(scb,
&msg->mhdr,
NCX_LAYER_OPERATION,
res,
methnode,
(errorval) ? NCX_NT_VAL : NCX_NT_NONE,
errorval,
(errorval) ? NCX_NT_VAL : NCX_NT_NONE,
errorval);
}
return res;
} /* global_action_validate */
/*
* @brief YANG 1.1 global action invoke callback. (agt_action_cb_t)\n
*
* @param scb session invoking the "<action>" RPC
* @param msg message in progress for this "<rpc>" request
* @param methnode XML node for the operation, which can be used
* in error reporting (or ignored).
* @param actionval the nested 'action-method-name' node that was parsed
* within the topval subtree, in the RPC "<action>" request.
* This is used to help derive the list keys.
* @return return status for the phase.
* - An error in validate phase will cancel invoke phase
* - An rpc-error will be added if an error is returned and
* the msg error Q is empty
*/
static status_t
global_action_invoke (ses_cb_t *scb,
rpc_msg_t *msg,
xml_node_t *methnode,
val_value_t *actionval)
{
status_t res = NO_ERR;
/* YANG module found for this node */
const xmlChar *modname = methnode->module;
/* qualified name of element */
const xmlChar *qname = methnode->qname;
/* element name without any prefix */
const xmlChar *elname = methnode->elname;
/* Invoke Global Action callbacks only for module with a name sample */
if (xml_strcmp(modname, (const xmlChar *)"sample")) {
if (LOGDEBUG) {
log_debug("\n Skipping INVOKE callback for module '%s'",
modname);
}
return res;
} else {
if (LOGDEBUG) {
log_debug("\n\nEnter GLOBAL ACTION INVOKE callback"
"\n modname=%s"
"\n Action Qualified Name=%s"
"\n Action Name=%s",
modname,
qname ? qname : NCX_NT_NONE,
elname ? elname : NCX_NT_NONE);
}
}
/* Handle Action Input parameter here */
(void)actionval;
/* remove the next line if msg is used */
(void)msg;
/* remove the next line if scb is used */
(void)scb;
/* remove the next line if methnode is used */
(void)methnode;
/* invoke your device instrumentation code here */
/* Handle Output parameters here */
return res;
} /* global_action_invoke */
#endif // ADD_GLOBAL_ACTION
/**************** Example Callback for an IPv6 address *******************/
#ifdef ADD_IPV6_FN
/********************************************************************
* FUNCTION my_ipv6_fn
*
* Canonical callback for an IPv6 address.
* Convert the inval to the canonical format for the type
*
* INPUTS:
* typdef == type definition for the user defined type
* val == input value to convert
* cookie == cookie value passed to register function
*
* OUTPUTS:
* val == can be changed to canonical format
*
* RETURNS:
* status
*
*********************************************************************/
static status_t
my_ipv6_fn (typ_def_t *typdef,
val_value_t *val,
void *cookie)
{
(void)typdef;
(void)cookie;
log_debug("\nmy_ipv6_fn called ******************************");
return NO_ERR;
} /* my_ipv6_fn */
#endif // ADD_IPV6_FN
#ifdef ADD_USER_TYPE
/********************************************************************
* FUNCTION dummy1_canonical_fn
*
* Canonical callback for a data type.
* Convert the inval to the canonical format for the type (not really)
*
* INPUTS:
* typdef == type definition for the user defined type
* val == input value to convert
* cookie == cookie value passed to register function
*
* OUTPUTS:
* val == can be changed to canonical format
*
* RETURNS:
* status
*
*********************************************************************/
static status_t
dummy1_canonical_fn (typ_def_t *typdef,
val_value_t *val,
void *cookie)
{
(void)typdef;
(void)cookie;
log_debug("\ndummy1_canonical(%s) called *****", VAL_NAME(val));
/* real function would change the value to canonical format */
return NO_ERR;
} /* dummy1_canonical_fn */
/********************************************************************
* FUNCTION dummy1_compare_fn
*
* Compare callback for a data type.
*
* INPUTS:
* typdef == type definition for the user defined type
* val1 == input value 1 to comapre
* val2 == input value 2 to comapre
* cookie == cookie value passed to register function
* retval == address of return compare value
* OUTPUTS:
* *retval == return compare value
* RETURNS:
* status (ERR_NCX_SKIPPED if no compare done)
*/
static status_t
dummy1_compare_fn (const typ_def_t *typdef,
const val_value_t *val1,
const val_value_t *val2,
void *cookie,
int *retval)
{
(void)typdef;
(void)cookie;
log_debug("\ndummy1_compare(%s) called *****", VAL_NAME(val1));
/* This must be a real compare function!
* just use the default compare function
* real function would compare the 2 values with different function
*/
*retval = val_compare(val1, val2);
return NO_ERR;
} /* dummy1_compare_fn */
/********************************************************************
* FUNCTION dummy1_validate_fn
* user validation callback for a userdef type
* Invoked when the input data is checked for field validation
* such as xml_parse. Applies to RPC input and datastore nodes
* INPUTS:
* typdef == type definition for the user defined type
* inval == input value to convert
* cookie == cookie value passed to register function
* RETURNS:
* the validation status
*/
static status_t
dummy1_validate_fn (typ_def_t *typdef,
val_value_t *val,
void *cookie)
{
(void)typdef;
(void)cookie;
log_debug("\ndummy1_validate(%s) called *****", VAL_NAME(val));
/* real function would test the value */
return NO_ERR;
} /* dummy1_validate_fn */
#endif // ADD_USER_TYPE
/**************** Example External ACM Hooks *******************/
#ifdef ADD_ACM_EXTERN
/********************************************************************
* FUNCTION acm_extern_rpc
*
* Check if the specified user is allowed to invoke an RPC
*
* INPUTS:
* msg == XML header in incoming message in progress
* user == user name string
* rpcobj == obj_template_t for the RPC method to check
*
* RETURNS:
* TRUE if user allowed invoke this RPC; FALSE otherwise
*
*********************************************************************/
static boolean
acm_extern_rpc (xml_msg_hdr_t *msg,
const xmlChar *user,
const obj_template_t *rpcobj)
{
(void)msg;
const xmlChar *modname = obj_get_mod_name(rpcobj);
const xmlChar *objname = obj_get_name(rpcobj);
log_debug("\nChecking RPC access for user %s to operation '%s:%s'",
user, modname, objname);
// check access here
log_debug("\nacm_extern_rpc: return OK\n");
return TRUE;
} /* acm_extern_rpc */
/********************************************************************
* FUNCTION acm_extern_notif
*
* Check if the specified user is allowed to receive
* a notification event
*
* INPUTS:
* user == user name string
* notifobj == obj_template_t for the notification event to check
*
* RETURNS:
* TRUE if user allowed receive this notification event;
* FALSE otherwise
*********************************************************************/
static boolean
acm_extern_notif (const xmlChar *user,
const obj_template_t *notifobj)
{
const xmlChar *modname = obj_get_mod_name(rpcobj);
const xmlChar *objname = obj_get_name(rpcobj);
log_debug("\nChecking Notification access for "
"user %s to event '%s:%s'",
user, modname, objname);
// check access here
log_debug("\nacm_extern_notif: return OK\n");
return TRUE;
} /* acm_extern_notif */
/********************************************************************
* FUNCTION acm_extern_write_fn
*
* Check if the specified user is allowed to access a value node
* The val->obj template will be checked against the val->editop
* requested access and the user's configured max-access
*
* INPUTS:
* msg == XML header from incoming message in progress
* newval == val_value_t in progress to check
* (may be NULL, if curval set)
* curval == val_value_t in progress to check
* (may be NULL, if newval set)
* val == val_value_t in progress to check
* editop == requested CRUD operation
*
* RETURNS:
* TRUE if user allowed this level of access to the value node
*********************************************************************/
static boolean
acm_extern_write (xml_msg_hdr_t *msg,
const xmlChar *user,
const val_value_t *newval,
const val_value_t *curval,
op_editop_t editop)
{
(void)msg;
(void)user;
(void)newval;
(void)curval;
(void)editop;
log_debug("\nacm_extern_write: return OK\n");
return TRUE;
} /* acm_extern_write */
/********************************************************************
* FUNCTION acm_extern_read_fn
*
* Check if the specified user is allowed to read a value node
*
* INPUTS:
* msg == XML header from incoming message in progress
* user == user name string
* val == val_value_t in progress to check
*
* RETURNS:
* TRUE if user allowed read access to the value node
*********************************************************************/
static boolean
acm_extern_read (xml_msg_hdr_t *msg,
const xmlChar *user,
const val_value_t *val)
{
(void)msg;
(void)user;
(void)val;
log_debug("\nacm_extern_read: return OK\n");
return TRUE;
} /* acm_extern_read */
#endif // ADD_ACM_EXTERN
/**************** Example External NACM Group Hook *******************/
#ifdef ADD_NACM_GROUP
/********************************************************************
* FUNCTION nacm_external_group_cbfn
*
* Get the list of group names for this username
* These groups are added to the usergroup cache for the session
* INPUTS:
* username: return the list of group names that this username
* is a member
* retgroups == address of return malloced string
* OUTPUTS:
* *retgroups is set to a malloced string that will be parsed.
* It contains a whitespace delimited list of group named
* ' group1 group2 group3'
* The caller will free this string with m__free
* RETURNS:
* status: if an error occurs the session will only use NACM groups
*********************************************************************/
static status_t
nacm_external_group_cbfn (const xmlChar *username,
xmlChar **retgroups)
{
if (retgroups == NULL) {
return ERR_NCX_INVALID_VALUE;
}
(void)username;
/* MUST use a function that allocates memory with m__getMem
* Will be freed by the caller with m__free macro
*/
*retgroups = xml_strdup("group1 group2 group5");
if (*retgroups == NULL) {
return ERR_INTERNAL_MEM;
}
return NO_ERR;
} /* nacm_external_group_cbfn */
#endif // ADD_NACM_GROUP
/************** Example External Log Vendor Hooks ***************/
#ifdef ADD_VENDOR_LOG
/********************************************************************
* FUNCTION log_vendor_send_fn
*
* Vendor function to consume log output (mandatory)
*
* INPUTS:
* app == "Facility" (Yangcli or Netconfd)
* level == Logging level (error, warn, info, debug, ..., debug4)
* fstr == format string (like printf)
* args == variable argument list
*
* RETURNS:
* void
*********************************************************************/
static void
log_vendor_send_fn (log_debug_app_t app,
log_debug_t level,
const char *fstr,
va_list args)
{
(void)app;
(void)level;
(void)fstr;
(void)args;
return;
} /* log_vendor_send_fn */
#endif // ADD_VENDOR_LOG
/*********** Example External NV-Storage Handler Hooks **********/
#ifdef ADD_NV_STORE_HOOK
#define EXAMPLE_CONFIG_SPEC (const xmlChar *)"/tmp/example-config.xml"
/********************************************************************
* FUNCTION example_nvsave
*
* Nvsave callback is invoked when some config needs to be saved
* to non-volatile storage
*
* INPUTS:
* encoding == encoding format for the config (xml only allowed value)
* filespec == filespec containing the config to save
*
* RETURNS:
* status; error indicates NV-save failed somehow
*
*********************************************************************/
static status_t
example_nvsave (ncx_display_mode_t encoding,
const xmlChar *filespec)
{
status_t res = NO_ERR;
if (filespec == NULL || *filespec == 0) {
res = ERR_NCX_INVALID_VALUE;
} else if (encoding != NCX_DISPLAY_MODE_XML) {
res = ERR_NCX_INVALID_VALUE;
} else {
res = ncxmod_copy_text_file(filespec, EXAMPLE_CONFIG_SPEC);
}
return res;
} /* example_nvsave */
/********************************************************************
* FUNCTION example_nvload
*
* Nvload callback invoked when some config needs to be read
* from non-volatile storage
*
* INPUTS:
* encoding == address of encoding for the config
* filespec == address of filespec containing the config that was loaded
*
* OUTPUTS:
* *encoding == set to the enum for the encoding used in the config
* *filespec == malloced filespec containing the config that was loaded
*
* RETURNS:
* status; error indicates NV-load failed somehow
* If return NO_ERR and *filespec == NULL then use the factory config
*
*********************************************************************/
static status_t
example_nvload (ncx_display_mode_t *encoding,
xmlChar **filespec)
{
log_debug("\nEnter example_nvload");
*filespec = NULL;
*encoding = NCX_DISPLAY_MODE_XML;
status_t res = NO_ERR;
if (ncxmod_test_filespec(EXAMPLE_CONFIG_SPEC)) {
/* file exists so copy the filespec */
*filespec = xml_strdup(EXAMPLE_CONFIG_SPEC);
if (*filespec == NULL) {
res = ERR_INTERNAL_MEM;
}
}
return res;
} /* example_nvload */
#endif // ADD_NV_STORE_HOOK
/*********** Example Transaction Management Hooks **********/
#ifdef ADD_TRANS_HOOK
/********************************************************************
* FUNCTION example_transaction_start
*
* The Start Transaction function is the user/system
* callback that is invoked before any changes to the
* candidate database will be committed.
*
* INPUTS:
* txcb == transaction control block in progress
*
* RETURNS:
* status
*
*********************************************************************/
static status_t
example_transaction_start (agt_cfg_transaction_t *txcb)
{
(void)txcb;
log_debug("\nEnter transaction_start example");
return NO_ERR;
} /* example_transaction_start */
/********************************************************************
* FUNCTION example_transaction_complete
*
* The Transaction Complete function is the
* user/system callback that is invoked after
* the transactions has been processed.
*
* INPUTS:
* txcb == transaction control block in progress
*
* RETURNS:
* none
*
*********************************************************************/
static void
example_transaction_complete (agt_cfg_transaction_t *txcb)
{
(void)txcb;
log_debug("\nEnter transaction_complete example");
return;
} /* example_transaction_complete */
#endif // ADD_TRANS_HOOK
#ifdef ADD_CC_HOOK
/********************************************************************
* FUNCTION example_validate_complete
*
* The Validate Complete callback is the user/system callback
* that is invoked after the Validate Phase has been processed
* during the <commit> operation.
*
* The Validate Complete is object independent and module
* independent which means you don't have to link them to
* the specific object as it's done for EDIT or GET callbacks,
* and you don't have to link them to any specific module
*
* Max Callbacks: No limit (except available heap memory)
*
* @param scb session control block making the request
* @param msg incoming rpc_msg_t in progress
* @param candidate candidate val_value_t for the config database to use
* @param running running val_value_t for the config database to use
* @return status
*/
static status_t
example_validate_complete (ses_cb_t *scb,
rpc_msg_t *msg,
val_value_t *candidate,
val_value_t *running)
{
if (LOGDEBUG) {
log_debug("\n*** Enter Validate Complete Callback (%u)",
++cb_trace);
}
status_t res = NO_ERR;
(void)scb;
(void)msg;
(void)candidate;
(void)running;
return res;
} /* example_validate_complete */
/********************************************************************
* FUNCTION example_apply_complete
*
* The Apply Complete callback is the user/system callback
* that is invoked after the Validate Phase has been processed
* during the <commit> operation.
*
* The Validate Complete is object independent and module
* independent which means you don't have to link them to
* the specific object as it's done for EDIT or GET callbacks,
* and you don't have to link them to any specific module
*
* Max Callbacks: No limit (except available heap memory)
*
* @param scb session control block making the request
* @param msg incoming rpc_msg_t in progress
* @param candidate candidate val_value_t for the config database to use
* @param running running val_value_t for the config database to use
* @return status
*/
static status_t
example_apply_complete (ses_cb_t *scb,
rpc_msg_t *msg,
val_value_t *candidate,
val_value_t *running)
{
if (LOGDEBUG) {
log_debug("\n*** Enter Apply Complete Callback (%u)",
++cb_trace);
}
status_t res = NO_ERR;
(void)scb;
(void)msg;
(void)candidate;
(void)running;
return res;
} /* example_apply_complete */
/********************************************************************
* FUNCTION example_commit_complete
*
* - Specific to the <commit> operation
* - Invoked if the validate, apply, and commit all return NO_ERR
* - This is a legacy API from yuma
*
* NOTE: IF RETURN VALUE IS NOT NO_ERR:
* - PRIOR TO 22.10T-10: This function causes an error to be returned
* but no Rollback phase is done
* - Starting with 22.10T-10: This function causes an error to be returned
* and also a Rollback phase is done
*
* @param commit_type
* - AGT_COMMIT_TYPE_NORMAL is a <commit> operation
* - AGT_COMMIT_TYPE_REPLAY is a replay-commit procedure
* @return status
* - Need to return NO_ERR or else end of transaction can be incompleted
*/
static status_t
example_commit_complete (agt_commit_type_t commit_type)
{
if (LOGDEBUG) {
log_debug("\n*** Enter Commit Complete Callback (%u)",
++cb_trace);
}
status_t res = NO_ERR;
(void)commit_type;
if (cb_trace > 5) {
//res = ERR_NCX_RESOURCE_DENIED;
}
return res;
} /* example_commit_complete */
/********************************************************************
* FUNCTION example_rollback_complete
*
* The Rollback Complete callback is the user/system callback
* that is invoked after and if the Rollback Phase has been processed
* during the <commit> operation.
*
* The Rollback Complete is object independent and module
* independent which means you don't have to link them to
* the specific object as it's done for EDIT or GET callbacks,
* and you don't have to link them to any specific module.
*
* Max Callbacks: No limit (except available heap memory)
*
* @param scb session control block making the request
* @param msg incoming rpc_msg_t in progress
* @param candidate candidate val_value_t for the config database to use
* @param running running val_value_t for the config database to use
* @return status
*/
static status_t
example_rollback_complete (ses_cb_t *scb,
rpc_msg_t *msg,
val_value_t *candidate,
val_value_t *running)
{
if (LOGDEBUG) {
log_debug("\n*** Enter Rollback Complete Callback (%u)",
++cb_trace);
}
status_t res = NO_ERR;
(void)scb;
(void)msg;
(void)candidate;
(void)running;
return res;
} /* example_rollback_complete */
#endif // ADD_CC_HOOK
/*********** Example Edit Phase Complete Template Callback **********/
#ifdef ADD_EPC_HOOK
/*
* @brief Example agt_cb_edit_phase_complete_t callback
*
* The Edit Phase Complete callback is the user/system callback
* that is invoked after each edit transaction phase has been processed
* during any edit transaction operation.
*
* Edit phases are defined in agt_cbtyp_t enumeration
*
* Callbacks for the AGT_CB_VALIDATE phase may be invoked
* for the <candidate> or <running> datastore.
*
* Callbacks for the other phases may be invoked
* for the <running> datastore.
*
* If the return value is not NO_ERR then the edit transaction
* will be terminated and a rollback will begin.
*
* Max Callbacks: No limit (except available heap memory)
*
* @param edit_phase edit phase enumeration that has just been completed
* @param scb session control block making the request
* @param msg incoming rpc_msg_t in progress
* @param source val_value_t for the source config database to use
* @param target val_value_t for the target config database to use
* @return status
*/
static status_t
example_edit_phase_complete (agt_cbtyp_t edit_phase,
ses_cb_t *scb,
rpc_msg_t *msg,
val_value_t *source,
val_value_t *target)
{
if (LOGDEBUG) {
log_debug("\n*** Enter Edit Phase Complete Callback "
"for '%s' (%u)",
agt_cbtype_name(edit_phase),
++cb_trace);
}
status_t res = NO_ERR;
(void)scb;
(void)msg;
(void)source;
(void)target;
/* check the specific phase that has just completed
* and set res to some error if the edit transaction
* should be rejected. (validate, apply, commit)
* For rollback phase this function can only change the
* status of the rollback printed in log messages
*/
switch (edit_phase) {
case AGT_CB_VALIDATE:
case AGT_CB_APPLY:
case AGT_CB_COMMIT:
case AGT_CB_ROLLBACK:
break;
default:
res = ERR_NCX_INVALID_VALUE;
}
return res;
}
#endif // ADD_EPC_HOOK
/*********** Example YANG Object Template Callback **********/
#ifdef ADD_YANG_OBJ_TEMP
#define FL_ACME_1 0x1
/********************************************************************
* FUNCTION example_transaction_complete
*
* User function callback template when a YANG object is
* parsed by yang_obj.c. This API is invoked at the
* end of the resolve phase if the status is NO_ERR
* It is skipped if the object has errors detected at the time
*
* Callback is invoked to check extensions in an obj_template_t
* representing YANG data nodes
*
* Assume YANG module foo exists with extension acme1
*
* module foo {
* prefix f;
* ...
* extension acme1 { ... }
*
*
* The extension is used inside object definitions. e.g:
*
* leaf X {
* f:acme1;
* type string;
* }
*
* Assume there is a vendor bit defined for the user flags field
* ncx_yang_obj_cbfn_t
*
* Run an instrumentation-defined function
* for a 'object parsed' event
*
* INPUTS:
* mod == module that is being parsed now
* obj == object being parsed
*
*********************************************************************/
static void
example_obj_template_cbfn (ncx_module_t *mod,
struct obj_template_t_ *obj)
{
/* optional: use the module to check cetain module names to
* pre-filter the callback
*/
(void)mod;
/* get the appinfoQ for the object */
dlq_hdr_t *appinfoQ = obj_get_appinfoQ(obj);
if (appinfoQ == NULL) {
return; // error!
}
/* check the object template appinfoQ to see if the vendor
* extensions are present
*/
ncx_appinfo_t *appinfo =
ncx_find_appinfo(appinfoQ,
(const xmlChar *)"f",
(const xmlChar *)"acme1");
if (appinfo) {
OBJ_USER_FLAGS(obj) |= FL_ACME_1;
}
} /* example_obj_template_cbfn */
#endif // ADD_YANG_OBJ_TEMP
/*********** Example YANG Extension Handler Callback **********/
#ifdef ADD_YANG_EXTEN
/********************************************************************
* FUNCTION example_ext_cbfn
*
* One YANG Extension Handler Callback
*
* Callback is invoked to check a specific extension in an
* obj_template_t, typ_template_t, typ_def_t
*
* Assume the same YANG module foo exists with extension acme1
*
* The example callback does the same task as the
* example_obj_template_cbfn, using the per-callback approach
*
* Handle the parsing and processing of an external statement
* using the associated YANG extension statement
*
* This callback is invoked when the external statement is
* first encountered. The current token is the argument string
* if any or the identifier token if none.
* The next token is expected to be a semi-colon or a left brace
* The callback is expected to parse the closing semi-colon or
* entire sub-section including starting brace
*
* INPUTS:
* rawpcb == parser control block in progress (cast as void *)
* mod == module being processed
* tkc == token chain of module tokens parse in progress
* ext == extension definition record (allows a handler to
* process multiple extension types)
* cookie == cbfn_cookie from the extension 'ext'
* arg == argument string used in the external statement (if any)
* node_type == type of node being processed; direct parent
* statement of the external statement using the extension
* If NULL, then the parent statement is the module itself,
* and 'mod' should be used as the 'node' pointer
* node == pointer to node indicated by node_type
* OUTPUTS:
*
* RETURNS:
* status of processing
*
*********************************************************************/
static status_t
example_ext_cbfn (void *rawpcb, // struct yang_pcb_t_ *pcb
ncx_module_t *mod,
tk_chain_t *tkc,
struct ext_template_t_ *ext,
void *cookie,
const xmlChar *arg,
ncx_node_t node_type,
void *node)
{
(void)rawpcb;
(void)mod;
(void)tkc;
(void)ext;
(void)cookie;
(void)arg;
/* ignore this extension in all contexts except object template */
if (node_type != NCX_NT_OBJ) {
return NO_ERR;
}
/* get the object template */
obj_template_t *obj = (obj_template_t *)node;
/* set the acme1 bit */
OBJ_USER_FLAGS(obj) |= FL_ACME_1;
return NO_ERR;
} /* example_ext_cbfn */
#endif // ADD_YANG_EXTEN
/*********** Example RPC Command Complete Callback **********/
#ifdef ADD_RPC_COMPLETE
/********************************************************************
* FUNCTION example_command_complete_cbfn
*
* One RPC Command Complete Handler Callback
*
* The Command Complete callback is the user/system callback
* that is invoked after each client command is executed
* for the NETCONF or RESTCONF protocols.
*
* The Command Complete is typically used for retrieval
* operations (get, get-config, get-bulk) to release resources
* used during GET2 callbacks invoked during the operation.
*
* Max Callbacks: limited by memory only
*
* INPUTS:
* scb == session control block making the request
* msg == incoming rpc_msg_t in progress
* command_modname == YANG module name of command that is completed
* command_name == YANG RPC object name of command that is completed
*
* OUTPUTS:
* none
*
* RETURNS:
* none
*
*********************************************************************/
static void
example_command_complete_cbfn (ses_cb_t *scb,
rpc_msg_t *msg,
const xmlChar *command_modname,
const xmlChar *command_name)
{
if (!xml_strcmp(command_modname, (const xmlChar *)"RESTCONF")) {
/* RESTCONF specific handling */
if (!xml_stricmp(command_name, (const xmlChar *)"POST") ||
!xml_stricmp(command_name, (const xmlChar *)"PUT") ||
!xml_stricmp(command_name, (const xmlChar *)"PATCH")) {
/* post, put or patch handling */
}
} else {
/* NETCONF operations handling */
if (!xml_strcmp(command_name, (const xmlChar *)"get") ||
!xml_strcmp(command_name, (const xmlChar *)"get-config") ||
!xml_strcmp(command_name, (const xmlChar *)"get-bulk")) {
/* cleanup our internal get cache data
* example_clean_get2_cache(scb, msg);
*/
}
}
} /* example_command_complete_cbfn */
#endif // ADD_RPC_COMPLETE
/*********** Example Session Hook Callback **********/
#ifdef ADD_SESSION_HOOK
/********************************************************************
* FUNCTION example_session_hook
*
* The Session Hook callback is invoked when a session starts
* and ends.
* Use ses.h macros like SES_USERNAME(scb) to get
* data like client username
* Max Callbacks: No limit (except available heap memory)
*
* INPUTS:
* ses_event == session event type
* scb == session control block for the session event
*
* OUTPUTS:
* none
*
* RETURNS:
* none
*
*********************************************************************/
static void
example_session_hook (ncx_ses_event_t ses_event,
const ses_cb_t *scb)
{
if (!scb) {
FLAG_INT_ERROR;
return;
}
/* event name is either session-start or session-end */
const xmlChar *event_name = ncx_get_ses_event_str(ses_event);
/* peer_addr should be set */
const xmlChar *peer_addr = SES_PEERADDR(scb);
if (peer_addr == NULL) {
peer_addr = NCX_EL_LOCALHOST;
}
/* user_name should be set */
const xmlChar *user_name = SES_MY_USERNAME(scb);
if (user_name == NULL) {
user_name = NCX_EL_NOBODY;
}
/* protocol name should be set */
ncx_protocol_t protocol = ses_get_protocol(scb);
const xmlChar *protocol_name = ncx_get_protocol_name(protocol);
if (protocol_name == NULL) {
protocol_name = NCX_EL_NONE;
}
log_info("\nGot %s event from host %s, user %s, protocol %s\n",
event_name, peer_addr, user_name, protocol_name);
} /* example_session_hook */
#endif // ADD_SESSION_HOOK
/**************** Required System Library Hooks *******************/
/********************************************************************
* FUNCTION yp_system_init_profile
*
* system init server profile callback
*
* Initialize the server profile if needed
*
* INPUTS:
* profile == server profile to change if needed
*
*********************************************************************/
void
yp_system_init_profile (agt_profile_t *profile)
{
(void) profile;
log_debug("\nyp_system init profile\n");
/* example: use an external ACM module */
//profile->agt_acm_model = AGT_ACM_MODEL_EXTERNAL;
/* example: set the with-defaults also-supported bits
* from agt/agt.h:
* bitmask of the with-defaults enumerations that should be
* enabled in the server
* explicit: bit0
* trim: bit1
* report-all: bit2
* report-all-tagged: bit3
*
* uint8 agt_withdef_enabled;
*
* The basic-mode (agt_defaultStyle and agt_defaultStyleEnum)
* will be added by the server automatically, so a value of 0
* will not enable any 'also-supported' retrieval modes
* for the 'with-defaults' leaf
*/
//profile->agt_withdef_enabled = bit1 | bit3;
/* add to enable callhome reconnect after a close-session */
//profile->agt_callhome_reconnect = TRUE;
} /* yp_system_init_profile */
/********************************************************************
* FUNCTION yp_system_init1
*
* init1 system call
* this callback is invoked twice; before and after CLI processing
*
* INPUTS:
* pre_cli == TRUE if this call is before the CLI parameters
* have been read
* FALSE if this call is after the CLI parameters
* have been read
* RETURNS:
* status
*
*********************************************************************/
status_t yp_system_init1 (boolean pre_cli)
{
status_t res = NO_ERR;
log_debug("\nyp_system init1 (%s)\n",
pre_cli ? "pre-CLI" : "post-CLI");
if (pre_cli) {
#ifdef ADD_VENDOR_LOG
// example -- register vendor callback to consume logging output.
/* Note that output will not be re-directed to the vendor stream
* until AFTER --log-vendor is parsed by CLI processing or log_vendor
* is parsed by config file processing.
* Uncomment the following 2 lines to enable!!
*/
log_vendor_extern_register_send_fn(log_vendor_send_fn);
#endif // ADD_VENDOR_LOG
} else {
#ifdef ADD_ACM_EXTERN
/* example -- external NACM callbacks
* load module for external module
* with ncxmod_load_module
* register the external ACM callbacks
* this will have no affect unless the
* yp_system_init_profile fn sets the
* agt_acm_model to AGT_ACM_MODEL_EXTERNAL
*/
agt_acm_extern_register_callbacks(acm_extern_rpc,
acm_extern_notif,
acm_extern_write,
acm_extern_read);
#endif // ADD_ACM_EXTERN
#ifdef ADD_NV_STORE_HOOK
/* example -- register NV-storage handler to load/save config */
res = agt_register_local_nv_handler(example_nvload,
example_nvsave);
if (res != NO_ERR) {
return res;
}
#endif // ADD_NV_STORE_HOOK
#ifdef ADD_YANG_OBJ_TEMP
/* example -- Register a YANG Object Template Callback */
res = ncx_set_yang_obj_callback(example_obj_template_cbfn);
if (res != NO_ERR) {
return res;
}
#endif // ADD_YANG_OBJ_TEMP
#ifdef ADD_YANG_EXTEN
/* example -- Register an Extension Handler Callback */
res = ext_register_cbfn((const xmlChar *)"acme-ext",
(const xmlChar *)"acme1",
example_ext_cbfn,
NULL); // cookie
if (res != NO_ERR) {
return res;
}
#endif // ADD_YANG_EXTEN
#ifdef ADD_IPV6_FN
/* Example: register a type-specific callback
* In real usage at least 1 of the 3 callback functions
* must be set
*/
res = typ_userdef_register(NCXMOD_IETF_INET_TYPES,
(const xmlChar *)"ipv6-address-no-zone",
NULL, // validate_fn
my_ipv6_fn, // canonical_fn
NULL, // compare_fn
NULL); // cookie
if (res != NO_ERR) {
return res;
}
#endif // ADD_IPV6_FN
#ifdef ADD_USER_TYPE
/* Example: register a type-specific callback
* Show all 3 callbacks being used
*/
res = typ_userdef_register(USERTYPE_MODULE,
USERTYPE_TYPE,
dummy1_validate_fn,
dummy1_canonical_fn,
dummy1_compare_fn,
NULL); // cookie
if (res != NO_ERR) {
return res;
}
#endif // ADD_USER_TPYE
#ifdef ADD_SESSION_HOOK
/* Example: register a Session Hook callback
* uncomment following to enable
*/
res = agt_cb_session_hook_register(example_session_hook);
if (res != NO_ERR) {
return res;
}
#endif // ADD_SESSION_HOOK
#ifdef ADD_GLOBAL_EDIT
/* Example: register a Global EDIT3 callback
* uncomment following to enable
*/
res = agt_glob_register_edit3(sample_global_edit3);
if (res != NO_ERR) {
return res;
}
#endif // ADD_GLOBAL_EDIT
#ifdef ADD_GLOBAL_GET
/* Example: register a Global GET2 callback
* uncomment following to enable
*/
res = agt_glob_register_get(sample_global_get2);
if (res != NO_ERR) {
return res;
}
#endif // ADD_GLOBAL_GET
#ifdef ADD_GLOBAL_RPC
/* Example: register a Global RPC callback
* uncomment following to enable
*/
res =
agt_glob_register_rpc(AGT_RPC_PH_VALIDATE,
global_rpc_validate);
if (res != NO_ERR) {
return res;
}
res =
agt_glob_register_rpc(AGT_RPC_PH_INVOKE,
global_rpc_invoke);
if (res != NO_ERR) {
return res;
}
#endif // ADD_GLOBAL_RPC
#ifdef ADD_GLOBAL_ACTION
/* Example: register a Global RPC callback
* uncomment following to enable
*/
res =
agt_glob_register_action(AGT_RPC_PH_VALIDATE,
global_action_validate);
if (res != NO_ERR) {
return res;
}
res =
agt_glob_register_action(AGT_RPC_PH_INVOKE,
global_action_invoke);
#endif // ADD_GLOBAL_ACTION
}
return res;
} /* yp_system_init1 */
/********************************************************************
* FUNCTION yp_system_init2
*
* init2 system call
* this callback is invoked twice; before and after
* load_running_config processing
*
* INPUTS:
* pre_load == TRUE if this call is before the running config
* has been loaded
* FALSE if this call is after the running config
* has been loaded
* RETURNS:
* status
*
*********************************************************************/
status_t
yp_system_init2 (boolean pre_load)
{
status_t res = NO_ERR;
log_debug("\nyp_system init2 (%s)\n",
pre_load ? "pre-load-config" : "post-load-config");
if (pre_load) {
#ifdef ADD_NACM_GROUP
/* example -- Register a NACM External Groups Callback
* uncomment following to enable
*/
agt_acm_ietf_register_group_cbfn(nacm_external_group_cbfn);
#endif // ADD_NACM_GROUP
#ifdef ADD_RPC_COMPLETE
/* initialize a Command Complete callback */
res = agt_cb_command_complete_register(example_command_complete_cbfn);
if (res != NO_ERR) {
return res;
}
#endif // ADD_RPC_COMPLETE
#ifdef ADD_TRANS_HOOK
/* example -- Register a Transaction Start callback */
res = agt_cb_trans_start_register(example_transaction_start);
if (res != NO_ERR) {
return res;
}
/* example -- Register a Transaction Complete callback */
res = agt_cb_trans_complete_register(example_transaction_complete);
if (res != NO_ERR) {
return res;
}
#endif // ADD_TRANS_HOOK
#ifdef ADD_CC_HOOK
/* example -- Register a Validate Complete callback */
res = agt_cb_validate_complete_register(example_validate_complete);
if (res != NO_ERR) {
return res;
}
/* example -- Register an Apply Complete callback */
res = agt_cb_apply_complete_register(example_apply_complete);
if (res != NO_ERR) {
return res;
}
/* example -- Register an Commit Complete callback */
res = agt_commit_complete_register(CC_HOOK_MODULE,
example_commit_complete);
if (res != NO_ERR) {
return res;
}
/* example -- Register a Rollback Complete callback */
res = agt_cb_rollback_complete_register(example_rollback_complete);
if (res != NO_ERR) {
return res;
}
#endif // ADD_CC_HOOK
#ifdef ADD_EPC_HOOK
/* example -- Register an Edit Phase Complete callback */
res = agt_cb_edit_phase_complete_register(example_edit_phase_complete);
if (res != NO_ERR) {
return res;
}
#endif // ADD_EPC_HOOK
} else {
;
}
return res;
} /* yp_system_init2 */
/********************************************************************
* FUNCTION yp_system_cleanup
*
* System cleanup callback
* this callback is invoked once during agt_cleanup
*
* INPUTS:
* none
*
* RETURNS:
* none
*
*********************************************************************/
void yp_system_cleanup (void)
{
log_debug("\nyp_system cleanup\n");
#ifdef ADD_SESSION_HOOK
/* Example: Unregister a Session Hook callback.
* This is optional; will get deleted at shutdown
* uncomment following to enable
*/
agt_cb_session_hook_unregister(example_session_hook);
#endif // ADD_SESSION_HOOK
#ifdef ADD_TRANS_HOOK
/* example -- Unregister a Transaction Start callback */
agt_cb_trans_start_unregister(example_transaction_start);
/* example -- Unregister a Transaction Complete callback */
agt_cb_trans_complete_unregister(example_transaction_complete);
#endif // ADD_TRANS_HOOK
#ifdef ADD_CC_HOOK
/* example -- UnRegister a Validate Complete callback */
agt_cb_validate_complete_unregister(example_validate_complete);
/* example -- UnRegister an Apply Complete callback */
agt_cb_apply_complete_unregister(example_apply_complete);
/* example -- UnRegister an Commit Complete callback */
agt_commit_complete_unregister(CC_HOOK_MODULE);
/* example -- Register a Rollback Complete callback */
agt_cb_rollback_complete_unregister(example_rollback_complete);
#endif // ADD_CC_HOOK
#ifdef ADD_EPC_HOOK
/* example -- UnRegister a Validate Complete callback */
agt_cb_edit_phase_complete_unregister(example_edit_phase_complete);
#endif // ADD_EPC_HOOK
#ifdef ADD_GLOBAL_EDIT
/* example -- UnRegister a Global EDIT3 callback */
agt_glob_unregister_edit();
#endif // ADD_GLOBAL_EDIT
#ifdef ADD_GLOBAL_GET
/* example -- UnRegister a Global GET2 callback */
agt_glob_unregister_get();
#endif // ADD_GLOBAL_GET
#ifdef ADD_GLOBAL_RPC
/* example -- UnRegister a Global RPC callback */
agt_glob_unregister_rpc();
#endif // ADD_GLOBAL_RPC
#ifdef ADD_GLOBAL_ACTION
/* example -- UnRegister a Global Action callback */
agt_glob_unregister_action();
#endif // ADD_GLOBAL_ACTION
} /* yp_system_cleanup */
/* END example-system.c */