/******************************************************************** * FUNCTION mgr_hello_dispatch * * Handle an incoming <hello> message from the client * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void mgr_hello_dispatch (ses_cb_t *scb, xml_node_t *top) { val_value_t *val; ncx_module_t *mod; obj_template_t *obj; mgr_scb_t *mscb; xml_msg_hdr_t msg; status_t res; #ifdef DEBUG if (!scb || !top) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif #ifdef MGR_HELLO_DEBUG if (LOGDEBUG) { log_debug("\nmgr_hello got node"); } if (LOGDEBUG2) { xml_dump_node(top); } #endif mscb = mgr_ses_get_mscb(scb); /* only process this message in hello wait state */ if (scb->state != SES_ST_HELLO_WAIT) { /* TBD: stats update */ if (LOGINFO) { log_info("\nmgr_hello dropped, wrong state for session %d", scb->sid); } return; } /* init local vars */ res = NO_ERR; val = NULL; obj = NULL; xml_msg_init_hdr(&msg); /* get a value struct to hold the server hello msg */ val = val_new_value(); if (!val) { res = ERR_INTERNAL_MEM; } /* get the type definition from the registry */ if (res == NO_ERR) { mod = ncx_find_module(NC_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, MGR_SERVER_HELLO_OBJ); } if (!obj) { /* netconf module should have loaded this definition */ res = SET_ERROR(ERR_INTERNAL_PTR); } } /* parse an server hello message */ if (res == NO_ERR) { res = mgr_val_parse(scb, obj, top, val); } /* examine the server capability list * and it matches the server protocol version */ if (res == NO_ERR) { res = process_server_hello(scb, val); } /* report first error and close session */ if (res != NO_ERR) { if (LOGINFO) { log_info("\nmgr_connect error (%s)\n dropping session %u (a:%u)", get_error_string(res), scb->sid, mscb->agtsid, res); } } else { scb->state = SES_ST_IDLE; if (LOGDEBUG) { log_debug("\nmgr_hello manager hello ok"); } } if (val) { val_free_value(val); } } /* mgr_hello_dispatch */
/******************************************************************** * FUNCTION consume_node * * Internal consume XML node function * see agt_xml_consume_node for details. * * EXTRA INPUTS: * eoferr == TRUE if an End of File error should be generated * == FALSE if not * nserr == TRUE if bad namespace should be checked * == FALSE if not * clean == TRUE is a string should be cleaned before returned * == FALSE if a string node should be returned as-is * * RETURNS: * status of the operation * Try to fail on fatal errors only *********************************************************************/ static status_t consume_node (ses_cb_t *scb, boolean advance, xml_node_t *node, ncx_layer_t layer, xml_msg_hdr_t *msghdr, boolean eoferr, boolean nserr, boolean clean) { int ret, nodetyp; const xmlChar *badns; xmlChar *valstr, *namestr; uint32 len; status_t res, res2; boolean done; /* init local vars */ done = FALSE; res = NO_ERR; res2 = NO_ERR; badns = NULL; /* loop past any unused xmlTextReader node types */ while (!done) { /* check if a new node should be read */ if (advance) { /* advance the node pointer */ ret = xmlTextReaderRead(scb->reader); if (ret != 1) { /* do not treat this as an internal error */ res = ERR_XML_READER_EOF; if (msghdr && eoferr) { /* generate an operation-failed error */ agt_record_error(scb, msghdr, layer, res, NULL, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } return res; } } /* get the node depth to match the end node correctly */ node->depth = xmlTextReaderDepth(scb->reader); if (node->depth == -1) { /* this never actaully happens */ SET_ERROR(ERR_XML_READER_INTERNAL); node->depth = 0; } /* get the internal nodetype, check it and convert it */ nodetyp = xmlTextReaderNodeType(scb->reader); switch (nodetyp) { case XML_ELEMENT_NODE: /* classify element as empty or start */ if (xmlTextReaderIsEmptyElement(scb->reader)) { node->nodetyp = XML_NT_EMPTY; } else { node->nodetyp = XML_NT_START; } done = TRUE; break; case XML_ELEMENT_DECL: node->nodetyp = XML_NT_END; done = TRUE; break; case XML_TEXT_NODE: /* case XML_DTD_NODE: */ node->nodetyp = XML_NT_STRING; done = TRUE; break; default: /* unused node type -- keep trying */ if (LOGDEBUG3) { log_debug3("\nxml_consume_node: skip unused node (%s)", xml_get_node_name(nodetyp)); } advance = TRUE; } } /* finish the node, depending on its type */ switch (node->nodetyp) { case XML_NT_START: case XML_NT_END: case XML_NT_EMPTY: /* get the element QName */ namestr = xml_strdup(xmlTextReaderConstName(scb->reader)); if (!namestr) { res = ERR_INTERNAL_MEM; } else { node->qname = namestr; /* check for namespace prefix in the name * only error returned is unknown-namespace */ len = 0; res = xml_check_ns(scb->reader, namestr, &node->nsid, &len, &badns); if (!nserr && res != NO_ERR) { node->nsid = xmlns_inv_id(); len = 0; res = NO_ERR; } /* set the element name to the char after the prefix, if any */ node->elname = (const xmlChar *)(namestr+len); /* get all the attributes, except for XML_NT_END */ if (res == NO_ERR && node->nodetyp != XML_NT_END) { res2 = get_all_attrs(scb, node, &node->attrs, layer, msghdr, nserr); } /* Set the node module */ if (res == NO_ERR) { if (node->nsid) { node->module = xmlns_get_module(node->nsid); } else { /* no entry, use the default module (ncx) */ node->module = NCX_DEF_MODULE; } } } break; case XML_NT_STRING: /* get the text value -- this is a malloced string */ node->simval = NULL; valstr = xmlTextReaderValue(scb->reader); if (valstr) { if (clean) { node->simfree = xml_copy_clean_string(valstr); } else { node->simfree = xml_strdup(valstr); } if (node->simfree) { node->simlen = xml_strlen(node->simfree); node->simval = (const xmlChar *)node->simfree; } /* see if this is a QName string; if so save the NSID */ xml_check_qname_content(scb->reader, node); xmlFree(valstr); } if (!node->simval) { /* prevent a NULL ptr reference */ node->simval = EMPTY_STRING; node->simlen = 0; node->simfree = NULL; } break; default: break; } if ((res != NO_ERR) && msghdr) { if (badns) { /* generate an operation-failed error */ agt_record_error(scb, msghdr, layer, res, node, NCX_NT_STRING, badns, NCX_NT_NONE, NULL); } else { agt_record_error(scb, msghdr, layer, res, node, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } } if (LOGDEBUG4) { log_debug4("\nxml_consume_node: return (%d)", (res==NO_ERR) ? res2 : res); if (scb->state != SES_ST_INIT) { xml_dump_node(node); } } /* return general error first, then attribute error * It doesn't really matter since the caller will * assume all error reports have been queued upon return */ return (res==NO_ERR) ? res2 : res; } /* consume_node */
/******************************************************************** * FUNCTION agt_top_dispatch_msg * * Find the appropriate top node handler and call it * called by the transport manager (through the session manager) * when a new message is detected * * INPUTS: * scb == session control block containing the xmlreader * set at the start of an incoming message. * * RETURNS: * none *********************************************************************/ void agt_top_dispatch_msg (ses_cb_t **ppscb) { ses_total_stats_t *myagttotals; agt_profile_t *profile; xml_node_t top; status_t res; top_handler_t handler; ses_cb_t *scb = *ppscb; #ifdef DEBUG if (!scb) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif myagttotals = ses_get_total_stats(); profile = agt_get_profile(); xml_init_node(&top); /* get the first node */ res = agt_xml_consume_node(scb, &top, NCX_LAYER_TRANSPORT, NULL); if (res != NO_ERR) { scb->stats.inBadRpcs++; myagttotals->stats.inBadRpcs++; myagttotals->droppedSessions++; if (LOGINFO) { log_info("\nagt_top: bad msg for session %d (%s)", scb->sid, get_error_string(res)); } xml_clean_node(&top); agt_ses_free_session(scb); /* set the supplied ptr to ptr to scb to NULL so that the * caller of this function knows that it was deallotcated */ *ppscb=NULL; return; } log_debug3("\nagt_top: got node"); if (LOGDEBUG4 && scb->state != SES_ST_INIT) { xml_dump_node(&top); } /* check node type and if handler exists, then call it */ if (top.nodetyp==XML_NT_START || top.nodetyp==XML_NT_EMPTY) { /* find the owner, elname tuple in the topQ */ handler = top_find_handler(top.module, top.elname); if (handler) { /* call the handler */ (*handler)(scb, &top); } else { res = ERR_NCX_DEF_NOT_FOUND; } } else { res = ERR_NCX_WRONG_NODETYP; } /* check any error trying to invoke the top handler */ if (res != NO_ERR) { scb->stats.inBadRpcs++; myagttotals->stats.inBadRpcs++; myagttotals->droppedSessions++; if (LOGINFO) { log_info("\nagt_top: bad msg for session %d (%s)", scb->sid, get_error_string(res)); } agt_ses_free_session(scb); /* set the supplied ptr to ptr to scb to NULL so that the * caller of this function knows that it was deallotcated */ *ppscb=NULL; } else if (profile->agt_stream_output && scb->state == SES_ST_SHUTDOWN_REQ) { /* session was closed */ agt_ses_kill_session(scb, scb->killedbysid, scb->termreason); /* set the supplied ptr to ptr to scb to NULL so that the * caller of this function knows that it was deallotcated */ *ppscb=NULL; } xml_clean_node(&top); } /* agt_top_dispatch_msg */
/******************************************************************** * FUNCTION agt_hello_dispatch * * Handle an incoming <hello> message from the client * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void agt_hello_dispatch (ses_cb_t *scb, xml_node_t *top) { assert( scb && "scb is NULL!" ); assert( top && "top is NULL!" ); if (LOGDEBUG2) { log_debug2("\nagt_hello: got node"); if (LOGDEBUG3) { xml_dump_node(top); } } /* only process this message in hello wait state */ if (scb->state != SES_ST_HELLO_WAIT) { log_info("\nagt_hello dropped, wrong state " "(%d) for session %d", scb->state, scb->sid); mytotals->inBadHellos++; mytotals->droppedSessions++; agt_ses_request_close(scb, scb->sid, SES_TR_BAD_HELLO); return; } /* init local vars */ status_t res = NO_ERR; obj_template_t *obj = NULL; xml_msg_hdr_t msg; xml_msg_init_hdr(&msg); /* get a value struct to hold the client hello msg */ val_value_t *val = val_new_value(); if (!val) { res = ERR_INTERNAL_MEM; } /* get the type definition from the registry */ if (res == NO_ERR) { ncx_module_t *mod = ncx_find_module(NC_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, CLIENT_HELLO_CON); } if (!obj) { /* netconf module should have loaded this definition */ res = SET_ERROR(ERR_INTERNAL_PTR); } } /* parse a manager hello message */ if (res == NO_ERR) { res = agt_val_parse_nc(scb, &msg, obj, top, NCX_DC_STATE, val); } /* check that the NETCONF base capability is included * and it matches the server protocol version */ if (res == NO_ERR) { res = check_manager_hello(scb, val); } /* report first error and close session */ if (res != NO_ERR) { if (LOGINFO) { log_info("\nagt_connect error (%s), dropping session %d", get_error_string(res), scb->sid); } mytotals->inBadHellos++; mytotals->droppedSessions++; agt_ses_request_close(scb, scb->sid, SES_TR_BAD_HELLO); } else { scb->state = SES_ST_IDLE; scb->active = TRUE; /* start the timer for the first rpc request */ (void)time(&scb->last_rpc_time); if (LOGDEBUG) { log_debug("\nSession %d for %s@%s now active", scb->sid, scb->username, scb->peeraddr); if (ses_get_protocol(scb) == NCX_PROTO_NETCONF11) { log_debug_append(" (base:1.1)"); } else { log_debug_append(" (base:1.0)"); } } } if (val) { val_free_value(val); } } /* agt_hello_dispatch */