/******************************************************************** * FUNCTION rpc_err_clean_record * * Clean an rpc_err_rec_t struct * * INPUTS: * err == rpc_err_rec_t struct to clean * RETURNS: * none *********************************************************************/ void rpc_err_clean_record (rpc_err_rec_t *err) { rpc_err_info_t *errinfo; #ifdef DEBUG if (!err) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif err->error_res = NO_ERR; err->error_id = RPC_ERR_NONE; err->error_type = NCX_LAYER_NONE; err->error_severity = RPC_ERR_SEV_NONE; err->error_tag = NULL; err->error_app_tag = NULL; if (err->error_path) { m__free(err->error_path); err->error_path = NULL; } if (err->error_message) { m__free(err->error_message); } err->error_message_lang = NULL; while (!dlq_empty(&err->error_info)) { errinfo = (rpc_err_info_t *)dlq_deque(&err->error_info); rpc_err_free_info(errinfo); } } /* rpc_err_clean_record */
/******************************************************************** * FUNCTION rpc_free_msg * * Free all the memory used by the specified rpc_msg_t * * INPUTS: * msg == rpc_msg_t to clean and delete * RETURNS: * none *********************************************************************/ void rpc_free_msg (rpc_msg_t *msg) { if (!msg) { return; } xml_msg_clean_hdr(&msg->mhdr); //msg->rpc_in_attrs = NULL; //msg->rpc_method = NULL; //msg->rpc_agt_state = 0; /* clean input parameter set */ if (msg->rpc_input) { val_free_value(msg->rpc_input); } //msg->rpc_user1 = NULL; //msg->rpc_user2 = NULL; //msg->rpc_filter.op_filtyp = OP_FILTER_NONE; //msg->rpc_filter.op_filter = NULL; //msg->rpc_datacb = NULL; /* clean data queue */ while (!dlq_empty(&msg->rpc_dataQ)) { val_value_t *val = (val_value_t *)dlq_deque(&msg->rpc_dataQ); val_free_value(val); } m__free(msg); } /* rpc_free_msg */
/******************************************************************** * FUNCTION yangapi_clean_keyvalQ * * Free all the YANGAPI keyval * * INPUTS: * rcb == control block to use * RETURNS: * none *********************************************************************/ void yangapi_clean_keyvalQ (yangapi_cb_t *rcb) { while (!dlq_empty(&rcb->keyvalQ)) { yangapi_keyval_t *kv = (yangapi_keyval_t *) dlq_deque(&rcb->keyvalQ); yangapi_free_keyval(kv); } } /* yangapi_clean_keyvalQ */
/******************************************************************** * FUNCTION mgr_not_clean_msgQ * * Clean the msg Q of mgr_not_msg_t entries * * INPUTS: * msgQ == Q of entries to free; the Q itself is not freed * * RETURNS: * none *********************************************************************/ void mgr_not_clean_msgQ (dlq_hdr_t *msgQ) { mgr_not_msg_t *msg; #ifdef DEBUG if (!msgQ) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif msg = (mgr_not_msg_t *)dlq_deque(msgQ); while (msg) { mgr_not_free_msg(msg); msg = (mgr_not_msg_t *)dlq_deque(msgQ); } } /* mgr_not_clean_msgQ */
/******************************************************************** * FUNCTION mgr_rpc_clean_requestQ * * Clean the request Q of mgr_rpc_req_t entries * * INPUTS: * reqQ == Q of entries to free; the Q itself is not freed * * RETURNS: * none *********************************************************************/ void mgr_rpc_clean_requestQ (dlq_hdr_t *reqQ) { mgr_rpc_req_t *req; #ifdef DEBUG if (!reqQ) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif req = (mgr_rpc_req_t *)dlq_deque(reqQ); while (req) { mgr_rpc_free_request(req); req = (mgr_rpc_req_t *)dlq_deque(reqQ); } } /* mgr_rpc_clean_requestQ */
/******************************************************************** * FUNCTION agt_cfg_free_transaction * * Clean and free a agt_cfg_transaction_t struct * * INPUTS: * txcb == transaction struct to free *********************************************************************/ void agt_cfg_free_transaction (agt_cfg_transaction_t *txcb) { if (txcb == NULL) { return; } /* clear current config txid if any */ if (txcb->txid) { cfg_template_t *cfg = cfg_get_config_id(txcb->cfg_id); if (cfg) { if (cfg->cur_txid == txcb->txid) { log_debug3("\nClearing current txid for %s config", cfg->name); cfg->cur_txid = 0; } } } /* clean undo queue */ while (!dlq_empty(&txcb->undoQ)) { agt_cfg_undo_rec_t *undorec = (agt_cfg_undo_rec_t *) dlq_deque(&txcb->undoQ); agt_cfg_free_undorec(undorec); } /* clean audit queue */ while (!dlq_empty(&txcb->auditQ)) { agt_cfg_audit_rec_t *auditrec = (agt_cfg_audit_rec_t *) dlq_deque(&txcb->auditQ); agt_cfg_free_auditrec(auditrec); } /* clean dead node queue */ while (!dlq_empty(&txcb->deadnodeQ)) { agt_cfg_nodeptr_t *nodeptr = (agt_cfg_nodeptr_t *) dlq_deque(&txcb->deadnodeQ); agt_cfg_free_nodeptr(nodeptr); } m__free(txcb); } /* agt_cfg_free_transaction */
/******************************************************************** * Clean a queue of grp_template_t structs * * \param que Q of grp_template_t data structures to free *********************************************************************/ void grp_clean_groupingQ (dlq_hdr_t *que) { if (!que) { return; } while (!dlq_empty(que)) { grp_template_t *grp = (grp_template_t *)dlq_deque(que); grp_free_template(grp); } } /* grp_clean_groupingQ */
/******************************************************************** * FUNCTION free_aliases * * Free all the command aliases * *********************************************************************/ void free_aliases (void) { dlq_hdr_t *aliasQ = get_aliasQ(); alias_cb_t *alias; while (!dlq_empty(aliasQ)) { alias = (alias_cb_t *)dlq_deque(aliasQ); free_alias(alias); } } /* free_aliases */
/******************************************************************** * FUNCTION yangcli_notif_cleanup * * Cleanup this module * *********************************************************************/ void yangcli_notif_cleanup (void) { if (yangcli_notif_init_done) { while (!dlq_empty(&event_cbQ)) { event_cb_t *cb = dlq_deque(&event_cbQ); free_event_cb(cb); } yangcli_notif_init_done = FALSE; } } /* yangcli_notif_cleanup */
void agt_not_queue_notification_cb_cleanup( void ) { if ( initialised ) { agt_cb_queue_notification_set_t* cbSet; while ( !dlq_empty( &callbackQ ) ) { cbSet = ( agt_cb_queue_notification_set_t* )dlq_deque( &callbackQ ); free_callback_set( cbSet ); } initialised = false; } } /* agt_not_queue_notification_callbacks_cleanup */
void agt_commit_complete_cleanup( void ) { if ( initialised ) { agt_cb_commit_complete_set_t* cbSet; while ( !dlq_empty( &callbackQ ) ) { cbSet = ( agt_cb_commit_complete_set_t* )dlq_deque( &callbackQ ); free_callback_set( cbSet ); } initialised = false; } } /* agt_commit_complete_cleanup */
/******************************************************************** * FUNCTION clean_server_profile * * Clean the server profile variables * * OUTPUTS: * *agt_profile is filled in with params of defaults * *********************************************************************/ static void clean_server_profile (void) { ncx_clean_save_deviationsQ(&agt_profile.agt_savedevQ); while (!dlq_empty(&agt_profile.agt_commit_testQ)) { agt_cfg_commit_test_t *commit_test = (agt_cfg_commit_test_t *) dlq_deque(&agt_profile.agt_commit_testQ); agt_cfg_free_commit_test(commit_test); } if (agt_profile.agt_startup_txid_file) { m__free(agt_profile.agt_startup_txid_file); agt_profile.agt_startup_txid_file = NULL; } } /* clean_server_profile */
/******************************************************************** * FUNCTION ncx_feature_cleanup * * Cleanup the ncx_feature module * * INPUTS: * none * RETURNS: * none *********************************************************************/ void ncx_feature_cleanup (void) { feature_entry_t *feature_entry; if (!feature_init_done) { return; } while (!dlq_empty(&feature_entryQ)) { feature_entry = (feature_entry_t *)dlq_deque(&feature_entryQ); free_feature_entry(feature_entry); } feature_init_done = FALSE; } /* ncx_feature_cleanup */
/******************************************************************** * FUNCTION rpc_err_clean_errQ * * Clean all the entries from a Q of rpc_err_rec_t * * INPUTS: * errQ == Q of rpc_err_rec_t to clean * RETURNS: * none *********************************************************************/ void rpc_err_clean_errQ (dlq_hdr_t *errQ) { rpc_err_rec_t *err; #ifdef DEBUG if (!errQ) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif /* clean error queue */ while (!dlq_empty(errQ)) { err = (rpc_err_rec_t *)dlq_deque(errQ); rpc_err_free_record(err); } } /* rpc_err_clean_errQ */
/******************************************************************** * FUNCTION ncx_clean_iffeatureQ * * Clean a Q of malloced ncx_iffeature_t struct * * INPUTS: * iffeatureQ == address of Q to clean * *********************************************************************/ void ncx_clean_iffeatureQ (dlq_hdr_t *iffeatureQ) { ncx_iffeature_t *iff; #ifdef DEBUG if (!iffeatureQ) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif while (!dlq_empty(iffeatureQ)) { iff = (ncx_iffeature_t *)dlq_deque(iffeatureQ); ncx_free_iffeature(iff); } } /* ncx_clean_iffeatureQ */
/******************************************************************** * FUNCTION xml_msg_clean_hdr * * Clean all the memory used by the specified xml_msg_hdr_t * but do not free the struct itself * * Do NOT reuse this header without calling xml_msg_init_hdr first!!! * xml_msg_t headers were originally meant to be used * only in other messages, but <hello> messages use the hdr * without a wrapper message * * INPUTS: * msg == xml_msg_hdr_t to clean * RETURNS: * none *********************************************************************/ void xml_msg_clean_hdr (xml_msg_hdr_t *msg) { if (!msg) { return; } /* clean prefix queue */ while (!dlq_empty(&msg->prefixQ)) { xmlns_pmap_t *pmap = (xmlns_pmap_t *)dlq_deque(&msg->prefixQ); xmlns_free_pmap(pmap); } /* clean error queue */ rpc_err_clean_errQ(&msg->errQ); // this step not needed; not sure why it was added! msg->withdef = NCX_DEF_WITHDEF; } /* xml_msg_clean_hdr */
/******************************************************************** * FUNCTION yangapi_free_rcb * * Free a YANGAPI control block * * INPUTS: * rcb == Yuma REST-API control block to free * RETURNS: * none *********************************************************************/ void yangapi_free_rcb (yangapi_cb_t *rcb) { if (rcb == NULL) { return; } while (!dlq_empty(&rcb->paramQ)) { yangapi_param_t *param = (yangapi_param_t *)dlq_deque(&rcb->paramQ); if (param) { yangapi_free_param(param); } } yangapi_clean_keyvalQ(rcb); m__free(rcb->accept); m__free(rcb->request_method); m__free(rcb->request_uri); xpath_free_pcb(rcb->request_xpath); xpath_free_result(rcb->request_xpath_result); xpath_free_pcb(rcb->query_select_xpath); xpath_free_result(rcb->query_select_xpath_result); xpath_free_pcb(rcb->query_test_xpath); xpath_free_result(rcb->query_test_xpath_result); m__free(rcb->content_type); m__free(rcb->content_length); m__free(rcb->if_modified_since); m__free(rcb->if_unmodified_since); m__free(rcb->if_match); m__free(rcb->if_none_match); m__free(rcb); } /* yangapi_free_rcb */
/******************************************************************** * FUNCTION clean_undorec * * Clean all the memory used by the specified agt_cfg_undo_rec_t * but do not free the struct itself * * !!! The caller must free internal pointers that were malloced * !!! instead of copied. This function does not check them!!! * * INPUTS: * undo == agt_cfg_undo_rec_t to clean * reuse == TRUE if possible reuse * FALSE if this node is being freed right now * * RETURNS: * none *********************************************************************/ static void clean_undorec (agt_cfg_undo_rec_t *undo, boolean reuse) { if (undo->free_curnode && undo->curnode) { val_free_value(undo->curnode); } if (undo->curnode_clone) { val_free_value(undo->curnode_clone); } if (undo->newnode_marker) { val_free_value(undo->newnode_marker); } if (undo->curnode_marker) { val_free_value(undo->curnode_marker); } /* really expecting the extra_deleteQ to be empty at this point */ while (!dlq_empty(&undo->extra_deleteQ)) { agt_cfg_nodeptr_t *nodeptr = (agt_cfg_nodeptr_t *) dlq_deque(&undo->extra_deleteQ); if (nodeptr && nodeptr->node) { val_remove_child(nodeptr->node); val_free_value(nodeptr->node); } else { SET_ERROR(ERR_INTERNAL_VAL); } agt_cfg_free_nodeptr(nodeptr); } if (reuse) { agt_cfg_init_undorec(undo); } } /* clean_undorec */
/******************************************************************** * FUNCTION exit_config_mode * * Exit the configuration mode * * INPUTS: * session_cb == session control block to use * *********************************************************************/ static void exit_config_mode (session_cb_t *session_cb) { session_cb->config_mode = FALSE; session_cb->config_no_active = FALSE; session_cb->config_edit_dirty = FALSE; session_cb->alt_names = session_cb->config_alt_names; session_cb->match_names = session_cb->config_match_names; m__free(session_cb->config_path); session_cb->config_path = NULL; session_cb->config_curval = NULL; session_cb->config_curobj = NULL; session_cb->config_curkey = NULL; val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; session_cb->config_ecurval = NULL; while (!dlq_empty(&session_cb->config_editQ)) { config_edit_t *edit = (config_edit_t *) dlq_deque(&session_cb->config_editQ); free_config_edit(edit); } } /* exit_config_mode */
/******************************************************************** * FUNCTION process_apply * (config mode input received) * Handle the apply command and check if there are edits * to apply to the server. If so apply the edits. * * INPUTS: * server_cb == server control block to use * session_cb == session control block to use * * RETURNS: * status *********************************************************************/ static status_t process_apply (server_cb_t *server_cb, session_cb_t *session_cb) { if (dlq_empty(&session_cb->config_editQ)) { if (LOGDEBUG2) { log_debug2("\nSkipping apply, no edits"); } session_cb->config_edit_dirty = FALSE; return NO_ERR; } /* make a dummy config root -- it will not be used; only the child * nodes added to this container will be added to the <config> * parameter in the <edit-config> operation */ val_value_t *configval = xml_val_new_root(NCX_EL_CONFIG, xmlns_nc_id()); if (configval == NULL) { log_error("\nError: malloc failed"); return ERR_INTERNAL_MEM; } status_t res = NO_ERR; boolean anyedits = FALSE; uint32 editcnt = dlq_count(&session_cb->config_editQ); while (!dlq_empty(&session_cb->config_editQ)) { config_edit_t *edit = (config_edit_t *) dlq_deque(&session_cb->config_editQ); /* compare the edit to the shadow config to see if it * represents any change or not */ boolean ischange = check_edit(session_cb, edit); if (ischange) { /** TBD: add to tree and collapse all edits!!! */ val_add_child(edit->edit_payload, configval); edit->edit_payload = NULL; anyedits = TRUE; } else if (LOGDEBUG3) { log_debug3("\nSkipping edit due to no change:\n"); val_dump_value(edit->edit_payload, 0); } free_config_edit(edit); } if (!anyedits) { val_free_value(configval); return NO_ERR; } if (server_cb->program_mode == PROG_MODE_SERVER) { if (LOGDEBUG) { if (editcnt == 1) { log_debug("\nApplying 1 edit\n"); } else { log_debug("\nApplying %u edits\n", editcnt); } } } else { if (LOGINFO) { const xmlChar *sesname = (session_cb->session_cfg) ? session_cb->session_cfg->name : NCX_EL_DEFAULT; if (editcnt == 1) { log_info("\nApplying 1 edit to session '%s'\n", sesname); } else { log_info("\nApplying %u edits to session '%s'\n", editcnt, sesname); } } } session_cb->command_mode = CMD_MODE_CONF_APPLY; session_cb->config_edit_dirty = FALSE; res = send_edit_config_to_server(server_cb, session_cb, NULL, configval, TRUE, session_cb->timeout, OP_DEFOP_MERGE); /* configval consumed no matter what! */ return res; } /* process_apply */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_lock_invoke * * RPC invocation phase * All constraints have passed at this point. * Call device instrumentation code in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_lock_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { plock_cb_t *plcb; val_value_t *testval, *newval; xpath_result_t *result; xpath_resnode_t *resnode, *clearnode; xmlChar *pathbuff; cfg_template_t *running; status_t res; ncx_num_t num; res = NO_ERR; plcb = (plock_cb_t *)msg->rpc_user1; result = plock_get_final_result(plcb); running = cfg_get_config_id(NCX_CFGID_RUNNING); /* try to lock all the target nodes */ for (resnode = xpath_get_first_resnode(result); resnode != NULL && res == NO_ERR; resnode = xpath_get_next_resnode(resnode)) { testval = xpath_get_resnode_valptr(resnode); res = val_set_partial_lock(testval, plcb); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, testval); } } /* unlock any nodes already attempted if any fail */ if (res != NO_ERR) { for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); if (clearnode == resnode) { return res; } } return res; } /* add this partial lock to the running config */ res = cfg_add_partial_lock(running, plcb); if (res != NO_ERR) { /* should not happen since config lock state could * not have changed since validate callback */ agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); } plock_cb_free(plcb); return res; } /* setup return data only if lock successful * cache the reply instead of stream the reply * in case there is any error; if so; the partial * lock will be backed out and the dataQ cleaned * for an error exit; add lock-id leaf first */ msg->rpc_data_type = RPC_DATA_YANG; ncx_init_num(&num); num.u = plock_get_id(plcb); newval = xml_val_new_number (y_ietf_netconf_partial_lock_N_lock_id, val_get_nsid(msg->rpc_input), &num, NCX_BT_UINT32); ncx_clean_num(NCX_BT_UINT32, &num); if (newval == NULL) { res = ERR_INTERNAL_MEM; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } else { dlq_enque(newval, &msg->rpc_dataQ); } /* add lock-node leaf-list instance for each resnode */ for (resnode = xpath_get_first_resnode(result); resnode != NULL && res == NO_ERR; resnode = xpath_get_next_resnode(resnode)) { /* Q&D method: generate the i-i string as a plain * string and add any needed prefixes to the global * prefix map for the reply message (in mhdr) */ pathbuff = NULL; testval = xpath_get_resnode_valptr(resnode); res = val_gen_instance_id(&msg->mhdr, testval, NCX_IFMT_XPATH1, &pathbuff); if (res == NO_ERR) { /* make leaf; pass off pathbuff malloced memory */ newval = xml_val_new_string (y_ietf_netconf_partial_lock_N_locked_node, val_get_nsid(msg->rpc_input), pathbuff); if (newval == NULL) { res = ERR_INTERNAL_MEM; m__free(pathbuff); pathbuff = NULL; } } if (res == NO_ERR) { dlq_enque(newval, &msg->rpc_dataQ); } else { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } } if (res != NO_ERR) { /* back out everything, except waste the lock ID */ for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); } cfg_delete_partial_lock(running, plock_get_id(plcb)); /* clear any data already queued */ while (!dlq_empty(&msg->rpc_dataQ)) { testval = (val_value_t *) dlq_deque(&msg->rpc_dataQ); val_free_value(testval); } msg->rpc_data_type = RPC_DATA_NONE; } return res; } /* y_ietf_netconf_partial_lock_partial_lock_invoke */