X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=example%2Fdiameter%2Flauncher%2FLauncher.cpp;h=4219399813e82a6fe06745cf1463b0bdabc9de64;hb=ec48516a195faabbb514298ad743520b3fdb7ee4;hp=a6c5bee3123363e4225f713d425e476981c50cf5;hpb=2921c651c9945cefec0715167201596aaa079e8d;p=anna.git diff --git a/example/diameter/launcher/Launcher.cpp b/example/diameter/launcher/Launcher.cpp index a6c5bee..4219399 100644 --- a/example/diameter/launcher/Launcher.cpp +++ b/example/diameter/launcher/Launcher.cpp @@ -15,7 +15,9 @@ // Project #include #include +#include #include +#include #include #include #include @@ -35,7 +37,6 @@ #define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.out" - const char *ServicesDTD = "\ \n\ \n\ @@ -43,66 +44,72 @@ const char *ServicesDTD = "\ \n\ \n\ \n\ -\n\ +\n\ \n\ \n\ \n\ -\n\ +\n\ \n\ \n\ @@ -110,8 +117,6 @@ const char *ServicesDTD = "\ Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "1.1"), a_communicator(NULL) { - a_codecEngine = new anna::diameter::codec::Engine("MyCodecEngine"); - a_baseProtocolDictionary = NULL; a_timeEngine = NULL; a_counterRecorder = NULL; a_admlMinResolution = 2 * anna::timex::Engine::minResolution; // 2*10 = 20 ms; 1000/20 = 50 ticks per second; @@ -128,20 +133,29 @@ Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", " void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOperation) throw(anna::RuntimeException) { - // - const anna::xml::Attribute *id, *dictionary; - // - const anna::xml::Attribute *originRealm, *originHost, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay, - *answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions, - *diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection, - *retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog; + CommandLine& cl(anna::CommandLine::instantiate()); + bool allLogsDisabled = cl.exists("disableLogs"); + + // + const anna::xml::Attribute *id, *dictionary; + // + const anna::xml::Attribute *originRealm, *appId, *originHost, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay, + *answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions, + *diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection, + *retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog; // Never clear services content from here (append new data from xml). At the moment no node removing is implemented in this process // Stacks anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate(); anna::diameter::stack::Dictionary *d; + const anna::diameter::stack::Dictionary *bpd = NULL; // base protocol dictionary + + // Codec engine manager: + anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate(); + anna::diameter::codec::Engine *ce; + /////////////////////////////////////////// // APPLICATION MESSAGE OAM MODULE SCOPES // /////////////////////////////////////////// @@ -149,8 +163,8 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp anna::diameter::comm::ApplicationMessageOamModule & appMsgOamModule = anna::diameter::comm::ApplicationMessageOamModule::instantiate(); appMsgOamModule.enableCounters(); // this special module is disabled by default (the only) static int scope_id = 3; - bool id_0_registered = false; unsigned int id_value; + std::string codecEngineName; for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) { std::string nodeName = (*it)->getName(); @@ -161,9 +175,14 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp dictionary = (*it)->getAttribute("dictionary"); id_value = id->getIntegerValue(); + if (stackEngine.getDictionary(id_value)) { // Ignore (but don't fail) dictionary load with same stack id already registered + LOGWARNING(anna::Logger::warning(anna::functions::asString("Ignore dictionary load for stack id already registered: %llu", id_value), ANNA_FILE_LOCATION)); + continue; + } + try { d = stackEngine.createDictionary(id_value, dictionary->getValue()); - getCodecEngine()->setDictionary(d); + LOGDEBUG(anna::Logger::debug(anna::functions::asString("Created dictionary (%p) for stack id %llu", d, id_value), ANNA_FILE_LOCATION)); // OAM module for counters: appMsgOamModule.createStackCounterScope(scope_id, id_value /* application-id */); @@ -174,9 +193,44 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp throw ex; } - if (id_value == 0) - id_0_registered = true; - a_baseProtocolDictionary = d; + bpd = d; // base protocol dictionary in case of monostack. If multistack, will be calculated later + + // Create codec engine and register it in the codec engine manager: + codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", id_value); + ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d); + em.registerCodecEngine(id_value, ce); + + // Codec engine configuration: + const anna::xml::Attribute *vm_attr = (*it)->getAttribute("validationMode", false /* no exception */); + const anna::xml::Attribute *vd_attr = (*it)->getAttribute("validationDepth", false /* no exception */); + const anna::xml::Attribute *fm_attr = (*it)->getAttribute("fixMode", false /* no exception */); + const anna::xml::Attribute *if_attr = (*it)->getAttribute("ignoreFlags", false /* no exception */); + + std::string vm_value = vm_attr ? vm_attr->getValue() : "AfterDecoding"; + std::string vd_value = vd_attr ? vd_attr->getValue() : "FirstError"; + std::string fm_value = fm_attr ? fm_attr->getValue() : "BeforeEncoding"; + + anna::diameter::codec::Engine::ValidationMode::_v vm; + if (vm_value == "BeforeEncoding") vm = anna::diameter::codec::Engine::ValidationMode::BeforeEncoding; + else if (vm_value == "AfterDecoding") vm = anna::diameter::codec::Engine::ValidationMode::AfterDecoding; + else if (vm_value == "Always") vm = anna::diameter::codec::Engine::ValidationMode::Always; + else if (vm_value == "Never") vm = anna::diameter::codec::Engine::ValidationMode::Never; + ce->setValidationMode(vm); + + anna::diameter::codec::Engine::ValidationDepth::_v vd; + if (vd_value == "Complete") vd = anna::diameter::codec::Engine::ValidationDepth::Complete; + else if (vd_value == "FirstError") vd = anna::diameter::codec::Engine::ValidationDepth::FirstError; + ce->setValidationDepth(vd); + + anna::diameter::codec::Engine::FixMode::_v fm; + if (fm_value == "BeforeEncoding") fm = anna::diameter::codec::Engine::FixMode::BeforeEncoding; + else if (fm_value == "AfterDecoding") fm = anna::diameter::codec::Engine::FixMode::AfterDecoding; + else if (fm_value == "Always") fm = anna::diameter::codec::Engine::FixMode::Always; + else if (fm_value == "Never") fm = anna::diameter::codec::Engine::FixMode::Never; + ce->setFixMode(fm); + + bool if_value = (if_attr ? (if_attr->getValue() == "yes") : false); + ce->ignoreFlagsOnValidation(if_value); } } @@ -184,26 +238,22 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp std::cout << "Stacks currently loaded:" << std::endl; std::cout << anna::functions::tab(stackEngine.asString(false /* light */)) << std::endl; - - // Codec engine adjustments: - // Auto stack selection based on Application-ID: + // Basic checking for multistack: bool multistack = (stackEngine.stack_size() > 1); if (multistack) { - getCodecEngine()->selectStackWithApplicationId(true); - // In multistack, id = 0 MUST be registered: - if (!id_0_registered) + bpd = stackEngine.getDictionary(0); + if(!bpd) throw anna::RuntimeException("In multistack applications is mandatory register a stack id = 0 using a dictionary which contains the needed elements to build base protocol messages (CER/A, DWR/A, DPR/A, STR/A, etc.)", ANNA_FILE_LOCATION); } - else { - a_baseProtocolDictionary = d; - } + // REALMS: for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) { std::string nodeName = (*it)->getName(); if(nodeName == "node") { // Input data: originRealm = (*it)->getAttribute("originRealm"); + appId = (*it)->getAttribute("applicationId"); originHost = (*it)->getAttribute("originHost", false /* no exception */); cer = (*it)->getAttribute("cer", false /* no exception */); dwr = (*it)->getAttribute("dwr", false /* no exception */); @@ -232,6 +282,12 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } + unsigned int applicationId = appId->getIntegerValue(); + if (!stackEngine.getDictionary(applicationId)) { + std::string msg = "Cannot found a registered stack id with the value of applicationId provided: "; msg += appId->getValue(); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + // Engine time measures checking & assignment: anna::Millisecond allowedInactivityTimeMs(90000); anna::Millisecond tcpConnectDelayMs(200); @@ -260,7 +316,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp } // Create new Node instance ///////////////////////////////////////////////////////////////// - a_workingNode = new RealmNode(originRealm->getValue(), a_codecEngine, a_baseProtocolDictionary); + a_workingNode = new RealmNode(originRealm->getValue(), applicationId, bpd); MyDiameterEngine *commEngine = a_workingNode->getMyDiameterEngine(); ///////////////////////////////////////////////////////////////////////////////////////////// @@ -301,24 +357,29 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp } // Logs: - std::string realm = commEngine->getRealm(); - std::string s_log = realm + ".launcher.log"; if (log) s_log = log->getValue(); - bool b_splitLog = (splitLog ? (splitLog->getValue() == "yes") : false); - bool b_detailedLog = (detailedLog ? (detailedLog->getValue() == "yes") : false); - bool b_dumpLog = (dumpLog ? (dumpLog->getValue() == "yes") : false); - std::string s_burstLog = realm + ".launcher.burst"; if (burstLog) s_burstLog = burstLog->getValue(); - a_workingNode->setLogs(s_log, b_splitLog, b_detailedLog, b_dumpLog, s_burstLog); + if (!allLogsDisabled) { + std::string realm = commEngine->getRealm(); + std::string s_log = realm + ".launcher.log"; if (log) s_log = log->getValue(); + bool b_splitLog = (splitLog ? (splitLog->getValue() == "yes") : false); + bool b_detailedLog = (detailedLog ? (detailedLog->getValue() == "yes") : false); + bool b_dumpLog = (dumpLog ? (dumpLog->getValue() == "yes") : false); + std::string s_burstLog = realm + ".launcher.burst"; if (burstLog) s_burstLog = burstLog->getValue(); + a_workingNode->setLogs(s_log, b_splitLog, b_detailedLog, b_dumpLog, s_burstLog); + } // Lazy initialization for comm engine: if (eventOperation) commEngine->lazyInitialize(); - // New Node assignment ////////////////////////////////////////////////////////////////////// + // Node and Codec Engine registration /////////////////////////////////////////////////////// a_nodes[originRealm->getValue()] = a_workingNode; ///////////////////////////////////////////////////////////////////////////////////////////// } } + if (!uniqueRealm()) + a_workingNode = NULL; // by default, mode auto + // Diameter comm engines which are loaded after application start (via management operation 'services') are not really started, // but this don't care because application startComponents() -> initialize() -> do_initialize() -> do nothing. // And when stopped, running state is not checked and it will be stopped anyway. @@ -333,10 +394,10 @@ void Launcher::loadServices(const std::string & xmlPathFile, bool eventOperation } LOGDEBUG( - std::string trace = "Loading ADML services file '"; - trace += xmlPathFile; - trace += "'"; - anna::Logger::debug(trace, ANNA_FILE_LOCATION); + std::string trace = "Loading ADML services file '"; + trace += xmlPathFile; + trace += "'"; + anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) anna::xml::DTDMemory xmlDTD; @@ -348,19 +409,19 @@ void Launcher::loadServices(const std::string & xmlPathFile, bool eventOperation } catch (anna::RuntimeException &ex) { LOGWARNING( - std::string msg = "Services DTD schema:\n\n"; - msg += ServicesDTD; - anna::Logger::warning(msg, ANNA_FILE_LOCATION); + std::string msg = "Services DTD schema:\n\n"; + msg += ServicesDTD; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); ); throw ex; } LOGDEBUG( - std::string trace = "Loaded XML file ("; - trace += xmlPathFile; - trace += "):\n"; - trace += anna::xml::Compiler().apply(rootNode); - anna::Logger::debug(trace, ANNA_FILE_LOCATION); + std::string trace = "Loaded XML file ("; + trace += xmlPathFile; + trace += "):\n"; + trace += anna::xml::Compiler().apply(rootNode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); servicesFromXML(rootNode, eventOperation); } @@ -407,37 +468,63 @@ anna::Millisecond Launcher::checkTimeMeasure(const std::string ¶meter, const throw RuntimeException(msg, ANNA_FILE_LOCATION); } -RealmNode *Launcher::getWorkingNode() const throw(anna::RuntimeException) { - - if (!a_workingNode) - throw RuntimeException("No services yet loaded. Try 'services' operation (via management interface), or restart process using command-line 'services' parameter", ANNA_FILE_LOCATION); - - return a_workingNode; -} - bool Launcher::setWorkingNode(const std::string &name) throw() { bool result = false; - realm_nodes_nc_it nodeIt = a_nodes.find(name); + realm_nodes_it nodeIt = a_nodes.find(name); if (nodeIt == a_nodes.end()) { LOGWARNING( - std::string msg = "Unknown node with name '"; msg += name; msg += "'. Ignoring ..."; - anna::Logger::warning(msg, ANNA_FILE_LOCATION); + std::string msg = "Unknown node with name '"; msg += name; msg += "'. Ignoring ..."; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); ); } else { - a_workingNode = nodeIt->second; + a_workingNode = const_cast(nodeIt->second); result = true; } return result; } -RealmNode *Launcher::getRealmNode(const std::string &realmName) const throw() { +RealmNode *Launcher::getRealmNode(const std::string &realmName) const throw(anna::RuntimeException) { realm_nodes_it it = a_nodes.find(realmName); if (it != a_nodes.end()) return it->second; + throw anna::RuntimeException(anna::functions::asString("There is no realm node registered as '%s' (set Origin-Realm avp correctly or force a specific realm with 'node' operation)", realmName.c_str()), ANNA_FILE_LOCATION); +} + +RealmNode *Launcher::getRealmNode(const anna::diameter::codec::Message &message) const throw(anna::RuntimeException) { + std::string originRealm = message.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue(); + return (getRealmNode(originRealm)); +} + +void Launcher::updateOperatedRealmNodeWithMessage(const anna::diameter::codec::Message &message) throw(anna::RuntimeException) { + if (!a_operatedRealm) // priority for working node by mean 'node' operation + a_operatedRealm = getRealmNode(message); +} + +RealmNode *Launcher::getOperatedRealm() const throw(anna::RuntimeException) { + if(!a_operatedRealm) + throw anna::RuntimeException("Realm Node not identified (try to force a specific realm with 'node' operation)", ANNA_FILE_LOCATION); + + return a_operatedRealm; +} - return NULL; // this never happens +MyDiameterEntity *Launcher::getOperatedEntity() const throw(anna::RuntimeException) { + MyDiameterEntity *result = getOperatedRealm()->getEntity(); + if (!result) + throw anna::RuntimeException("No entity configured for the operated Realm Node", ANNA_FILE_LOCATION); + return result; +} + +MyLocalServer *Launcher::getOperatedServer() const throw(anna::RuntimeException) { + MyLocalServer *result = getOperatedRealm()->getDiameterServer(); + if (!result) + throw anna::RuntimeException("No local server configured for the operated Realm Node", ANNA_FILE_LOCATION); + return result; +} + +MyDiameterEngine *Launcher::getOperatedEngine() const throw(anna::RuntimeException) { + return getOperatedRealm()->getMyDiameterEngine(); // never will be NULL } void Launcher::initialize() @@ -484,12 +571,12 @@ throw(anna::RuntimeException) { anna::statistics::Engine::instantiate().enable(); LOGINFORMATION( - // Help on startup traces: - anna::Logger::information(help(), ANNA_FILE_LOCATION); - // Test messages dtd: - std::string msg = "\n ------------- TESTMESSAGES DTD -------------\n"; - msg += anna::diameter::codec::MessageDTD; - anna::Logger::information(msg, ANNA_FILE_LOCATION); + // Help on startup traces: + anna::Logger::information(help(), ANNA_FILE_LOCATION); + // Test messages dtd: + std::string msg = "\n ------------- TESTMESSAGES DTD -------------\n"; + msg += anna::diameter::codec::MessageDTD; + anna::Logger::information(msg, ANNA_FILE_LOCATION); ); // HTTP Server: @@ -626,29 +713,6 @@ throw(anna::RuntimeException) { a_timeEngine->activate(a_counterRecorderClock); // start clock } - - // Integration (validation 'Complete' for receiving messages) and debugging (validation also before encoding: 'Always'). - // If missing 'integrationAndDebugging', default behaviour at engine is: mode 'AfterDecoding', depth 'FirstError': - if(cl.exists("integrationAndDebugging")) { - getCodecEngine()->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); - getCodecEngine()->setValidationDepth(anna::diameter::codec::Engine::ValidationDepth::Complete); - } - - // Fix mode - if(cl.exists("fixMode")) { // BeforeEncoding(default), AfterDecoding, Always, Never - std::string fixMode = cl.getValue("fixMode"); - anna::diameter::codec::Engine::FixMode::_v fm; - if (fixMode == "BeforeEncoding") fm = anna::diameter::codec::Engine::FixMode::BeforeEncoding; - else if (fixMode == "AfterDecoding") fm = anna::diameter::codec::Engine::FixMode::AfterDecoding; - else if (fixMode == "Always") fm = anna::diameter::codec::Engine::FixMode::Always; - else if (fixMode == "Never") fm = anna::diameter::codec::Engine::FixMode::Never; - else LOGINFORMATION(anna::Logger::information("Unreconized command-line fix mode. Assumed default 'BeforeEncoding'", ANNA_FILE_LOCATION)); - getCodecEngine()->setFixMode(fm); - } - - getCodecEngine()->ignoreFlagsOnValidation(cl.exists("ignoreFlags")); - - // Log statistics concepts if(cl.exists("logStatisticSamples")) { std::string list = cl.getValue("logStatisticSamples"); @@ -707,9 +771,9 @@ bool Launcher::getDataBlockFromHexFile(const std::string &pathfile, anna::DataBl // Allow colon separator in hex string: we have to remove them before processing with 'fromHexString': hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end()); LOGDEBUG( - std::string msg = "Hex string (remove colons if exists): "; - msg += hexString; - anna::Logger::debug(msg, ANNA_FILE_LOCATION); + std::string msg = "Hex string (remove colons if exists): "; + msg += hexString; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); anna::functions::fromHexString(hexString, db); // Close file @@ -721,7 +785,14 @@ bool Launcher::getDataBlockFromHexFile(const std::string &pathfile, anna::DataBl } void Launcher::resetStatistics() throw() { - getWorkingNode()->getMyDiameterEngine()->resetStatistics(); + if (a_workingNode) { + a_workingNode->getMyDiameterEngine()->resetStatistics(); + } + else { + for (realm_nodes_it it = a_nodes.begin(); it != a_nodes.end(); it++) { + it->second->getMyDiameterEngine()->resetStatistics(); + } + } } void Launcher::resetCounters() throw() { @@ -732,12 +803,12 @@ void Launcher::resetCounters() throw() { void Launcher::signalUSR2() throw(anna::RuntimeException) { LOGNOTICE( - std::string msg = "Captured signal SIGUSR2. Reading tasks at '"; - msg += SIGUSR2_TASKS_INPUT_FILENAME; - msg += "' (results will be written at '"; - msg += SIGUSR2_TASKS_OUTPUT_FILENAME; - msg += "')"; - anna::Logger::notice(msg, ANNA_FILE_LOCATION); + std::string msg = "Captured signal SIGUSR2. Reading tasks at '"; + msg += SIGUSR2_TASKS_INPUT_FILENAME; + msg += "' (results will be written at '"; + msg += SIGUSR2_TASKS_OUTPUT_FILENAME; + msg += "')"; + anna::Logger::notice(msg, ANNA_FILE_LOCATION); ); // Operation: @@ -747,14 +818,13 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) { std::ofstream out_file(SIGUSR2_TASKS_OUTPUT_FILENAME); if(!in_file.is_open()) throw RuntimeException("Unable to read tasks", ANNA_FILE_LOCATION); - if(!out_file.is_open()) throw RuntimeException("Unable to write tasks", ANNA_FILE_LOCATION); while(getline(in_file, line)) { LOGDEBUG( - std::string msg = "Processing line: "; - msg += line; - anna::Logger::debug(msg, ANNA_FILE_LOCATION); + std::string msg = "Processing line: "; + msg += line; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); try { @@ -767,6 +837,7 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) { } in_file.close(); + out_file << "EOF\n"; out_file.close(); } @@ -827,7 +898,7 @@ std::string Launcher::help() const throw() { result += "\n "; result += "\n"; result += "\n "; - result += "\n "; + result += "\n "; result += "\n"; result += "\n"; result += "\nServer configuration:"; @@ -837,7 +908,7 @@ std::string Launcher::help() const throw() { result += "\n "; result += "\n"; result += "\n "; - result += "\n "; + result += "\n "; result += "\n"; result += "\n"; result += "\nIf you act as a proxy or a translation agent, you need to combine both former setups, and probably"; @@ -854,8 +925,8 @@ std::string Launcher::help() const throw() { result += "\n "; result += "\n"; result += "\n "; - result += "\n "; - result += "\n "; + result += "\n "; + result += "\n "; result += "\n"; result += "\n"; result += "\n"; @@ -875,11 +946,24 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\nhelp This help."; result += "\n"; - result += "\n---------------------------------------------------------------------------------------- Node selection"; - result += "\n"; - result += "\nnode[|] Select current working node by mean the registered name."; - result += "\n All the subsequent operations will be referred to this node."; - result += "\n Without argument, the current node information is retrieved."; + result += "\n--------------------------------------------------------------------------------------- Node management"; + result += "\n"; + result += "\nnode[|] Selects a context working node by mean a registered name."; + result += "\n All the subsequent operations will be forced to work with"; + result += "\n this node, which makes possible some rare scenarios like"; + result += "\n sending unexpected messages on remote peers. This is also"; + result += "\n useful for some operations in order to restrict the scope"; + result += "\n of action (statistics, communication visibility, etc.)."; + result += "\n Empty parameter will show the current configuration."; + result += "\n"; + result += "\nnode_auto Returns to the default behaviour (smart node selection)."; + result += "\n Depending on the operation, this could imply a global"; + result += "\n action scope, affecting to all the registered realms."; + result += "\n This should be the normal configuration. Take into"; + result += "\n account that if you fix the working node, this could"; + result += "\n affect to things like test programming: communication"; + result += "\n resources will override those which would be inferred"; + result += "\n from programmed messages Origin-Realm avps."; result += "\n"; result += "\n------------------------------------------------------------------------------------ Parsing operations"; result += "\n"; @@ -890,12 +974,14 @@ std::string Launcher::help() const throw() { result += "\n------------------------------------------------------------------------------------------- Hot changes"; result += "\n"; result += "\nservices[|source file] Adds and starts the services specified in the xml file provided."; - result += "\n (if missing, the file 'services.xml' will be used)."; - result += "\n The last loaded realm node will be automatically the new current"; - result += "\n working node. This is used to load new nodes once the ADML is"; - result += "\n started, regardless if '--services' command line parameter was"; - result += "\n used or not. Those services which are not correctly loaded, will"; - result += "\n be ignored, keeping the process alive."; + result += "\n (if missing, the file 'services.xml' will be used). This is used"; + result += "\n to load new nodes once the ADML is started, regardless if command"; + result += "\n line '--services' parameter was used or not. Those services which"; + result += "\n are not correctly loaded will be ignored to keep the process alive."; + result += "\n If you need to load services as deltas, you must firstly load the"; + result += "\n diameter base dictionary with stack id 0, because all the realms"; + result += "\n will use this dictionary to encode/decode base protocol messages"; + result += "\n managed by the communication engine."; result += "\n"; result += "\ndiameterServerSessions| Updates the maximum number of accepted connections to diameter"; result += "\n server socket."; @@ -904,9 +990,15 @@ std::string Launcher::help() const throw() { result += "\n default '/var/tmp/anna.context.' will be used."; result += "\ncollect Reset statistics and counters to start a new test stage of"; result += "\n performance measurement. Context data can be written at"; - result += "\n '/var/tmp/anna.context.' by mean 'kill -10 '"; + result += "\n '/var/tmp/anna.context.' by mean 'kill -10 '."; result += "\n or sending operation 'context|[target file]'."; + result += "\n This operation applies over all the registered realm nodes"; + result += "\n except if one specific working node has been set."; result += "\nforceCountersRecord Forces dump to file the current counters of the process."; + result += "\nshow-oam Dumps current counters of the process. This is also done at"; + result += "\n process context dump."; + result += "\nshow-stats Dumps statistics of the process. This is also done at process"; + result += "\n context dump."; result += "\n"; result += "\n[|
:][|socket id]"; result += "\n"; @@ -924,20 +1016,18 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\nsendxml2e| Sends xml source file (pathfile) through configured entity."; result += "\nsendxml2c| Sends xml source file (pathfile) to client."; - result += "\nsendxml| Same as 'sendxml2e'."; result += "\nanswerxml2e[|source_file] Answer xml source file (pathfile) for incoming request with same code from entity."; result += "\n The answer is stored in a FIFO queue for a specific message code, then there are"; result += "\n as many queues as different message codes have been programmed."; result += "\nanswerxml2c[|source_file] Answer xml source file (pathfile) for incoming request with same code from client."; result += "\n The answer is stored in a FIFO queue for a specific message code, then there are"; result += "\n as many queues as different message codes have been programmed."; - result += "\nanswerxml[|source_file] Same as 'answerxml2c'."; - result += "\nanswerxml(2e/2c) List programmed answers (to entity/client) if no parameter provided."; - result += "\nanswerxml(2e/2c)|dump Write programmed answers (to entity/client) to file 'programmed_answer..',"; + result += "\nanswerxml<2e/2c> List programmed answers (to entity/client) if no parameter provided."; + result += "\nanswerxml<2e/2c>|dump Write programmed answers (to entity/client) to file 'programmed_answer..',"; result += "\n where 'sequence' is the order of the answer in each FIFO code-queue of programmed answers."; - result += "\nanswerxml(2e/2c)|clear Clear programmed answers (to entity/client)."; - result += "\nanswerxml(2e/2c)|exhaust Disable the corresponding queue rotation, which is the default behaviour."; - result += "\nanswerxml(2e/2c)|rotate Enable the corresponding queue rotation, useful in performance tests."; + result += "\nanswerxml<2e/2c>|clear Clear programmed answers (to entity/client)."; + result += "\nanswerxml<2e/2c>|exhaust Disable the corresponding queue rotation, which is the default behaviour."; + result += "\nanswerxml<2e/2c>|rotate Enable the corresponding queue rotation, useful in performance tests."; result += "\n Rotation consists in add again to the queue, each element retrieved for answering."; result += "\n"; result += "\nSend operations are available using hexadecimal content (hex formatted files) which also allow to test"; @@ -945,13 +1035,12 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\nsendhex2e| Sends hex source file (pathfile) through configured entity."; result += "\nsendhex2c| Sends hex source file (pathfile) to client."; - result += "\nsendhex| Same as 'sendhex2e'."; result += "\n"; result += "\nAnswer programming in hexadecimal is not really neccessary (you could use send primitives) and also"; result += "\n is intended to be used with decoded messages in order to replace things like hop by hop, end to end,"; result += "\n subscriber id, session id, etc. Anyway you could use 'decode' operation and then program the xml created."; result += "\n"; - result += "\nIf a request is received, answer map (built with 'answerxml<[2c] or 2e>' operations) will be"; + result += "\nIf a request is received, answer map (built with 'answerxml<2e/2c>' operations) will be"; result += "\n checked to find a corresponding programmed answer to be replied(*). If no ocurrence is found,"; result += "\n or answer message was received, the message is forwarded to the other side (entity or client),"; result += "\n or nothing but trace when no peer at that side is configured. Answer to client have sense when"; @@ -964,7 +1053,7 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n(*) sequence values (hop-by-hop and end-to-end), Session-Id and Subscription-Id avps, are mirrored"; result += "\n to the peer which sent the request. If user wants to test a specific answer without changing it,"; - result += "\n use sendxml/sendhex operations better than programming."; + result += "\n use sendxml<2e/2c>/sendhex<2e/2c> operations better than programming."; result += "\n"; result += "\nBalance ('--balance' command line parameter) could be used to forward server socket receptions through"; result += "\n entity servers by mean a round-robin algorithm. Both diameter server socket and entity targets should"; @@ -992,6 +1081,12 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n------------------------------------------------------------------------------------------- Burst tests"; result += "\n"; + result += "\nIn order to simplify user experience, burst category operations are only allowed in single realm node"; + result += "\n configuration. Indeed, you could send messages with incorrect Origin-Realm, and no warning is shown."; + result += "\nAll the operations are performed through the unique realm: if you need to use more interfaces, you may"; + result += "\n launch different ADML instances. Is nonsense to allow burst in a multi-realm configured ADML, because"; + result += "\n this feature is not able to coordinate the messages."; + result += "\n"; result += "\nburst|[|parameter] Used for performance testing, we first program diameter requests"; result += "\n messages in order to launch them from client side to the configured"; result += "\n diameter entity. We could start the burst with an initial load"; @@ -1030,7 +1125,9 @@ std::string Launcher::help() const throw() { result += "\n Adds a new step to the test case with provided identifier. If provided identifier"; result += "\n is not registered yet, a new test case will be created with that value and the"; result += "\n step will be added as the first. For a specific 'id', the steps are stored in"; - result += "\n order as they are programmed"; + result += "\n order as they are programmed. Check possible runtime exceptions when adding a"; + result += "\n new step because those which fail, will be ignored/skipped during test case"; + result += "\n programming giving an incomplete sequence invalid for the testing purpose."; result += "\n"; result += "\n : integer number, normally monotonically increased for each test case. Some external"; result += "\n script/procedure shall clone a test case template in order to build a collection"; @@ -1067,17 +1164,35 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n delay| Blocking step until the time lapse expires. Useful to give "; result += "\n some cadence control and time schedule for a specific case."; + result += "\n A value of 0 could be used as a dummy step."; result += "\n wait| Blocking step until condition is fulfilled. The message could"; result += "\n received from entity (waitfe) or from client (waitfc)."; result += "\n"; result += "\n wait-regexp|"; - result += "\n Wait condition, from entity (waitfe-regexp) or client (waitfc-regexp)"; + result += "\n Wait condition, from entity (waitfe-regexp) or client (waitfc-regexp)"; result += "\n to match the serialized xml content for received messages. CPU cost"; result += "\n is bigger than the former ones because the whole message must be"; result += "\n decoded and converted to xml instead of doing a direct hexadecimal"; result += "\n buffer search. The main advantage is the great flexibility to identify"; result += "\n any content with a regular expression."; result += "\n"; + result += "\n sh-command|