#include <anna/time/functions.hpp>
#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
#include <anna/xml/xml.hpp>
+#include <Procedure.hpp>
// Process
#include <Launcher.hpp>
-->\n\
\n\
<!ELEMENT node EMPTY>\n\
-<!ATTLIST node originHost CDATA #REQUIRED applicationId CDATA #REQUIRED originRealm CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>\n\
+<!ATTLIST node originHost CDATA #REQUIRED applicationId CDATA #REQUIRED originRealm CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED cea CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>\n\
<!--\n\
Node record\n\
\n\
originHost: Node identifier as diameter application host name.\n\
applicationId: The Application-Id provided must exists as a registered 'stack id'.\n\
originRealm: Origin-Realm (domain-name internally used by default).\n\
+\n\
+\n\
+ - Diameter clients:\n\
+\n\
+ entity: Target diameter entity (comma-separated '<address>:<port>' format).\n\
+ For example: 10.20.30.40:3868,10.20.30.41:3868. If missing, no entity will be enabled.\n\
+ entityServerSessions: Diameter entity server sessions (0: diameter entity disabled). Default value of 1.\n\
cer: User defined CER path file to be encoded to establish diameter connections.\n\
If missing, will be harcoded.\n\
dwr: User defined DWR path file to be encoded for diameter protocol keep alive.\n\
If missing, will be harcoded.\n\
- allowedInactivityTime: Milliseconds for the maximum allowed inactivity time on server sessions born over the\n\
- local server before being reset. If missing, default value of 90000 will be assigned.\n\
tcpConnectDelay: Milliseconds to wait TCP connect to any server. If missing, default value of 200 will\n\
be assigned\n\
- answersTimeout: Milliseconds to wait pending application answers from diameter peers. If missing,\n\
- default value of 10000 will be assigned.\n\
ceaTimeout: Milliseconds to wait CEA from diameter server. If missing, default value of 'answersTimeout'\n\
will be assigned.\n\
watchdogPeriod: Milliseconds for watchdog timer (Tw) for diameter keep-alive procedure. If missing, default\n\
value of 30000 will be assigned.\n\
- entity: Target diameter entity (comma-separated '<address>:<port>' format).\n\
- For example: 10.20.30.40:3868,10.20.30.41:3868. If missing, no entity will be enabled.\n\
- entityServerSessions: Diameter entity server sessions (0: diameter entity disabled). Default value of 1.\n\
- diameterServer: Diameter own server address in '<address>:<port>' format. For example: 10.20.30.40:3868.\n\
- If missing, no local server will be enabled.\n\
- diameterServerSessions: Diameter own server available connections (0: diameter server disabled). Default value of 1.\n\
- Negative value implies no limit accepting incoming connections.\n\
balance: Balance over entity servers instead of doing standard behaviour (first primary, secondary\n\
if fails, etc.). Default value 'no'.\n\
sessionBasedModelsClientSocketSelection: By default, round-robin will be applied for IEC model (SMS/MMS), and Session-Id Low Part\n\
will be analyzed for ECUR/SCUR model (data, voice and content). You could change ECUR/SCUR\n\
analysis behaviour providing 'SessionIdHighPart', 'SessionIdOptionalPart' (atoi applied;\n\
usually subscriber id data, i.e. MSISDN or IMSI) and 'RoundRobin' (also 'SessionIdLowPart').\n\
+\n\
+\n\
+ - Diameter servers:\n\
+\n\
+ diameterServer: Diameter own server address in '<address>:<port>' format. For example: 10.20.30.40:3868.\n\
+ If missing, no local server will be enabled.\n\
+ diameterServerSessions: Diameter own server available connections (0: diameter server disabled). Default value of 1.\n\
+ Negative value implies no limit accepting incoming connections.\n\
+ cea: User defined CEA path file to be encoded to answer client CERs.\n\
+ If missing, will be harcoded.\n\
+ allowedInactivityTime: Milliseconds for the maximum allowed inactivity time on server sessions born over the\n\
+ local server before being reset. If missing, default value of 90000 will be assigned.\n\
+\n\
+\n\
+ - General:\n\
+\n\
+ answersTimeout: Milliseconds to wait pending application answers from diameter peers. If missing,\n\
+ default value of 10000 will be assigned.\n\
retries: Expired responses will cause a number of request retransmissions. Disabled by default (0 retries).\n\
log: Process log file (operations result, traffic log, etc.). By default '<originHost>.launcher.log'.\n\
Empty string or \"null\" name, to disable. Warning: there is no rotation for log files\n\
detailedLog: Insert detailed information at log files (timestamps, communication resources, etc.). Useful\n\
to analyze the messages flow along the sockets (specially on 'balance' mode). Default 'no'.\n\
dumpLog: Write to disk every incoming/outcoming message named as:\n\
- '<originHost>.<hop by hop>.<end to end>.<message code>.<request|answer>.<type of event>.xml'\n\
+ '<unix ms timestamp>.<originHost>.<hop by hop>.<end to end>.<message code>.<request|answer>.<type of event>.xml'\n\
Default value 'no'.\n\
burstLog: Burst operations log file. By default '<originHost>.launcher.burst'. Empty string or \"null\" name, to disable.\n\
Warning: there is no rotation for log files (use logrotate or whatever). Output: dot (.) for each\n\
const anna::xml::Attribute *id, *dictionary;
// <!ATTLIST node originHost CDATA #REQUIRED applicationId CDATA #REQUIRED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
- const anna::xml::Attribute *originHost, *appId, *originRealm, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay,
+ const anna::xml::Attribute *originHost, *appId, *originRealm, *cer, *dwr, *cea, *allowedInactivityTime, *tcpConnectDelay,
*answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions,
*diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection,
*retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog;
originRealm = (*it)->getAttribute("originRealm", false /* no exception */);
cer = (*it)->getAttribute("cer", false /* no exception */);
dwr = (*it)->getAttribute("dwr", false /* no exception */);
+ cea = (*it)->getAttribute("cea", false /* no exception */);
allowedInactivityTime = (*it)->getAttribute("allowedInactivityTime", false /* no exception */);
tcpConnectDelay = (*it)->getAttribute("tcpConnectDelay", false /* no exception */);
answersTimeout = (*it)->getAttribute("answersTimeout", false /* no exception */);
// Assignments:
commEngine->setMaxConnectionDelay(tcpConnectDelayMs);
commEngine->setWatchdogPeriod(watchdogPeriodMs);
+ a_workingNode->setRequestRetransmissions(retransmissions);
// Realm information:
commEngine->setOriginHost(originHost->getValue());
// Register one entity for this engine:
a_workingNode->createEntity(entity->getValue(), ceaTimeoutMs, answersTimeoutMs);
- a_workingNode->setRequestRetransmissions(retransmissions);
a_workingNode->getEntity()->setSessionBasedModelsType(sessionBasedModelsType);
a_workingNode->getEntity()->setBalance(balance ? (balance->getValue() == "yes") : false); // for sendings
if (eventOperation) a_workingNode->getEntity()->bind();
// Diameter Server:
if(diameterServer) {
+ // Server CEA
+ std::string ceaPathfile = cea ? cea->getValue() : "";
+
int sessions = diameterServerSessions ? diameterServerSessions->getIntegerValue() : 1;
- a_workingNode->startDiameterServer(diameterServer->getValue(), sessions, allowedInactivityTimeMs);
+ a_workingNode->startDiameterServer(diameterServer->getValue(), sessions, allowedInactivityTimeMs, answersTimeoutMs, ceaPathfile);
}
// Logs:
a_timeEngine->activate(a_counterRecorderClock); // start clock
}
- // Log statistics concepts
- if(cl.exists("logStatisticSamples")) {
- std::string list = cl.getValue("logStatisticSamples");
- anna::statistics::Engine &statEngine = anna::statistics::Engine::instantiate();
-
- if(list == "all") {
- if(statEngine.enableSampleLog(/* -1: all concepts */))
- LOGDEBUG(anna::Logger::debug("Sample log activation for all statistic concepts", ANNA_FILE_LOCATION));
- } else {
- anna::Tokenizer lst;
- lst.apply(cl.getValue("logStatisticSamples"), ",");
-
- if(lst.size() >= 1) {
- anna::Tokenizer::const_iterator tok_min(lst.begin());
- anna::Tokenizer::const_iterator tok_max(lst.end());
- anna::Tokenizer::const_iterator tok_iter;
- int conceptId;
-
- for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
- conceptId = atoi(anna::Tokenizer::data(tok_iter));
-
- if(statEngine.enableSampleLog(conceptId))
- LOGDEBUG(anna::Logger::debug(anna::functions::asString("Sample log activation for statistic concept id = %d", conceptId), ANNA_FILE_LOCATION));
- }
- }
- }
- }
-
+ /////////////////////////////
+ // Log statistics concepts //
+ /////////////////////////////
+ if(cl.exists("logStatisticSamples"))
+ logStatisticsSamples(cl.getValue("logStatisticSamples"));
// Start client connections //////////////////////////////////////////////////////////////////////////////////
MyDiameterEntity *entity;
result += "\n This operation applies over all the registered host 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 += "\nlog-statistics-samples|<list> Log statistics samples for the provided comma-separated concept id";
+ result += "\n list, over './sample.<concept id>.csv' files. For example: \"1,2\"";
+ result += "\n will log concepts 1 and 2. Reserved words \"all\"/\"none\" activates/";
+ result += "\n deactivates all registered statistics concept identifiers. That ids";
+ result += "\n are shown at context dump.";
result += "\nchange-dir[|directory] Changes the execution point which could be fine to ease some";
result += "\n file system interaction tasks. Be care about some requirements";
result += "\n (for example if you have a user defined counters directory as";
result += "\n sendxml2e|<source_file>[|<step number>]";
result += "\n Sends xml source file (pathfile) to entity (it would be a";
result += "\n 'forward' event if it came through local server endpoint).";
+ result += "\n Take into account that the xml message is encoded just on";
+ result += "\n call. The xml file is not longer needed neither interpreted";
+ result += "\n in case of modification, after calling this command.";
result += "\n The step number should be provided for answers to indicate";
result += "\n the 'wait for request' corresponding step. If you miss this";
result += "\n reference, the sequence information (hop-by-hop, end-to-end)";
result += "\n the difficulty of predicting these information). Be sure to";
result += "\n refer to a 'wait for request' step. Conditions like 'regexp'";
result += "\n (as we will see later) are not verified.";
+ result += "\n In the case of requests, the step number is used to force the";
+ result += "\n copy of Session-Id value from the referred step.";
result += "\n";
result += "\n sendxml2c|<source_file>[|<step number>]";
result += "\n Sends xml source file (pathfile) to client (it would be a";
result += "\n test|report-hex[|[yes]|no] Reports could include the diameter messages in hexadecimal format. Disabled by default.";
result += "\n";
result += "\n";
+ result += "\n------------------------------------------------------------------------------------- Dynamic procedure";
+ result += "\n";
+ result += "\ndynamic[|args] This launch an internal operation implemented in 'Procedure' class.";
+ result += "\n Its default implementation does nothing, but you could create a dynamic";
+ result += "\n library 'libanna_launcherDynamic.so' and replace the one in this project.";
+ result += "\n One interesting application consists in the use of the diameter API and";
+ result += "\n event operation to create a set of libraries as the testing framework.";
+ result += "\n To execute each test case, the ADML process would be executed with a";
+ result += "\n specific library path. But the main use would be the stress programming";
+ result += "\n to achieve a great amount of cloned (even mixed) tests without using";
+ result += "\n the management operation interface by mean http or signals: a single";
+ result += "\n call to 'dynamic' would be enough to start a cascade of internally";
+ result += "\n implemented operations.";
+ result += "\n This operation accepts a generic string argument (piped or not, as you";
+ result += "\n desire and depending on your procedure implementation).";
+ result += "\n";
+ result += "\n This operation requires advanced programming and knowlegde of ANNA Diameter";
+ result += "\n stack and testing framework, to take advantage of all the possibilities.";
+ result += "\n";
+ result += "\n";
+ result += "\n";
result += "\nUSING OPERATIONS INTERFACE";
result += "\n--------------------------";
result += "\n";
return result;
}
+
+void Launcher::logStatisticsSamples(const std::string &conceptsList) throw() {
+ anna::statistics::Engine &statEngine = anna::statistics::Engine::instantiate();
+
+ if(conceptsList == "all") {
+ if(statEngine.enableSampleLog(/* -1: all concepts */))
+ LOGDEBUG(anna::Logger::debug("Sample log activation for all statistic concepts", ANNA_FILE_LOCATION));
+ }
+ else if(conceptsList == "none") {
+ if(statEngine.disableSampleLog(/* -1: all concepts */))
+ LOGDEBUG(anna::Logger::debug("Sample log deactivation for all statistic concepts", ANNA_FILE_LOCATION));
+ } else {
+ anna::Tokenizer lst;
+ lst.apply(conceptsList, ",");
+
+ if(lst.size() >= 1) {
+ anna::Tokenizer::const_iterator tok_min(lst.begin());
+ anna::Tokenizer::const_iterator tok_max(lst.end());
+ anna::Tokenizer::const_iterator tok_iter;
+ int conceptId;
+
+ for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
+ conceptId = atoi(anna::Tokenizer::data(tok_iter));
+
+ if(statEngine.enableSampleLog(conceptId))
+ LOGDEBUG(anna::Logger::debug(anna::functions::asString("Sample log activation for statistic concept id = %d", conceptId), ANNA_FILE_LOCATION));
+ }
+ }
+ }
+}
+
+
void Launcher::eventOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) {
LOGMETHOD(anna::TraceMethod tm("Launcher", "eventOperation", ANNA_FILE_LOCATION));
if (operation == "") return; // ignore
- LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION));
+ LOGDEBUG(anna::Logger::debug(anna::functions::asString("Operation: %s", operation.c_str()), ANNA_FILE_LOCATION));
// Default response:
response_content = "Operation processed with exception: ";
///////////////////////////////////////////////////////////////////
// Simple operations without arguments:
+ // Dynamic operation:
+ if(operation.find("dynamic") == 0) {
+ Procedure p(this);
+ int op_size = operation.size();
+ std::string args = ((operation.find("dynamic|") == 0) && (op_size > 8)) ? operation.substr(8) : "";
+ if (args == "" && op_size != 7)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+ p.execute(args, response_content);
+ return;
+ }
+
// Help:
if(operation == "help") {
response_content = help();
bool wrongBody = false;
if((opType == "change-dir") && (numParams > 1)) wrongBody = true;
+ if((opType == "log-statistics-samples") && (numParams != 1)) wrongBody = true;
if((opType == "node") && (numParams > 1)) wrongBody = true;
if((opType == "node_auto") && (numParams > 0)) wrongBody = true;
return;
}
+ if(opType == "log-statistics-samples") {
+ logStatisticsSamples(param1);
+ response_content = anna::functions::asString("Log statistics samples for '%s' concepts", param1.c_str());
+ return;
+ }
+
// Change execution directory:
if(opType == "change-dir") {
if (param1 == "") param1 = a_initialWorkingDirectory;
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see 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);
codecMsg.loadXML(param3);
- if (codecMsg.isRequest()) {
- if (param4 != "")
- throw anna::RuntimeException("Step number is provided with answers (to resolve the corresponding 'wait for request' step), but NOT with requests", ANNA_FILE_LOCATION);
- }
- else {
- if (param4 == "") LOGWARNING(anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION));
- }
+ LOGWARNING(
+ if (!codecMsg.isRequest() && (param4 == ""))
+ anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION);
+ );
+
updateOperatedOriginHostWithMessage(codecMsg);
int stepNumber = ((param4 != "") ? atoi(param4.c_str()):-1);