X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=example%2Fdiameter%2Flauncher%2FLauncher.cpp;h=2ad9a59661769883ee473eab4af1ff483a691d57;hb=080dc0740d8b02011dee032f5d44eeb5f2ffe23f;hp=bb28699ec9bf76837e9048055dd8c867830ecc3c;hpb=1f560cfaaea555f037a99a6790eade56434eb119;p=anna.git diff --git a/example/diameter/launcher/Launcher.cpp b/example/diameter/launcher/Launcher.cpp index bb28699..2ad9a59 100644 --- a/example/diameter/launcher/Launcher.cpp +++ b/example/diameter/launcher/Launcher.cpp @@ -48,7 +48,7 @@ const char *ServicesDTD = "\ \n\ \n\ \n\ -\n\ +\n\ \n\ \n\ \n\ @@ -144,21 +144,22 @@ Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", " a_counterRecorderClock = NULL; a_workingNode = NULL; + a_operatedHost = NULL; a_httpServerSocket = NULL; } std::string Launcher::getSignalUSR2InputFile() const throw() { - return (a_initialWorkingDirectory + "/" + SIGUSR2_TASKS_INPUT_FILENAME); + return (getInitialWorkingDirectory() + "/" + SIGUSR2_TASKS_INPUT_FILENAME); } std::string Launcher::getSignalUSR2OutputFile() const throw() { - return (a_initialWorkingDirectory + "/" + SIGUSR2_TASKS_OUTPUT_FILENAME); + return (getInitialWorkingDirectory() + "/" + SIGUSR2_TASKS_OUTPUT_FILENAME); } -void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOperation) throw(anna::RuntimeException) { +void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool bindResources) throw(anna::RuntimeException) { CommandLine& cl(anna::CommandLine::instantiate()); bool allLogsDisabled = cl.exists("disableLogs"); @@ -203,6 +204,9 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp 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)); + // Delta loads, in case we provide base protocol already registered (comm::Engine will need 'bpd') + if (id_value == 0) + bpd = stackEngine.getDictionary(0); continue; } @@ -389,7 +393,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp a_workingNode->createEntity(entity->getValue(), ceaTimeoutMs, answersTimeoutMs); a_workingNode->getEntity()->setSessionBasedModelsType(sessionBasedModelsTypeEnum); a_workingNode->getEntity()->setBalance(balance ? (balance->getValue() == "yes") : false); // for sendings - if (eventOperation) a_workingNode->getEntity()->bind(); + if (bindResources) a_workingNode->getEntity()->bind(); } } @@ -415,7 +419,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp // Lazy initialization for comm engine: - if (eventOperation) commEngine->lazyInitialize(); + if (bindResources) commEngine->lazyInitialize(); // Node and Codec Engine registration /////////////////////////////////////////////////////// ohm.registerOriginHost(originHost->getValue(), a_workingNode); @@ -432,7 +436,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp } -void Launcher::loadServices(const std::string & xmlPathFile, bool eventOperation) throw(anna::RuntimeException) { +void Launcher::loadServicesFromFile(const std::string & xmlPathFile, bool bindResources) throw(anna::RuntimeException) { if (xmlPathFile == "null" || xmlPathFile == "") { LOGWARNING(anna::Logger::warning("Ignoring services configuration on start: empty or 'null' string provided as xml file. Use management interface (operation 'services') in order to add services", ANNA_FILE_LOCATION)); @@ -469,7 +473,35 @@ void Launcher::loadServices(const std::string & xmlPathFile, bool eventOperation trace += anna::xml::Compiler().apply(rootNode); anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); - servicesFromXML(rootNode, eventOperation); + servicesFromXML(rootNode, bindResources); +} + + +void Launcher::loadServicesFromXMLString(const std::string & xmlString, bool bindResources) throw(anna::RuntimeException) { + + anna::xml::DocumentMemory xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) + anna::xml::DTDMemory xmlDTD; + const anna::xml::Node *rootNode; + xmlDocument.initialize(xmlString.c_str()); + xmlDTD.initialize(ServicesDTD); + try { + rootNode = xmlDocument.parse(xmlDTD); // Parsing: fail here if xml violates dtd + } + catch (anna::RuntimeException &ex) { + LOGWARNING( + 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 String:\n"; + trace += anna::xml::Compiler().apply(rootNode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); + servicesFromXML(rootNode, bindResources); } @@ -543,17 +575,26 @@ anna::diameter::comm::OriginHost *Launcher::getOriginHost(const anna::diameter:: return (getOriginHost(originHost)); } +anna::diameter::comm::OriginHost *Launcher::getOriginHost(const anna::DataBlock &messageDataBlock) const throw(anna::RuntimeException) { + std::string originHost = anna::diameter::helpers::base::functions::getOriginHost(messageDataBlock); + return (getOriginHost(originHost)); +} + bool Launcher::uniqueOriginHost() const throw() { anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate(); return (ohm.size() == 1); } - void Launcher::updateOperatedOriginHostWithMessage(const anna::diameter::codec::Message &message) throw(anna::RuntimeException) { if (!a_operatedHost) // priority for working node by mean 'node' operation a_operatedHost = getOriginHost(message); } +void Launcher::updateOperatedOriginHostWithMessage(const anna::DataBlock &messageDataBlock) throw(anna::RuntimeException) { + if (!a_operatedHost) // priority for working node by mean 'node' operation + a_operatedHost = getOriginHost(messageDataBlock); +} + anna::diameter::comm::OriginHost *Launcher::getWorkingNode() const throw(anna::RuntimeException) { if(!a_workingNode) throw anna::RuntimeException("Working node not identified (try to load services)", ANNA_FILE_LOCATION); @@ -568,6 +609,10 @@ anna::diameter::comm::OriginHost *Launcher::getOperatedHost() const throw(anna:: return a_operatedHost; } +void Launcher::setOperatedHost(anna::diameter::comm::OriginHost *op) { + a_operatedHost = op; +} + MyDiameterEntity *Launcher::getOperatedEntity() const throw(anna::RuntimeException) { MyDiameterEntity *result = (MyDiameterEntity *)(getOperatedHost()->getEntity()); if (!result) @@ -622,7 +667,7 @@ throw(anna::RuntimeException) { anna::Logger::setLevel(anna::Logger::asLevel(cl.getValue("trace"))); // Load launcher services: - loadServices(cl.getValue("services")); // before run (have components to be created) + loadServicesFromFile(cl.getValue("services"), false /* no bind at the moment */); // before run (have components to be created) } void Launcher::run() @@ -833,21 +878,6 @@ bool Launcher::getDataBlockFromHexFile(const std::string &pathfile, anna::DataBl return false; } -bool Launcher::getContentFromFile(const std::string &pathfile, std::string &content) const throw(anna::RuntimeException) { - - std::ifstream inFile(pathfile.c_str(), std::ifstream::in); - if(!inFile.good()) { - throw RuntimeException(anna::functions::asString("Unable to open file '%s'", pathfile.c_str()), ANNA_FILE_LOCATION); - } - - std::stringstream strStream; - strStream << inFile.rdbuf(); //read the file - content = strStream.str(); // holds the content of the file - inFile.close(); - - return true; -} - void Launcher::resetStatistics() throw() { if (a_workingNode) { a_workingNode->getCommEngine()->resetStatistics(); @@ -956,7 +986,7 @@ void Launcher::logStatisticsSamples(const std::string &conceptsList) throw() { } -bool Launcher::eventOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) { +bool Launcher::eventOperation(const std::string &operation, std::string &response) throw(anna::RuntimeException) { bool result = true; @@ -964,10 +994,13 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if (operation == "") return result; // ignore LOGDEBUG(anna::Logger::debug(anna::functions::asString("Operation: %s", operation.c_str()), ANNA_FILE_LOCATION)); + EventOperation eop(false /* not HTTP, it is SIGUSR2 */); + // Default response: - response_content = "Operation processed with exception: "; - response_content += operation; - std::string opt_response_content = ""; // aditional response content + //response = "Operation processed with exception: "; + response = "Internal error (check ADML traces): "; + response += operation; + std::string opt_response = ""; // aditional response content anna::DataBlock db_aux(true); anna::diameter::codec::Message codecMsg; // auxiliary codec message @@ -986,11 +1019,11 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if (args == "" && op_size != 7) throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); try { - p.execute(args, response_content); + p.execute(args, response); } catch(anna::RuntimeException &ex) { ex.trace(); - response_content = ex.asString(); + response = ex.asString(); return false; } return true; // OK @@ -998,29 +1031,20 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons // Reset performance data: if(operation == "collect") { - resetCounters(); - resetStatistics(); - response_content = "All process counters & statistic information have been reset"; - return true; // OK + return eop.collect(response); } // Counters dump on demand: if(operation == "forceCountersRecord") { - forceCountersRecord(); - response_content = "Current counters have been dump to disk"; - return true; // OK + return eop.forceCountersRecord(response); } // OAM & statistics: if(operation == "show-oam") { - anna::xml::Node root("root"); - response_content = anna::xml::Compiler().apply(oamAsXML(&root)); - return true; // OK + return eop.show_oam(response); } if(operation == "show-stats") { - anna::xml::Node root("root"); - response_content = anna::xml::Compiler().apply(statsAsXML(&root)); - return true; // OK + return eop.show_stats(response); } /////////////////////////////////////////////////////////////////// @@ -1070,7 +1094,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if((opType == "log-statistics-samples") && (numParams != 1)) wrongBody = true; if((opType == "node") && (numParams > 1)) wrongBody = true; - if((opType == "node_auto") && (numParams > 0)) wrongBody = true; + if((opType == "node-auto") && (numParams > 0)) wrongBody = true; if(((opType == "code") || (opType == "decode")) && (numParams != 2)) wrongBody = true; @@ -1092,76 +1116,40 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons // Operations: if(opType == "context") { - std::string contextFile = ((numParams == 1) ? param1 : anna::functions::asString("/var/tmp/anna.context.%05d", getPid())); - writeContext(contextFile); - response_content = anna::functions::asString("Context dumped on file '%s'", contextFile.c_str()); - return true; // OK + return eop.context(response, (numParams == 1) ? param1 : ""); } if(opType == "log-statistics-samples") { - logStatisticsSamples(param1); - response_content = anna::functions::asString("Log statistics samples for '%s' concepts", param1.c_str()); - return true; // OK + return eop.log_statistics_samples(response, param1); } // Change execution directory: if(opType == "change-dir") { - if (param1 == "") param1 = a_initialWorkingDirectory; - result = (chdir(param1.c_str()) == 0); - - if (result) - response_content = "New execution directory configured: "; - else - response_content = "Cannot assign provided execution directory: "; - - response_content += param1; - return result; + return eop.change_dir(response, param1); } if(opType == "services") { std::string servicesFile = ((numParams == 1) ? param1 : "services.xml"); try { - loadServices(servicesFile, true /* bind entities */); + loadServicesFromFile(servicesFile, true /* bind entities */); } catch(anna::RuntimeException &ex) { ex.trace(); - response_content = anna::functions::asString("Loaded services from file '%s' with errors", servicesFile.c_str()); + response = anna::functions::asString("Loaded services from file '%s' with errors", servicesFile.c_str()); return false; } - response_content = anna::functions::asString("Loaded services from file '%s'", servicesFile.c_str()); + response = anna::functions::asString("Loaded services from file '%s'", servicesFile.c_str()); return true; // OK } // Host switch: if(opType == "node") { - if (param1 != "") { - if (setWorkingNode(param1)) response_content = anna::functions::asString("Forced node is now '%s'", param1.c_str()); - } - else { - if (a_workingNode) { - response_content = "Working node is forced to be: \n\n"; - response_content += a_workingNode->asXMLString(); - } - else { - response_content = "Working node is automatic"; - } - } - return true; // OK + return eop.node(response, param1); } - if(opType == "node_auto") { - a_workingNode = NULL; - response_content = "Working node has been set to automatic"; - return true; // OK + else if(opType == "node-auto") { + return eop.node_auto(response); } - // Operated host from possible forced-working node: - a_operatedHost = a_workingNode ? a_workingNode /* priority */: NULL /* auto */; - // Use later: - // If any message is managed: updateOperatedOriginHostWithMessage(codecMessage) - // To operate, use the exception-protected methods which never will return NULL: - // getOperatedHost(), getOperatedEntity(), getOperatedServer(), getOperatedEngine() - - if(opType == "code") { codecMsg.loadXMLFile(param1); std::string hexString = anna::functions::asHexString(codecMsg.code()); @@ -1183,42 +1171,8 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons outfile.write(xmlString.c_str(), xmlString.size()); outfile.close(); } else if((opType == "hide") || (opType == "show") || (opType == "hidden") || (opType == "shown")) { + result = eop.visibility(opt_response, opType, param1, (param2 != "") ? atoi(param2.c_str()) : -1); - if(param1 != "") { - if(param2 != "") { - std::string key = param1; - key += "|"; - key += param2; - - if(opType == "hide") getOperatedEngine()->findClientSession(key)->hide(); - - if(opType == "show") getOperatedEngine()->findClientSession(key)->show(); - - if(opType == "hidden") opt_response_content = getOperatedEngine()->findClientSession(key)->hidden() ? "true" : "false"; - - if(opType == "shown") opt_response_content = getOperatedEngine()->findClientSession(key)->shown() ? "true" : "false"; - } else { - std::string address; - int port; - anna::functions::getAddressAndPortFromSocketLiteral(param1, address, port); - - if(opType == "hide") getOperatedEngine()->findServer(address, port)->hide(); - - if(opType == "show") getOperatedEngine()->findServer(address, port)->show(); - - if(opType == "hidden") opt_response_content = getOperatedEngine()->findServer(address, port)->hidden() ? "true" : "false"; - - if(opType == "shown") opt_response_content = getOperatedEngine()->findServer(address, port)->shown() ? "true" : "false"; - } - } else { - if(opType == "hide") getOperatedEntity()->hide(); - - if(opType == "show") getOperatedEntity()->show(); - - if(opType == "hidden") opt_response_content = getOperatedEntity()->hidden() ? "true" : "false"; - - if(opType == "shown") opt_response_content = getOperatedEntity()->shown() ? "true" : "false"; - } } else if((opType == "sendxml2e") || (opType == "sendhex2e")) { anna::diameter::comm::Message *msg; @@ -1233,6 +1187,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons // Get DataBlock from file with hex content: if(!getDataBlockFromHexFile(param1, db_aux)) throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION); + updateOperatedOriginHostWithMessage(db_aux); msg = getOperatedHost()->createCommMessage(); msg->setBody(db_aux); try { if(getOperatedHost()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); } @@ -1248,6 +1203,87 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons std::string detail = usedClientSession ? usedClientSession->asString() : ""; // shouldn't happen getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail); } + } else if((opType == "sendxml2c") || (opType == "sendhex2c")) { + anna::diameter::comm::Message *msg; + + if(opType == "sendxml2c") { + codecMsg.loadXMLFile(param1); + updateOperatedOriginHostWithMessage(codecMsg); + msg = getOperatedHost()->createCommMessage(); + msg->clearBody(); + try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher) + + msg->setBody(codecMsg.code()); + } else { + // Get DataBlock from file with hex content: + if(!getDataBlockFromHexFile(param1, db_aux)) + throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION); + updateOperatedOriginHostWithMessage(db_aux); + msg = getOperatedHost()->createCommMessage(); + msg->setBody(db_aux); + } + + bool success = getOperatedServer()->send(msg); + getOperatedHost()->releaseCommMessage(msg); + + // Detailed log: + if(getOperatedHost()->logEnabled()) { + anna::diameter::comm::ServerSession *usedServerSession = getOperatedServer()->getLastUsedResource(); + std::string detail = usedServerSession ? usedServerSession->asString() : ""; // shouldn't happen + getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail); + } + } else if(opType == "answerxml2e") { + + if(param1 == "") { // programmed answers FIFO's to stdout + response = getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY"); + return true; // OK + } else if (param1 == "rotate") { + getOperatedEntity()->getReactingAnswers()->rotate(true); + } else if (param1 == "exhaust") { + getOperatedEntity()->getReactingAnswers()->rotate(false); + } else if (param1 == "clear") { + getOperatedEntity()->getReactingAnswers()->clear(); + } else if (param1 == "dump") { + getOperatedEntity()->getReactingAnswers()->dump("programmed_answer"); + } else { + codecMsg.loadXMLFile(param1); + updateOperatedOriginHostWithMessage(codecMsg); + anna::diameter::codec::Message *message = getOperatedHost()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils + LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION)); + + if(message->isRequest()) + throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); + + int code = message->getId().first; + LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); + getOperatedEntity()->getReactingAnswers()->addMessage(code, message); + } + } else if(opType == "answerxml2c") { + + if(param1 == "") { // programmed answers FIFO's to stdout + response = getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT"); + return true; // OK + } else if (param1 == "rotate") { + getOperatedServer()->getReactingAnswers()->rotate(true); + } else if (param1 == "exhaust") { + getOperatedServer()->getReactingAnswers()->rotate(false); + } else if (param1 == "clear") { + getOperatedServer()->getReactingAnswers()->clear(); + } else if (param1 == "dump") { + getOperatedServer()->getReactingAnswers()->dump("programmed_answer"); + } else { + codecMsg.loadXMLFile(param1); + updateOperatedOriginHostWithMessage(codecMsg); + anna::diameter::codec::Message *message = getOperatedHost()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils + LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION)); + + if(message->isRequest()) + throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); + + int code = message->getId().first; + LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); + getOperatedServer()->getReactingAnswers()->addMessage(code, message); + } } else if((opType == "burst")) { if (!uniqueOriginHost()) @@ -1267,9 +1303,9 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons // burst|look| Show programmed burst message for order provided, current when missing. if(param1 == "clear") { - opt_response_content = "removed "; - opt_response_content += anna::functions::asString(getOperatedHost()->clearBurst()); - opt_response_content += " elements"; + opt_response = "removed "; + opt_response += anna::functions::asString(getOperatedHost()->clearBurst()); + opt_response += " elements"; } else if(param1 == "load") { if(param2 == "") throw anna::RuntimeException("Missing xml path file for burst load operation", ANNA_FILE_LOCATION); @@ -1278,10 +1314,10 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue loading (see validation mode configured in launcher) int position = getOperatedHost()->loadBurstMessage(codecMsg.code()); - opt_response_content = "loaded '"; - opt_response_content += param2; - opt_response_content += "' file into burst list position "; - opt_response_content += anna::functions::asString(position); + opt_response = "loaded '"; + opt_response += param2; + opt_response += "' file into burst list position "; + opt_response += anna::functions::asString(position); } else if(param1 == "start") { if(param2 == "") throw anna::RuntimeException("Missing initial load for burst start operation", ANNA_FILE_LOCATION); @@ -1289,8 +1325,8 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons int processed = getOperatedHost()->startBurst(initialLoad); if(processed > 0) { - opt_response_content = "initial load completed for "; - opt_response_content += anna::functions::entriesAsString(processed, "message"); + opt_response = "initial load completed for "; + opt_response += anna::functions::entriesAsString(processed, "message"); } } else if(param1 == "push") { if(param2 == "") throw anna::RuntimeException("Missing load amount for burst push operation", ANNA_FILE_LOCATION); @@ -1298,8 +1334,8 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons int pushed = getOperatedHost()->pushBurst(atoi(param2.c_str())); if(pushed > 0) { - opt_response_content = "pushed "; - opt_response_content += anna::functions::entriesAsString(pushed, "message"); + opt_response = "pushed "; + opt_response += anna::functions::entriesAsString(pushed, "message"); } } else if(param1 == "pop") { if(param2 == "") throw anna::RuntimeException("Missing amount for burst pop operation", ANNA_FILE_LOCATION); @@ -1308,39 +1344,39 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons int popped = getOperatedHost()->popBurst(releaseLoad); if(popped > 0) { - opt_response_content = "burst popped for "; - opt_response_content += anna::functions::entriesAsString(popped, "message"); + opt_response = "burst popped for "; + opt_response += anna::functions::entriesAsString(popped, "message"); } } else if(param1 == "stop") { int left = getOperatedHost()->stopBurst(); if(left != -1) { - opt_response_content += anna::functions::entriesAsString(left, "message"); - opt_response_content += " left to the end of the cycle"; + opt_response += anna::functions::entriesAsString(left, "message"); + opt_response += " left to the end of the cycle"; } } else if(param1 == "repeat") { if(param2 == "") param2 = "yes"; bool repeat = (param2 == "yes"); getOperatedHost()->repeatBurst(repeat); - opt_response_content += (repeat ? "repeat enabled" : "repeat disabled"); + opt_response += (repeat ? "repeat enabled" : "repeat disabled"); } else if(param1 == "send") { if(param2 == "") throw anna::RuntimeException("Missing amount for burst send operation", ANNA_FILE_LOCATION); int sent = getOperatedHost()->sendBurst(atoi(param2.c_str())); if(sent > 0) { - opt_response_content = "sent "; - opt_response_content += anna::functions::entriesAsString(sent, "message"); + opt_response = "sent "; + opt_response += anna::functions::entriesAsString(sent, "message"); } } else if(param1 == "goto") { if(param2 == "") throw anna::RuntimeException("Missing order position for burst goto operation", ANNA_FILE_LOCATION); - opt_response_content = getOperatedHost()->gotoBurst(atoi(param2.c_str())); + opt_response = getOperatedHost()->gotoBurst(atoi(param2.c_str())); } else if(param1 == "look") { int order = ((param2 != "") ? atoi(param2.c_str()) : -1); - opt_response_content = "\n\n"; - opt_response_content += getOperatedHost()->lookBurst(order); + opt_response = "\n\n"; + opt_response += getOperatedHost()->lookBurst(order); } else { throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); } @@ -1355,6 +1391,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons // Enables/disables report generation for a certain test case state: initialized, in-progress ... // test|report-hex[|[yes]|no] Reports could include the diameter messages in hexadecimal format. Disabled by default. // test|goto| Updates current test pointer position. + // test|run| Executes the given test case // test|look[|id] Show programmed test case for id provided, current when missing ... // test|state[|id] Show test case state for id provided, current when missing ... // test|interact|amount|id Makes interactive a specific test case id. The amount is the margin of execution steps ... @@ -1370,12 +1407,12 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons bool success = ((param2 != "") ? testManager.configureTTPS(atoi(param2.c_str())) : false); if (success) { - opt_response_content = "assigned new test launch rate to "; - opt_response_content += anna::functions::asString(atoi(param2.c_str())); - opt_response_content += " events per second"; + opt_response = "assigned new test launch rate to "; + opt_response += anna::functions::asString(atoi(param2.c_str())); + opt_response += " events per second"; } else { - opt_response_content += "unable to configure the test rate provided"; + opt_response += "unable to configure the test rate provided"; } } else if (param1 == "next") { @@ -1389,10 +1426,10 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons bool success = testManager.execTestCases(sync_amount); - opt_response_content = (success ? "" : "not completely " /* completed cycle and no repeats, rare case */); - opt_response_content += "processed "; - opt_response_content += anna::functions::asString(sync_amount); - opt_response_content += ((sync_amount > 1) ? " test cases synchronously" : " test case"); + opt_response = (success ? "" : "not completely " /* completed cycle and no repeats, rare case */); + opt_response += "processed "; + opt_response += anna::functions::asString(sync_amount); + opt_response += ((sync_amount > 1) ? " test cases synchronously" : " test case"); } else if(param1 == "ip-limit") { if (numParams > 2) @@ -1402,16 +1439,16 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if (param2 != "") { limit = atoi(param2.c_str()); testManager.setInProgressLimit(limit); - opt_response_content = "new in-progress limit: "; - opt_response_content += (limit != UINT_MAX) ? anna::functions::asString(limit) : ""; + opt_response = "new in-progress limit: "; + opt_response += (limit != UINT_MAX) ? anna::functions::asString(limit) : ""; } else { - opt_response_content = "in-progress limit amount: "; + opt_response = "in-progress limit amount: "; limit = testManager.getInProgressLimit(); - opt_response_content += (limit != UINT_MAX) ? anna::functions::asString(limit) : ""; - opt_response_content += "; currently there are "; - opt_response_content += anna::functions::asString(testManager.getInProgressCount()); - opt_response_content += " test cases running"; + opt_response += (limit != UINT_MAX) ? anna::functions::asString(limit) : ""; + opt_response += "; currently there are "; + opt_response += anna::functions::asString(testManager.getInProgressCount()); + opt_response += " test cases running"; } } else if(param1 == "repeats") { @@ -1421,7 +1458,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if (repeats < 0) repeats = -1; testManager.setPoolRepeats(repeats); std::string nolimit = (repeats != -1) ? "":" [no limit]"; - opt_response_content += anna::functions::asString("Pool repeats: %d%s (current cycle: %d)", repeats, nolimit.c_str(), testManager.getPoolCycle()); + opt_response += anna::functions::asString("Pool repeats: %d%s (current cycle: %d)", repeats, nolimit.c_str(), testManager.getPoolCycle()); } else if(param1 == "report") { if (numParams > 3) @@ -1451,10 +1488,10 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons else throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); - opt_response_content += (enable ? "report enabled " : "report disabled "); - opt_response_content += "for tests in '"; - opt_response_content += param2; - opt_response_content += "' state"; + opt_response += (enable ? "report enabled " : "report disabled "); + opt_response += "for tests in '"; + opt_response += param2; + opt_response += "' state"; } else if(param1 == "report-hex") { if (numParams > 2) @@ -1462,7 +1499,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") param2 = "yes"; testManager.setDumpHex((param2 == "yes")); - opt_response_content += (testManager.getDumpHex() ? "report includes hexadecimal messages" : "report excludes hexadecimal messages"); + opt_response += (testManager.getDumpHex() ? "report includes hexadecimal messages" : "report excludes hexadecimal messages"); } else if(param1 == "dump-stdout") { if (numParams > 2) @@ -1470,7 +1507,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") param2 = "yes"; testManager.setDumpStdout((param2 == "yes")); - opt_response_content += (testManager.getDumpHex() ? "test manager dumps progress into stdout" : "test manager does not dump progress into stdout"); + opt_response += (testManager.getDumpHex() ? "test manager dumps progress into stdout" : "test manager does not dump progress into stdout"); } else if(param1 == "goto") { if (numParams > 2) @@ -1479,13 +1516,13 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") throw anna::RuntimeException("Missing id for test goto operation", ANNA_FILE_LOCATION); int id = atoi(param2.c_str()); if (testManager.gotoTestCase(id)) { - opt_response_content = "position updated for id provided ("; + opt_response = "position updated for id provided ("; } else { - opt_response_content = "cannot found test id ("; + opt_response = "cannot found test id ("; } - opt_response_content += anna::functions::asString(id); - opt_response_content += ")"; + opt_response += anna::functions::asString(id); + opt_response += ")"; } else if(param1 == "run") { if (numParams > 2) @@ -1494,13 +1531,13 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") throw anna::RuntimeException("Missing id for test run operation", ANNA_FILE_LOCATION); int id = atoi(param2.c_str()); if (testManager.runTestCase(id)) { - opt_response_content = "test executed for id provided ("; + opt_response = "test executed for id provided ("; } else { - opt_response_content = "cannot found test id ("; + opt_response = "cannot found test id ("; } - opt_response_content += anna::functions::asString(id); - opt_response_content += ")"; + opt_response += anna::functions::asString(id); + opt_response += ")"; } else if(param1 == "look") { if (numParams > 2) @@ -1510,18 +1547,18 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons anna::testing::TestCase *testCase = testManager.findTestCase(id); if (testCase) { - response_content = testCase->asXMLString(); + response = testCase->asXMLString(); return true; // OK } else { result = false; if (id == -1) { - opt_response_content = "no current test case detected (testing started ?)"; + opt_response = "no current test case detected (testing started ?)"; } else { - opt_response_content = "cannot found test id ("; - opt_response_content += anna::functions::asString(id); - opt_response_content += ")"; + opt_response = "cannot found test id ("; + opt_response += anna::functions::asString(id); + opt_response += ")"; } } } @@ -1533,18 +1570,18 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons anna::testing::TestCase *testCase = testManager.findTestCase(id); if (testCase) { - response_content = anna::testing::TestCase::asText(testCase->getState()); + response = anna::testing::TestCase::asText(testCase->getState()); return testCase->isSuccess(); } else { result = false; if (id == -1) { - opt_response_content = "no current test case detected (testing started ?)"; + opt_response = "no current test case detected (testing started ?)"; } else { - opt_response_content = "cannot found test id ("; - opt_response_content += anna::functions::asString(id); - opt_response_content += ")"; + opt_response = "cannot found test id ("; + opt_response += anna::functions::asString(id); + opt_response += ")"; } } } @@ -1561,23 +1598,23 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if (testCase) { if (amount == -1) { testCase->makeInteractive(false); - opt_response_content = "interactive mode disabled"; + opt_response = "interactive mode disabled"; } else { testCase->addInteractiveAmount(amount); - opt_response_content = "added interactive amount of "; - opt_response_content += anna::functions::asString(amount); - opt_response_content += " units"; - if (amount == 0) opt_response_content += " (0: freezing a non-interactive testcase, no effect on already interactive)"; + opt_response = "added interactive amount of "; + opt_response += anna::functions::asString(amount); + opt_response += " units"; + if (amount == 0) opt_response += " (0: freezing a non-interactive testcase, no effect on already interactive)"; } - opt_response_content += " for test case id "; - opt_response_content += anna::functions::asString(id); + opt_response += " for test case id "; + opt_response += anna::functions::asString(id); } else { result = false; - opt_response_content = "cannot found test id ("; - opt_response_content += anna::functions::asString(id); - opt_response_content += ")"; + opt_response = "cannot found test id ("; + opt_response += anna::functions::asString(id); + opt_response += ")"; } } else if(param1 == "reset") { @@ -1593,22 +1630,22 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons if (testCase) { bool done = testCase->reset(param2 == "hard"); - opt_response_content = "test "; - opt_response_content += param2; - opt_response_content += " reset for id "; - opt_response_content += anna::functions::asString(id); - opt_response_content += done ? ": done": ": not done"; + opt_response = "test "; + opt_response += param2; + opt_response += " reset for id "; + opt_response += anna::functions::asString(id); + opt_response += done ? ": done": ": not done"; } else { if (id == -1) { bool anyReset = testManager.resetPool(param2 == "hard"); - opt_response_content = param2; opt_response_content += " reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all have been reset" : "nothing was reset"; + opt_response = param2; opt_response += " reset have been sent to all programmed tests: "; opt_response += anyReset ? "some/all have been reset" : "nothing was reset"; } else { result = false; - opt_response_content = "cannot found test id ("; - opt_response_content += anna::functions::asString(id); - opt_response_content += ")"; + opt_response = "cannot found test id ("; + opt_response += anna::functions::asString(id); + opt_response += ")"; } } } @@ -1620,45 +1657,40 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); testManager.setAutoResetHard(param2 == "hard"); - opt_response_content += anna::functions::asString("Auto-reset configured to '%s'", param2.c_str()); + opt_response += anna::functions::asString("Auto-reset configured to '%s'", param2.c_str()); } else if(param1 == "initialized") { if (numParams > 1) throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); - opt_response_content = anna::functions::asString("%lu", testManager.getInitializedCount()); + opt_response = anna::functions::asString("%lu", testManager.getInitializedCount()); } else if(param1 == "finished") { if (numParams > 1) throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); - opt_response_content = anna::functions::asString("%lu", testManager.getFinishedCount()); + opt_response = anna::functions::asString("%lu", testManager.getFinishedCount()); } else if(param1 == "clear") { if (numParams > 1) throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); - if (testManager.clearPool()) { - opt_response_content = "all the programmed test cases have been dropped"; - } - else { - opt_response_content = "there are not programmed test cases to be removed"; - } + result = testManager.clearPool(opt_response); } else if(param1 == "junit") { - response_content = testManager.junitAsXMLString(); + response = testManager.junitAsXMLString(); return true; // OK } else if(param1 == "summary-counts") { - response_content = testManager.summaryCounts(); + response = testManager.summaryCounts(); return true; // OK } else if(param1 == "summary-states") { - response_content = testManager.summaryStates(); + response = testManager.summaryStates(); return true; // OK } else if(param1 == "summary") { - response_content = testManager.asXMLString(); + response = testManager.asXMLString(); return true; // OK } else { @@ -1777,49 +1809,42 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION); - // Get xml content from file: - std::string regexp; - if(!getContentFromFile(param3, regexp)) - throw anna::RuntimeException("Error reading xml content from file provided", ANNA_FILE_LOCATION); + codecMsg.loadXMLFile(param3); + std::string regexp = codecMsg.asXMLString(true /* normalization */); + + // Now we must insert regular expressions in hop-by-hop, end-to-end and Origin-State-Id: // optional 'full': if(param4 != "strict") { - - // TODO: use this from gcc4.9.0: http://stackoverflow.com/questions/8060025/is-this-c11-regex-error-me-or-the-compiler -/* - std::string s_from = "hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\""; - std::string s_to = s_from; - std::string s_from2 = "avp name=\"Origin-State-Id\" data=\"[0-9]+\""; - std::string s_to2 = s_from2; - - try { - regexp = std::regex_replace (regexp, std::regex(s_from), s_to); - regexp = std::regex_replace (regexp, std::regex(s_from2), s_to2); - } - catch (const std::regex_error& e) { - throw anna::RuntimeException(e.what(), ANNA_FILE_LOCATION); - } - -*/ std::string::size_type pos, pos_1, pos_2; - pos = regexp.find("hop-by-hop-id=", 0u); + pos = regexp.find("end-to-end-id=", 0u); pos = regexp.find("\"", pos); pos_1 = pos; pos = regexp.find("\"", pos+1); pos_2 = pos; regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+"); - pos = regexp.find("end-to-end-id=", 0u); + pos = regexp.find("hop-by-hop-id=", 0u); pos = regexp.find("\"", pos); pos_1 = pos; pos = regexp.find("\"", pos+1); pos_2 = pos; regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+"); + // For this representation: + //pos = regexp.find("Origin-State-Id", 0u); + //pos = regexp.find("\"", pos); + //pos = regexp.find("\"", pos+1); + //pos_1 = pos; + //pos = regexp.find("\"", pos+1); + //pos_2 = pos; + //regexp.replace(pos_1 + 1, pos_2 - pos_1 - 1, "[0-9]+"); + // But we have this one: pos = regexp.find("Origin-State-Id", 0u); - pos = regexp.find("\"", pos); - pos = regexp.find("\"", pos+1); + pos = regexp.rfind("\"", pos); + pos = regexp.rfind("\"", pos-1); + pos = regexp.rfind("\"", pos-1); pos_1 = pos; pos = regexp.find("\"", pos+1); pos_2 = pos; @@ -1846,102 +1871,27 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons } } - } else if((opType == "sendxml2c") || (opType == "sendhex2c")) { - anna::diameter::comm::Message *msg; - - if(opType == "sendxml2c") { - codecMsg.loadXMLFile(param1); - updateOperatedOriginHostWithMessage(codecMsg); - msg = getOperatedHost()->createCommMessage(); - msg->clearBody(); - try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher) - - msg->setBody(codecMsg.code()); - } else { - // Get DataBlock from file with hex content: - if(!getDataBlockFromHexFile(param1, db_aux)) - throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION); - msg = getOperatedHost()->createCommMessage(); - msg->setBody(db_aux); - } - - bool success = getOperatedServer()->send(msg); - getOperatedHost()->releaseCommMessage(msg); - - // Detailed log: - if(getOperatedHost()->logEnabled()) { - anna::diameter::comm::ServerSession *usedServerSession = getOperatedServer()->getLastUsedResource(); - std::string detail = usedServerSession ? usedServerSession->asString() : ""; // shouldn't happen - getOperatedHost()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail); - } } else if(opType == "loadxml") { codecMsg.loadXMLFile(param1); - response_content = codecMsg.asXMLString(); + response = codecMsg.asXMLString(); return true; // OK } else if(opType == "diameterServerSessions") { int diameterServerSessions = atoi(param1.c_str()); getOperatedServer()->setMaxConnections(diameterServerSessions); - } else if(opType == "answerxml2c") { - if(param1 == "") { // programmed answers FIFO's to stdout - response_content = getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT"); - return true; // OK - } else if (param1 == "rotate") { - getOperatedServer()->getReactingAnswers()->rotate(true); - } else if (param1 == "exhaust") { - getOperatedServer()->getReactingAnswers()->rotate(false); - } else if (param1 == "clear") { - getOperatedServer()->getReactingAnswers()->clear(); - } else if (param1 == "dump") { - getOperatedServer()->getReactingAnswers()->dump("programmed_answer"); - } else { - codecMsg.loadXMLFile(param1); - updateOperatedOriginHostWithMessage(codecMsg); - anna::diameter::codec::Message *message = getOperatedHost()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils - LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION)); - if(message->isRequest()) - throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); - int code = message->getId().first; - LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); - getOperatedServer()->getReactingAnswers()->addMessage(code, message); - } - } else if(opType == "answerxml2e") { - - if(param1 == "") { // programmed answers FIFO's to stdout - response_content = getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY"); - return true; // OK - } else if (param1 == "rotate") { - getOperatedEntity()->getReactingAnswers()->rotate(true); - } else if (param1 == "exhaust") { - getOperatedEntity()->getReactingAnswers()->rotate(false); - } else if (param1 == "clear") { - getOperatedEntity()->getReactingAnswers()->clear(); - } else if (param1 == "dump") { - getOperatedEntity()->getReactingAnswers()->dump("programmed_answer"); - } else { - codecMsg.loadXMLFile(param1); - updateOperatedOriginHostWithMessage(codecMsg); - anna::diameter::codec::Message *message = getOperatedHost()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils - LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION)); - - if(message->isRequest()) - throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); - - int code = message->getId().first; - LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); - getOperatedEntity()->getReactingAnswers()->addMessage(code, message); - } } else { throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION); } + + // HTTP response - response_content = "Operation correctly processed: "; response_content += operation; - if (opt_response_content != "") { - response_content += " => "; - response_content += opt_response_content; + response = "Operation correctly processed: "; response += operation; + if (opt_response != "") { + response += " => "; + response += opt_response; } return result;