/*! \brief Removes config contexts found at the specified scope path. \param[in] Scope String containing scope to use when overwriting. \return Returns dmz::True if config context was successfully removed. */ dmz::Boolean dmz::Config::remove_config (const String &Scope) { Boolean result = False; if (Scope) { result = True; String value, remainder; if (pop_last_config_scope_element (Scope, value, remainder)) { Config list; lookup_all_config (remainder, list); ConfigIterator it; Config cd; while (list.get_next_config (it, cd)) { ConfigContext *context (cd.get_config_context ()); if (context) { context->remove_config (value); } } } else if (_state.context) { _state.context->remove_config (Scope); } } return result; }
/*! \brief Overwrites config contexts found at the specified scope path. \param[in] Scope String containing scope to use when overwriting. \param[in] Data Config containing config context to use in the over write. \return Returns dmz::True if config context was successfully overwritten. */ dmz::Boolean dmz::Config::overwrite_config (const String &Scope, const Config &Data) { if (!Scope) { if (_state.context) { _state.context->remove_config (Data.get_name ()); } } else { Config list; lookup_all_config (Scope, list); ConfigIterator it; Config cd; while (list.get_next_config (it, cd)) { ConfigContext *context (cd.get_config_context ()); if (context) { context->remove_config (Data.get_name ()); } } } return add_config (Scope, Data); }
/*! \brief Looks up all config contexts with the given name. \details All config context found with a matching name are stored as children of \a data. \param[in] Name String containing name of config contexts to lookup. \param[out] data Config to store the found config contexts. \return Returns dmz::True if any config contexts were found. */ dmz::Boolean dmz::Config::lookup_all_config (const String &Name, Config &data) const { Boolean result (False); StringTokenizer it (Name, LocalScopeChar); String sub = it.get_next (); Boolean done (!sub ? True : False); Config prev ("prev"); prev.add_config (*this); Config current (sub); while (!done) { ConfigIterator tableIt; Config next; ConfigContext *curContext = current.get_config_context (); while (prev.get_next_config (tableIt, next)) { ConfigContext *nextContext = next.get_config_context (); if (nextContext && curContext) { ConfigContext::DataList *dl (nextContext->configTable.lookup (sub)); if (dl) { dl->lock.lock (); ConfigContext::DataStruct *ds = dl->head; while (ds) { if (ds->handle) { curContext->add_config (ds->context); } ds = ds->next; } dl->lock.unlock (); } } } if (current.is_empty ()) { done = True; } else { sub = it.get_next (); if (!sub) { data = current; done = True; result = True; } else { prev = current; Config next (sub); current = next; } } } if (data.is_empty ()) { data.set_config_context (0); result = False; } return result; }
/*! \brief Appends a string to the current config context value. \param[in] Value String containing value to be appended. \param[in] IsFormatted If set to dmz::True the config context will be marked as containing formatted data. \return Returns dmz::True if the value was appended successfully. */ dmz::Boolean dmz::Config::append_value (const String &Value, const Boolean IsFormatted) { Boolean result (False); if (_state.context) { if (!_state.context->Name) { if (IsFormatted) { _state.context->isFormatted = True; } ConfigAttributeContext *ac (_state.context->attrTable.lookup ("")); if (!ac) { ac = new ConfigAttributeContext (Value); if (ac && _state.context->attrTable.store ("", ac)) { result = True; } else if (ac) { delete ac; ac = 0; } } else { result = True; ac->lock.lock (); ac->value << Value; ac->lock.unlock (); } } else { ConfigContext *cd (new ConfigContext ("")); if (cd) { cd->isFormatted = IsFormatted; ConfigAttributeContext *ptr = new ConfigAttributeContext (Value); if (ptr && !cd->attrTable.store ("", ptr)) { delete ptr; ptr = 0; } _state.context->add_config (cd); result = True; cd->unref (); cd = 0; } } } return result; }
/*! \brief Adds a config context. \details The \a Scope parameter may be used to add a config context to child config contexts. For example the following code snippet: \code dmz::Config dataDMZ; if (global.lookup_data ("dmz", dataDMZ)) { dmz::Config dataType if (dataDMZ.lookup_data ("type", dataType)) { Config fooData ("foo"); dataType.add_config (fooData); } } \endcode May also be written as: \code Config fooData ("foo"); global.add_config ("dmz.type", fooData); \endcode \param[in] Scope String containing the scope at witch to add the config context. \param[in] Data Config containing config context to add. \return Returns dmz::True if the config context was successfully added. */ dmz::Boolean dmz::Config::add_config (const String &Scope, const Config &Data) { Boolean result (False); if (_state.context && _state.context->Name) { ConfigContext *cd = Data.get_config_context (); ConfigContext *target = local_get_config_from_scope (Scope, _state.context, True); if (cd && target) { result = target->add_config (cd); } } return result; }
FSTATIC char * _childprocess_toString(gconstpointer aself) { const ChildProcess* self = CASTTOCONSTCLASS(ChildProcess, aself); ConfigContext* cfg = configcontext_new(0); char* ret; cfg->setint(cfg, "child_pid", self->child_pid); cfg->setint(cfg, "timeout", self->timeout); cfg->setint(cfg, "timeoutsrc_id", self->timeoutsrc_id); cfg->setint(cfg, "childsrc_id", self->childsrc_id); cfg->setint(cfg, "child_state", self->child_state); cfg->setstring(cfg, "loggingname", self->loggingname); ret = cfg->baseclass.toString(&cfg->baseclass); UNREF(cfg); return ret; }
/// Send JSON that we discovered to the CMA - with some caching going on FSTATIC void _discovery_sendjson(Discovery* self, ///< Our discovery object char * jsonout, ///< malloced JSON output - which we free (!) gsize jsonlen) ///< length of jsonout { FrameSet* fs; CstringFrame* jsf; IntFrame* intf; Frame* fsf; ConfigContext* cfg = self->_config; NetGSource* io = self->_iosource; NetAddr* cma; const char * basename = self->instancename(self); ConfigContext* jsonobject; g_return_if_fail(cfg != NULL && io != NULL); if (NULL == (jsonobject = configcontext_new_JSON_string(jsonout))) { g_warning("%s.%d: JSON Discovery is not legal JSON [%s]" , __FUNCTION__, __LINE__, jsonout); return; } g_free(jsonout); jsonobject->setstring(jsonobject, CONFIGNAME_INSTANCE, basename); jsonout = jsonobject->baseclass.toString(&jsonobject->baseclass); jsonlen = strlen(jsonout); UNREF(jsonobject); DEBUGMSG2("%s.%d: discovering %s: _sentyet == %d" , __FUNCTION__, __LINE__, basename, self->_sentyet); // Primitive caching - don't send what we've already sent. if (self->_sentyet) { const char * oldvalue = cfg->getstring(cfg, basename); if (oldvalue != NULL && strcmp(jsonout, oldvalue) == 0) { DEBUGMSG2("%s.%d: %s sent this value - don't send again." , __FUNCTION__, __LINE__, basename); g_free(jsonout); return; } DEBUGMSG2("%s.%d: %s this value is different from previous value" , __FUNCTION__, __LINE__, basename); } DEBUGMSG2("%s.%d: Sending %"G_GSIZE_FORMAT" bytes of JSON text" , __FUNCTION__, __LINE__, jsonlen); cfg->setstring(cfg, basename, jsonout); cma = cfg->getaddr(cfg, CONFIGNAME_CMADISCOVER); if (cma == NULL) { DEBUGMSG2("%s.%d: %s address is unknown - skipping send" , __FUNCTION__, __LINE__, CONFIGNAME_CMADISCOVER); g_free(jsonout); return; } self->_sentyet = TRUE; fs = frameset_new(FRAMESETTYPE_JSDISCOVERY); intf = intframe_new(FRAMETYPE_WALLCLOCK, 8); intf->setint(intf, self->starttime); frameset_append_frame(fs, &intf->baseclass); UNREF2(intf); jsf = cstringframe_new(FRAMETYPE_JSDISCOVER, 0); fsf = &jsf->baseclass; // base class object of jsf fsf->setvalue(fsf, jsonout, jsonlen+1, frame_default_valuefinalize); // jsonlen is strlen(jsonout) frameset_append_frame(fs, fsf); DEBUGMSG2("%s.%d: Sending a %"G_GSIZE_FORMAT" bytes JSON frameset" , __FUNCTION__, __LINE__, jsonlen); io->_netio->sendareliablefs(io->_netio, cma, DEFAULT_FSP_QID, fs); ++ self->reportcount; UNREF(fsf); UNREF(fs); }
/** * Test program looping and reading LLDP/CDP packets and exercising most of the packet * send/receive mechanism and a good bit of nanoprobe and CMA basic infrastructure. * * It plays both sides of the game - the CMA and the nanoprobe. * * It leaves most of the work of starting up the nanoprobe code to nano_start_full() */ int main(int argc, char **argv) { const guint8 loopback[] = CONST_IPV6_LOOPBACK; //const guint8 mcastaddrstring[] = CONST_ASSIM_DEFAULT_V4_MCAST; //NetAddr* mcastaddr; const guint8 otheradstring[] = {127,0,0,1}; const guint8 otheradstring2[] = {10,10,10,4}; const guint8 anyadstring[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; guint16 testport = TESTPORT; SignFrame* signature = signframe_glib_new(G_CHECKSUM_SHA256, 0); Listener* otherlistener; ConfigContext* config = configcontext_new(0); PacketDecoder* decoder = nano_packet_decoder(); AuthListener* listentonanoprobes; ReliableUDP* rtransport; #if 0 # ifdef HAVE_MCHECK_PEDANTIC g_assert(mcheck_pedantic(NULL) == 0); # else # ifdef HAVE_MCHECK g_assert(mcheck(NULL) == 0); # endif # endif #endif g_setenv("G_MESSAGES_DEBUG", "all", TRUE); #if 0 proj_class_incr_debug(NULL); proj_class_incr_debug(NULL); proj_class_incr_debug(NULL); proj_class_incr_debug(NULL); #endif g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR); if (argc > 1) { maxpkts = atol(argv[1]); g_debug("Max packet count is "FMT_64BIT"d", maxpkts); } if (netio_is_dual_ipv4v6_stack()) { g_message("Our OS supports dual ipv4/v6 sockets. Hurray!"); }else{ g_warning("Our OS DOES NOT support dual ipv4/v6 sockets - this may not work!!"); } config->setframe(config, CONFIGNAME_OUTSIG, &signature->baseclass); // Create a network transport object for normal UDP packets rtransport = reliableudp_new(0, config, decoder, 0); rtransport->_protocol->window_size = 8; nettransport = &(rtransport->baseclass.baseclass); g_return_val_if_fail(NULL != nettransport, 2); // Set up the parameters the 'CMA' is going to send to our 'nanoprobe' // in response to their request for configuration data. nanoconfig = configcontext_new(0); nanoconfig->setint(nanoconfig, CONFIGNAME_INTERVAL, 1); nanoconfig->setint(nanoconfig, CONFIGNAME_TIMEOUT, 3); nanoconfig->setint(nanoconfig, CONFIGNAME_CMAPORT, testport); // Construct the NetAddr we'll talk to (i.e., ourselves) and listen from destaddr = netaddr_ipv6_new(loopback, testport); g_return_val_if_fail(NULL != destaddr, 3); config->setaddr(config, CONFIGNAME_CMAINIT, destaddr); nanoconfig->setaddr(nanoconfig, CONFIGNAME_CMAADDR, destaddr); nanoconfig->setaddr(nanoconfig, CONFIGNAME_CMAFAIL, destaddr); nanoconfig->setaddr(nanoconfig, CONFIGNAME_CMADISCOVER, destaddr); // Construct another couple of NetAddrs to talk to and listen from // for good measure... otheraddr = netaddr_ipv4_new(otheradstring, testport); g_return_val_if_fail(NULL != otheraddr, 4); otheraddr2 = netaddr_ipv4_new(otheradstring2, testport); g_return_val_if_fail(NULL != otheraddr2, 4); // Construct another NetAddr to bind to (anything) anyaddr = netaddr_ipv6_new(anyadstring, testport); g_return_val_if_fail(NULL != destaddr, 5); // Bind to ANY address (as noted above) g_return_val_if_fail(nettransport->bindaddr(nettransport, anyaddr, FALSE),16); //g_return_val_if_fail(nettransport->bindaddr(nettransport, destaddr),16); g_message("NOT Joining multicast address."); #if 0 // We can't do this because of encryption and we will likely screw up // others on our network even if that weren't a problem... mcastaddr = netaddr_ipv4_new(mcastaddrstring, testport); g_return_val_if_fail(nettransport->mcastjoin(nettransport, mcastaddr, NULL), 17); UNREF(mcastaddr); g_message("multicast join succeeded."); #endif // Connect up our network transport into the g_main_loop paradigm // so we get dispatched when packets arrive netpkt = netgsource_new(nettransport, NULL, G_PRIORITY_HIGH, FALSE, NULL, 0, NULL); // Set up so that we can observe all unclaimed packets otherlistener = listener_new(config, 0); otherlistener->got_frameset = gotnetpkt; netpkt->addListener(netpkt, 0, otherlistener); otherlistener->associate(otherlistener,netpkt); // Unref the "other" listener - we hold other references to it UNREF(otherlistener); // Pretend to be the CMA... // Listen for packets from our nanoprobes - scattered throughout space... listentonanoprobes = authlistener_new(0, cmalist, config, TRUE, NULL); listentonanoprobes->baseclass.associate(&listentonanoprobes->baseclass, netpkt); nano_start_full("netconfig", 900, netpkt, config, test_cma_authentication); g_timeout_add_seconds(1, timeout_agent, NULL); mainloop = g_main_loop_new(g_main_context_default(), TRUE); /******************************************************************** * Start up the main loop - run our test program... * (the one pretending to be both the nanoprobe and the CMA) ********************************************************************/ g_main_loop_run(mainloop); /******************************************************************** * We exited the main loop. Shut things down. ********************************************************************/ nano_shutdown(TRUE); // Tell it to shutdown and print stats g_message("Count of 'other' pkts received:\t%d", wirepktcount); UNREF(nettransport); // Main loop is over - shut everything down, free everything... g_main_loop_unref(mainloop); mainloop=NULL; // Unlink misc dispatcher - this should NOT be necessary... netpkt->addListener(netpkt, 0, NULL); // Dissociate packet actions from the packet source. listentonanoprobes->baseclass.dissociate(&listentonanoprobes->baseclass); // Unref the AuthListener object UNREF2(listentonanoprobes); g_source_destroy(&netpkt->baseclass); g_source_unref(&netpkt->baseclass); //g_main_context_unref(g_main_context_default()); // Free signature frame UNREF2(signature); // Free misc addresses UNREF(destaddr); UNREF(otheraddr); UNREF(otheraddr2); UNREF(anyaddr); // Free config object UNREF(config); UNREF(nanoconfig); // At this point - nothing should show up - we should have freed everything if (proj_class_live_object_count() > 0) { g_warning("Too many objects (%d) alive at end of test.", proj_class_live_object_count()); proj_class_dump_live_objects(); ++errcount; }else{ g_message("No objects left alive. Awesome!"); } proj_class_finalize_sys(); // Shut down object system to make valgrind happy :-D return(errcount <= 127 ? errcount : 127); }
~State () { if (context) { context->unref (); context = 0; } }
State (ConfigContext *theContext) : context (theContext) { if (context) { context->ref (); } }