/******************************************************************** * FUNCTION mgr_rpc_dispatch * * Dispatch an incoming <rpc-reply> response * handle the <rpc-reply> element * called by mgr_top.c: * This function is registered with top_register_node * for the module 'netconf', top-node 'rpc-reply' * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void mgr_rpc_dispatch (ses_cb_t *scb, xml_node_t *top) { obj_template_t *rpyobj; mgr_rpc_rpy_t *rpy; mgr_rpc_req_t *req; xml_attr_t *attr; xmlChar *msg_id; ncx_module_t *mod; mgr_rpc_cbfn_t handler; ncx_num_t num; status_t res; #ifdef DEBUG if (!scb || !top) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif /* init local vars */ res = NO_ERR; msg_id = NULL; req = NULL; /* make sure any real session has been properly established */ if (scb->type != SES_TYP_DUMMY && scb->state != SES_ST_IDLE) { log_error("\nError: mgr_rpc: skipping incoming message '%s'", top->qname); mgr_xml_skip_subtree(scb->reader, top); return; } /* check if the reply template is already cached */ rpyobj = NULL; mod = ncx_find_module(NC_MODULE, NULL); if (mod != NULL) { rpyobj = ncx_find_object(mod, NC_RPC_REPLY_TYPE); } if (rpyobj == NULL) { SET_ERROR(ERR_NCX_DEF_NOT_FOUND); mgr_xml_skip_subtree(scb->reader, top); return; } /* get the NC RPC message-id attribute; should be present * because the send-rpc function put a message-id in <rpc> */ attr = xml_find_attr(top, 0, NCX_EL_MESSAGE_ID); if (attr && attr->attr_val) { msg_id = xml_strdup(attr->attr_val); } if (msg_id == NULL) { mgr_xml_skip_subtree(scb->reader, top); log_info("\nmgr_rpc: incoming message with no message-id"); return; } /* the current node is 'rpc-reply' in the netconf namespace * First get a new RPC reply struct */ rpy = new_reply(); if (rpy == NULL) { m__free(msg_id); log_error("\nError: mgr_rpc: skipping incoming message"); mgr_xml_skip_subtree(scb->reader, top); return; } else { rpy->msg_id = msg_id; } /* get the NCX RPC group-id attribute if present */ attr = xml_find_attr(top, xmlns_ncx_id(), NCX_EL_GROUP_ID); if (attr && attr->attr_val) { res = ncx_decode_num(attr->attr_val, NCX_BT_UINT32, &num); if (res == NO_ERR) { rpy->group_id = num.u; } } /* find the request that goes with this reply */ if (rpy->msg_id != NULL) { req = find_request(scb, rpy->msg_id); if (req == NULL) { #ifdef MGR_RPC_DEBUG log_debug("\nmgr_rpc: got request found for msg (%s) " "on session %d", rpy->msg_id, scb->sid); #endif mgr_xml_skip_subtree(scb->reader, top); mgr_rpc_free_reply(rpy); return; } else { dlq_remove(req); } } /* have a request/reply pair, so parse the reply * as a val_value_t tree, stored in rpy->reply */ rpy->res = mgr_val_parse_reply(scb, rpyobj, (req != NULL) ? req->rpc : ncx_get_gen_anyxml(), top, rpy->reply); if (rpy->res != NO_ERR && LOGINFO) { log_info("\nmgr_rpc: got invalid reply on session %d (%s)", scb->sid, get_error_string(rpy->res)); } /* check that there is nothing after the <rpc-reply> element */ if (rpy->res==NO_ERR && !xml_docdone(scb->reader) && LOGINFO) { log_info("\nmgr_rpc: got extra nodes in reply on session %d", scb->sid); } /* invoke the reply handler */ if (req != NULL) { handler = (mgr_rpc_cbfn_t)req->replycb; (*handler)(scb, req, rpy); } /* only reset the session state to idle if was not changed * to SES_ST_SHUTDOWN_REQ during this RPC call */ if (scb->state == SES_ST_IN_MSG) { scb->state = SES_ST_IDLE; } #ifdef MGR_RPC_DEBUG print_errors(); clear_errors(); #endif } /* mgr_rpc_dispatch */
/******************************************************************** * FUNCTION xml_msg_gen_xmlns_attrs * * Generate any xmlns directives in the top-level * attribute Q * * INPUTS: * msg == message in progress * attrs == xmlns_attrs_t Q to process * addncx == TRUE if an xmlns for the NCX prefix (for errors) * should be added to the <rpc-reply> element * FALSE if not * * OUTPUTS: * *attrs will be populated as needed, * * RETURNS: * status *********************************************************************/ status_t xml_msg_gen_xmlns_attrs (xml_msg_hdr_t *msg, xml_attrs_t *attrs, boolean addncx) { xmlns_pmap_t *pmap, *newpmap; xmlChar *buff; status_t res, retres; boolean ncxfound; xmlns_id_t ncx_id; #ifdef DEBUG if (!msg || !attrs) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif ncxfound = FALSE; retres = NO_ERR; ncx_id = xmlns_ncx_id(); for (pmap = (xmlns_pmap_t *)dlq_firstEntry(&msg->prefixQ); pmap != NULL; pmap = (xmlns_pmap_t *)dlq_nextEntry(pmap)) { if (pmap->nm_id == ncx_id) { ncxfound = TRUE; } if (pmap->nm_topattr) { continue; } buff = NULL; res = xml_msg_gen_new_prefix(msg, pmap->nm_id, &buff, 0); if (res == NO_ERR) { res = xml_add_xmlns_attr(attrs, pmap->nm_id, buff); } if (buff) { m__free(buff); } if (res != NO_ERR) { retres = res; } else { pmap->nm_topattr = TRUE; } } if (!ncxfound && addncx && retres == NO_ERR) { /* need to create a new prefix map and save it */ newpmap = xmlns_new_pmap(0); if (!newpmap) { retres = ERR_INTERNAL_MEM; } else { /* generate a prefix ID */ newpmap->nm_id = ncx_id; newpmap->nm_topattr = TRUE; res = xml_msg_gen_new_prefix(msg, ncx_id, &newpmap->nm_pfix, 0); if (res == NO_ERR) { /* add the new prefix mapping to the prefixQ */ res = xml_add_xmlns_attr(attrs, newpmap->nm_id, newpmap->nm_pfix); if (res == NO_ERR) { add_pmap(msg, newpmap); } else { xmlns_free_pmap(newpmap); retres = res; } } else { xmlns_free_pmap(newpmap); retres = res; } } } return retres; } /* xml_msg_gen_xmlns_attrs */
/******************************************************************** * FUNCTION mgr_rpc_send_request * * Send an <rpc> request to the agent on the specified session * non-blocking send, reply function will be called when * one is received or a timeout occurs * * INPUTS: * scb == session control block * req == request to send * rpyfn == reply callback function * * RETURNS: * status *********************************************************************/ status_t mgr_rpc_send_request (ses_cb_t *scb, mgr_rpc_req_t *req, mgr_rpc_cbfn_t rpyfn) { xml_msg_hdr_t msg; xml_attr_t *attr; status_t res; boolean anyout; xmlns_id_t nc_id; #ifdef DEBUG if (!scb || !req || !rpyfn) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif #ifdef MGR_HELLO_DEBUG log_debug2("\nmgr sending RPC request %s on session %d", req->msg_id, scb->sid); #endif anyout = FALSE; xml_msg_init_hdr(&msg); nc_id = xmlns_nc_id(); /* make sure the message-id attribute is not already present */ attr = xml_find_attr_q(&req->attrs, 0, NCX_EL_MESSAGE_ID); if (attr) { dlq_remove(attr); xml_free_attr(attr); } /* setup the prefix map with the NETCONF (and maybe NCX) namespace */ res = xml_msg_build_prefix_map(&msg, &req->attrs, FALSE, (req->data->nsid == xmlns_ncx_id())); /* add the message-id attribute */ if (res == NO_ERR) { res = xml_add_attr(&req->attrs, 0, NCX_EL_MESSAGE_ID, req->msg_id); } /* set perf timestamp in case response timing active */ gettimeofday(&req->perfstarttime, NULL); /* send the <?xml?> directive */ if (res == NO_ERR) { res = ses_start_msg(scb); } /* start the <rpc> element */ if (res == NO_ERR) { anyout = TRUE; xml_wr_begin_elem_ex(scb, &msg, 0, nc_id, NCX_EL_RPC, &req->attrs, ATTRQ, 0, START); } /* send the method and parameters */ if (res == NO_ERR) { xml_wr_full_val(scb, &msg, req->data, NCX_DEF_INDENT); } /* finish the <rpc> element */ if (res == NO_ERR) { xml_wr_end_elem(scb, &msg, nc_id, NCX_EL_RPC, 0); } /* finish the message */ if (anyout) { ses_finish_msg(scb); } if (res == NO_ERR) { req->replycb = rpyfn; add_request(scb, req); } xml_msg_clean_hdr(&msg); return res; } /* mgr_rpc_send_request */