Fixes and improvs. Basic DRA feature.
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Tue, 8 Sep 2015 00:19:21 +0000 (02:19 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Fri, 11 Sep 2015 20:19:15 +0000 (22:19 +0200)
23 files changed:
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/Launcher.hpp
example/diameter/launcher/MyDiameterEngine.hpp
example/diameter/launcher/RealmNode.cpp
example/diameter/launcher/RealmNode.hpp
example/diameter/launcher/resources/scripts/operation_signal.sh
example/diameter/launcher/resources/services_examples/balancer.xml
example/diameter/launcher/resources/services_examples/client.xml
example/diameter/launcher/resources/services_examples/dummy.xml
example/diameter/launcher/resources/services_examples/multi-client.xml
example/diameter/launcher/resources/services_examples/server.xml
example/diameter/launcher/resources/services_examples/services.dtd
example/diameter/launcher/testing/TestCase.cpp
example/diameter/launcher/testing/TestManager.cpp
example/diameter/launcher/testing/TestManager.hpp
example/diameter/launcher/testing/TestStep.cpp
example/diameter/launcher/testing/TestStep.hpp
include/anna/diameter.comm/Engine.hpp
include/anna/diameter/codec/EngineImpl.hpp
include/anna/diameter/codec/Message.hpp
source/diameter.comm/Engine.cpp
source/diameter.comm/LocalServer.cpp
source/diameter.comm/ServerSession.cpp

index eb4dfe7..a6c5bee 100644 (file)
@@ -31,8 +31,8 @@
 #include <TestCase.hpp>
 
 
 #include <TestCase.hpp>
 
 
-#define SIGUSR2_TASKS_INPUT_FILENAME "./sigusr2.tasks.input"
-#define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.tasks.output"
+#define SIGUSR2_TASKS_INPUT_FILENAME "./sigusr2.in"
+#define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.out"
 
 
 
 
 
 
@@ -47,19 +47,18 @@ const char *ServicesDTD = "\
 <!--\n\
    Stack record\n\
 \n\
 <!--\n\
    Stack record\n\
 \n\
-   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed.\n\
+   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed\n\
                (in multistack applications, it shall be mandatory respect such association to know the stack used\n\
                for processed messages).\n\
    dictionary: Path to the dictionary file\n\
 -->\n\
 \n\
 <!ELEMENT node EMPTY>\n\
                (in multistack applications, it shall be mandatory respect such association to know the stack used\n\
                for processed messages).\n\
    dictionary: Path to the dictionary file\n\
 -->\n\
 \n\
 <!ELEMENT node EMPTY>\n\
-<!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost 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 originRealm CDATA #REQUIRED originHost 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\
 <!--\n\
    Node record\n\
 \n\
    originRealm:                             Node identifier (Origin-Realm name).\n\
 <!--\n\
    Node record\n\
 \n\
    originRealm:                             Node identifier (Origin-Realm name).\n\
-   applicationId:                           The Application-Id provided must exists as a registered 'stack id'.\n\
    originHost:                              Diameter application host name (system name). If missing, process sets o.s. hostname\n\
                                             Note that if you have two or more realms, the names must be different.\n\
    cer:                                     User defined CER path file to be encoded to establish diameter connections.\n\
    originHost:                              Diameter application host name (system name). If missing, process sets o.s. hostname\n\
                                             Note that if you have two or more realms, the names must be different.\n\
    cer:                                     User defined CER path file to be encoded to establish diameter connections.\n\
@@ -112,6 +111,7 @@ const char *ServicesDTD = "\
 
 Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "1.1"), a_communicator(NULL) {
   a_codecEngine = new anna::diameter::codec::Engine("MyCodecEngine");
 
 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;
   a_timeEngine = NULL;
   a_counterRecorder = NULL;
   a_admlMinResolution = 2 * anna::timex::Engine::minResolution; // 2*10 = 20 ms; 1000/20 = 50 ticks per second;
@@ -131,8 +131,8 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
   //<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>
   const anna::xml::Attribute  *id, *dictionary;
 
   //<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>
   const anna::xml::Attribute  *id, *dictionary;
 
-  // <!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost 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>
-  const anna::xml::Attribute  *originRealm, *appId, *originHost, *cer, *dwr, *allowedInactivityTime, *tcpConnectDelay,
+  // <!ATTLIST node originRealm CDATA #REQUIRED originHost 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>
+  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;
                               *answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions,
                               *diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection,
                               *retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog;
@@ -149,6 +149,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;
   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;
 
   for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
     std::string nodeName = (*it)->getName();
 
   for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
     std::string nodeName = (*it)->getName();
@@ -157,32 +159,44 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       // Input data:
       id = (*it)->getAttribute("id");
       dictionary = (*it)->getAttribute("dictionary");
       // Input data:
       id = (*it)->getAttribute("id");
       dictionary = (*it)->getAttribute("dictionary");
+      id_value = id->getIntegerValue();
 
       try {
 
       try {
-        d = stackEngine.createDictionary(id->getIntegerValue(), dictionary->getValue());
+        d = stackEngine.createDictionary(id_value, dictionary->getValue());
         getCodecEngine()->setDictionary(d);
 
         // OAM module for counters:
         getCodecEngine()->setDictionary(d);
 
         // OAM module for counters:
-        appMsgOamModule.createStackCounterScope(scope_id, id->getIntegerValue() /* application-id */);
+        appMsgOamModule.createStackCounterScope(scope_id, id_value /* application-id */);
         scope_id++;
 
       } catch(anna::RuntimeException &ex) {
         //_exit(ex.asString());
         throw ex;
       }
         scope_id++;
 
       } catch(anna::RuntimeException &ex) {
         //_exit(ex.asString());
         throw ex;
       }
+
+      if (id_value == 0)
+        id_0_registered = true;
+        a_baseProtocolDictionary = d;
     }
   }
 
   // Show loaded stacks:
   std::cout << "Stacks currently loaded:" << std::endl;
     }
   }
 
   // Show loaded stacks:
   std::cout << "Stacks currently loaded:" << std::endl;
-  std::cout << anna::functions::tab(stackEngine.asString(false /* light */));
-  std::cout << std::endl;
+  std::cout << anna::functions::tab(stackEngine.asString(false /* light */)) << std::endl;
 
 
   // Codec engine adjustments:
   // Auto stack selection based on Application-ID:
   bool multistack = (stackEngine.stack_size() > 1);
 
 
   // Codec engine adjustments:
   // Auto stack selection based on Application-ID:
   bool multistack = (stackEngine.stack_size() > 1);
-  if (multistack) getCodecEngine()->selectStackWithApplicationId(true);
+  if (multistack) {
+    getCodecEngine()->selectStackWithApplicationId(true);
+    // In multistack, id = 0 MUST be registered:
+    if (!id_0_registered)
+      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;
+  }
 
   for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
     std::string nodeName = (*it)->getName();
 
   for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
     std::string nodeName = (*it)->getName();
@@ -190,7 +204,6 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
     if(nodeName == "node") {
       // Input data:
       originRealm = (*it)->getAttribute("originRealm");
     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 */);
       originHost = (*it)->getAttribute("originHost", false /* no exception */);
       cer = (*it)->getAttribute("cer", false /* no exception */);
       dwr = (*it)->getAttribute("dwr", false /* no exception */);
@@ -213,10 +226,6 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       burstLog = (*it)->getAttribute("burstLog", false /* no exception */); // (yes | no)
 
       // Basic checkings:
       burstLog = (*it)->getAttribute("burstLog", false /* no exception */); // (yes | no)
 
       // Basic checkings:
-      if (stackEngine.getDictionary(appId->getIntegerValue()) == NULL) {
-        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);
-      }
       realm_nodes_it nodeIt = a_nodes.find(originRealm->getValue());
       if (nodeIt != a_nodes.end()) {
         std::string msg = "Already registered node name (Origin-Realm): "; msg += originRealm->getValue();
       realm_nodes_it nodeIt = a_nodes.find(originRealm->getValue());
       if (nodeIt != a_nodes.end()) {
         std::string msg = "Already registered node name (Origin-Realm): "; msg += originRealm->getValue();
@@ -251,7 +260,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOp
       }
 
       // Create new Node instance /////////////////////////////////////////////////////////////////
       }
 
       // Create new Node instance /////////////////////////////////////////////////////////////////
-      a_workingNode = new RealmNode(originRealm->getValue(), appId->getIntegerValue(), a_codecEngine);
+      a_workingNode = new RealmNode(originRealm->getValue(), a_codecEngine, a_baseProtocolDictionary);
       MyDiameterEngine *commEngine = a_workingNode->getMyDiameterEngine();
       /////////////////////////////////////////////////////////////////////////////////////////////
 
       MyDiameterEngine *commEngine = a_workingNode->getMyDiameterEngine();
       /////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -730,6 +739,7 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) {
     msg += "')";
     anna::Logger::notice(msg, ANNA_FILE_LOCATION);
   );
     msg += "')";
     anna::Logger::notice(msg, ANNA_FILE_LOCATION);
   );
+
   // Operation:
   std::string line;
   std::string response_content;
   // Operation:
   std::string line;
   std::string response_content;
@@ -753,7 +763,7 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) {
       ex.trace();
     }
 
       ex.trace();
     }
 
-    out_file << response_content;
+    out_file << response_content << "\n";
   }
 
   in_file.close();
   }
 
   in_file.close();
@@ -806,27 +816,53 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\nStart the launcher process without arguments in order to see all the startup configuration";
   result += "\n posibilities, many of which could be modified on the air through the management interface";
   result += "\n";
   result += "\nStart the launcher process without arguments in order to see all the startup configuration";
   result += "\n posibilities, many of which could be modified on the air through the management interface";
-  result += "\n (we will talk later about this great feature). Some of the more common parameters are:";
+  result += "\n (we will talk later about this great feature). There is only one mandatory parameter which";
+  result += "\n is the services definition: --services <services xml file>. You must follow the dtd schema";
+  result += "\n to build a valid services xml file. Some basic examples are:";
+  result += "\n";
+  result += "\nClient configuration:";
+  result += "\n";
+  result += "\n<services>";
+  result += "\n  <!-- Stacks -->";
+  result += "\n  <stack id=\"0\" dictionary=\"dictionary.xml\"/>";
   result += "\n";
   result += "\n";
-  result += "\nAs mandatory, the stacks enabled given through the applicationId and the xml dictionary:";
-  result += "\n   --stacks <appid1,dictionary1#appid2,dictionary2#...#appidN,dictionaryN>";
+  result += "\n  <!-- Nodes -->";
+  result += "\n  <node originRealm=\"ADML-client\" entity=\"localhost:3868\"/>";
+  result += "\n</services>";
   result += "\n";
   result += "\n";
-  result += "\nActing as a diameter server (accepting i.e. 10 connections), you would have:";
-  result += "\n   --diameterServer localhost:3868 --diameterServerSessions 10 --entityServerSessions 0";
+  result += "\nServer configuration:";
   result += "\n";
   result += "\n";
-  result += "\nActing as a diameter client (launching i.e. 10 connections to each entity server), you would have:";
-  result += "\n   --entity 192.168.12.11:3868,192.168.12.21:3868 --entityServerSessions 10 --diameterServerSessions 0";
+  result += "\n<services>";
+  result += "\n  <!-- Stacks -->";
+  result += "\n  <stack id=\"0\" dictionary=\"dictionary.xml\"/>";
+  result += "\n";
+  result += "\n  <!-- Nodes -->";
+  result += "\n  <node originRealm=\"ADML-server\" diameterServer=\"localhost:3868\"/>";
+  result += "\n</services>";
   result += "\n";
   result += "\nIf you act as a proxy or a translation agent, you need to combine both former setups, and probably";
   result += "\n will need to program the answers to be replied through the operations interface. To balance the";
   result += "\n traffic at your client side you shall use '--balance' and '--sessionBasedModelsClientSocketSelection'";
   result += "\n";
   result += "\nIf you act as a proxy or a translation agent, you need to combine both former setups, and probably";
   result += "\n will need to program the answers to be replied through the operations interface. To balance the";
   result += "\n traffic at your client side you shall use '--balance' and '--sessionBasedModelsClientSocketSelection'";
-  result += "\n arguments in order to define the balancing behaviour.";
+  result += "\n arguments in order to define the balancing behaviour. To make hybrid setups you only must mix the realms:";
   result += "\n";
   result += "\n";
-  result += "\nThe process builds automatically CER and DWR messages as a client, but you could specify your own";
-  result += "\n customized ones using '--cer <xml message file>' and '--dwr <xml message file>'.";
-  result += "\nThe process builds automatically CEA and DWA messages as a server, but you could program your own";
-  result += "\n customized ones using operations interface.";
+  result += "\nClient and server configuration:";
+  result += "\n";
+  result += "\n<services>";
+  result += "\n  <!-- Stacks -->";
+  result += "\n  <stack id=\"16777236\" dictionary=\"dictionary_Rx.xml\"/>";
+  result += "\n  <stack id=\"16777238\" dictionary=\"dictionary_Gx.xml\"/>";
+  result += "\n  <stack id=\"0\" dictionary=\"dictionary_base.xml\"/>";
   result += "\n";
   result += "\n";
+  result += "\n  <!-- Nodes -->";
+  result += "\n  <node originRealm=\"ADML-Rx-client\" entity=\"localhost:3868\" cer=\"cer_Rx.xml\"/>";
+  result += "\n  <node originRealm=\"ADML-Gx-client\" entity=\"localhost:3868\" cer=\"cer_Gx.xml\"/>";
+  result += "\n</services>";
+  result += "\n";
+  result += "\n";
+  result += "\nThe process builds automatically CER and DWR messages as a client, but you could specify your own";
+  result += "\n as shown in the hybrid former example. Note that the base protocol stack must be registered because";
+  result += "\n the configuration corresponds to a multistack process which change the stack using the application-id";
+  result += "\n processed (0 in the case of base protocol messages: CER, CEA, DWR, DWA, DPR, DPA).";
   result += "\n";
   result += "\nDYNAMIC OPERATIONS";
   result += "\n------------------";
   result += "\n";
   result += "\nDYNAMIC OPERATIONS";
   result += "\n------------------";
@@ -837,13 +873,13 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\n--------------------------------------------------------------------------------------- General purpose";
   result += "\n";
   result += "\n";
   result += "\n--------------------------------------------------------------------------------------- General purpose";
   result += "\n";
-  result += "\nhelp                                 This help. Startup information-level traces also dump this help.";
+  result += "\nhelp                                 This help.";
   result += "\n";
   result += "\n---------------------------------------------------------------------------------------- Node selection";
   result += "\n";
   result += "\nnode[|<name>]                         Select current working node by mean the registered name.";
   result += "\n                                      All the subsequent operations will be referred to this node.";
   result += "\n";
   result += "\n---------------------------------------------------------------------------------------- Node selection";
   result += "\n";
   result += "\nnode[|<name>]                         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 is dumped on stdout.";
+  result += "\n                                      Without argument, the current node information is retrieved.";
   result += "\n";
   result += "\n------------------------------------------------------------------------------------ Parsing operations";
   result += "\n";
   result += "\n";
   result += "\n------------------------------------------------------------------------------------ Parsing operations";
   result += "\n";
@@ -1241,11 +1277,14 @@ std::string Launcher::help() const throw() {
   result += "\n interface.";
   result += "\n";
   result += "\n";
   result += "\n interface.";
   result += "\n";
   result += "\n";
+
   return result;
 }
 
 void Launcher::eventOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tm("Launcher", "eventOperation", ANNA_FILE_LOCATION));
   return result;
 }
 
 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
+
   CommandLine& cl(anna::CommandLine::instantiate());
   TestManager &testManager = TestManager::instantiate();
   LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION));
   CommandLine& cl(anna::CommandLine::instantiate());
   TestManager &testManager = TestManager::instantiate();
   LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION));
@@ -1253,21 +1292,17 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   // Default response:
   response_content = "Operation processed with exception (see traces): ";
   response_content += operation;
   // Default response:
   response_content = "Operation processed with exception (see traces): ";
   response_content += operation;
-  response_content += "\n";
 
 
-  std::string result_msg = "";
-  anna::DataBlock db_aux(true);
 
 
+  std::string opt_response_content = ""; // aditional response content
+  anna::DataBlock db_aux(true);
 
   ///////////////////////////////////////////////////////////////////
   // Simple operations without arguments:
 
   // Help:
   if(operation == "help") {
 
   ///////////////////////////////////////////////////////////////////
   // Simple operations without arguments:
 
   // Help:
   if(operation == "help") {
-    std::string s_help = help();
-    std::cout << s_help << std::endl;
-    LOGINFORMATION(anna::Logger::information(s_help, ANNA_FILE_LOCATION));
-    response_content = "Help dumped on stdout and information-level traces\n";
+    response_content = help();
     return;
   }
 
     return;
   }
 
@@ -1275,14 +1310,14 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   if(operation == "collect") {
     resetCounters();
     resetStatistics();
   if(operation == "collect") {
     resetCounters();
     resetStatistics();
-    response_content = "All process counters & statistic information have been reset\n";
+    response_content = "All process counters & statistic information have been reset";
     return;
   }
 
   // Counters dump on demand:
   if(operation == "forceCountersRecord") {
     forceCountersRecord();
     return;
   }
 
   // Counters dump on demand:
   if(operation == "forceCountersRecord") {
     forceCountersRecord();
-    response_content = "Current counters have been dump to disk\n";
+    response_content = "Current counters have been dump to disk";
     return;
   }
 
     return;
   }
 
@@ -1351,7 +1386,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   if(opType == "context") {
     std::string contextFile = ((numParams == 1) ? param1 : anna::functions::asString("/var/tmp/anna.context.%05d", getPid()));
     writeContext(contextFile);
   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'\n", contextFile.c_str());
+    response_content = anna::functions::asString("Context dumped on file '%s'", contextFile.c_str());
     return;
   }
 
     return;
   }
 
@@ -1362,20 +1397,20 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     catch(anna::RuntimeException &ex) {
       ex.trace();
     }
     catch(anna::RuntimeException &ex) {
       ex.trace();
-      response_content = anna::functions::asString("Loaded services from file '%s' with some problems (ignored ones)\n", servicesFile.c_str());
+      response_content = anna::functions::asString("Loaded services from file '%s' with some problems (ignored ones)", servicesFile.c_str());
       return;
     }
       return;
     }
-    response_content = anna::functions::asString("Loaded services from file '%s'\n", servicesFile.c_str());
+    response_content = anna::functions::asString("Loaded services from file '%s'", servicesFile.c_str());
     return;
   }
 
   // Realm switch:
   if(opType == "node") {
     if (param1 != "") {
     return;
   }
 
   // Realm switch:
   if(opType == "node") {
     if (param1 != "") {
-      if (setWorkingNode(param1)) response_content = anna::functions::asString("Current node is now '%s'\n", param1.c_str());
+      if (setWorkingNode(param1)) response_content = anna::functions::asString("Current node is now '%s'", param1.c_str());
     }
     else {
     }
     else {
-      std::cout << getWorkingNode()->asXMLString() << std::endl;
+      response_content = getWorkingNode()->asXMLString();
     }
     return;
   }
     }
     return;
   }
@@ -1420,9 +1455,9 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
         if(opType == "show") commEngine->findClientSession(key)->show();
 
 
         if(opType == "show") commEngine->findClientSession(key)->show();
 
-        if(opType == "hidden") result_msg = commEngine->findClientSession(key)->hidden() ? "true" : "false";
+        if(opType == "hidden") opt_response_content = commEngine->findClientSession(key)->hidden() ? "true" : "false";
 
 
-        if(opType == "shown") result_msg = commEngine->findClientSession(key)->shown() ? "true" : "false";
+        if(opType == "shown") opt_response_content = commEngine->findClientSession(key)->shown() ? "true" : "false";
       } else {
         std::string address;
         int port;
       } else {
         std::string address;
         int port;
@@ -1432,18 +1467,18 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
         if(opType == "show") commEngine->findServer(address, port)->show();
 
 
         if(opType == "show") commEngine->findServer(address, port)->show();
 
-        if(opType == "hidden") result_msg = commEngine->findServer(address, port)->hidden() ? "true" : "false";
+        if(opType == "hidden") opt_response_content = commEngine->findServer(address, port)->hidden() ? "true" : "false";
 
 
-        if(opType == "shown") result_msg = commEngine->findServer(address, port)->shown() ? "true" : "false";
+        if(opType == "shown") opt_response_content = commEngine->findServer(address, port)->shown() ? "true" : "false";
       }
     } else {
       if(opType == "hide") entity->hide();
 
       if(opType == "show") entity->show();
 
       }
     } else {
       if(opType == "hide") entity->hide();
 
       if(opType == "show") entity->show();
 
-      if(opType == "hidden") result_msg = entity->hidden() ? "true" : "false";
+      if(opType == "hidden") opt_response_content = entity->hidden() ? "true" : "false";
 
 
-      if(opType == "shown") result_msg = entity->shown() ? "true" : "false";
+      if(opType == "shown") opt_response_content = entity->shown() ? "true" : "false";
     }
   } else if((opType == "sendxml") || (opType == "sendxml2e") || (opType == "sendhex") || (opType == "sendhex2e")) {
     if(!entity) throw anna::RuntimeException("No entity configured to send the message", ANNA_FILE_LOCATION);
     }
   } else if((opType == "sendxml") || (opType == "sendxml2e") || (opType == "sendhex") || (opType == "sendhex2e")) {
     if(!entity) throw anna::RuntimeException("No entity configured to send the message", ANNA_FILE_LOCATION);
@@ -1490,9 +1525,9 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     // burst|look|<order>              Show programmed burst message for order provided, current when missing.
 
     if(param1 == "clear") {
     // burst|look|<order>              Show programmed burst message for order provided, current when missing.
 
     if(param1 == "clear") {
-      result_msg = "removed ";
-      result_msg += anna::functions::asString(getWorkingNode()->clearBurst());
-      result_msg += " elements";
+      opt_response_content = "removed ";
+      opt_response_content += anna::functions::asString(getWorkingNode()->clearBurst());
+      opt_response_content += " elements";
     } else if(param1 == "load") {
       if(param2 == "") throw anna::RuntimeException("Missing xml path file for burst load operation", ANNA_FILE_LOCATION);
 
     } else if(param1 == "load") {
       if(param2 == "") throw anna::RuntimeException("Missing xml path file for burst load operation", ANNA_FILE_LOCATION);
 
@@ -1502,10 +1537,10 @@ void 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 = getWorkingNode()->loadBurstMessage(codecMsg.code());
       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 = getWorkingNode()->loadBurstMessage(codecMsg.code());
-      result_msg = "loaded '";
-      result_msg += param2;
-      result_msg += "' file into burst list position ";
-      result_msg += anna::functions::asString(position);
+      opt_response_content = "loaded '";
+      opt_response_content += param2;
+      opt_response_content += "' file into burst list position ";
+      opt_response_content += anna::functions::asString(position);
     } else if(param1 == "start") {
       if(param2 == "") throw anna::RuntimeException("Missing initial load for burst start operation", ANNA_FILE_LOCATION);
 
     } else if(param1 == "start") {
       if(param2 == "") throw anna::RuntimeException("Missing initial load for burst start operation", ANNA_FILE_LOCATION);
 
@@ -1513,8 +1548,8 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       int processed = getWorkingNode()->startBurst(initialLoad);
 
       if(processed > 0) {
       int processed = getWorkingNode()->startBurst(initialLoad);
 
       if(processed > 0) {
-        result_msg = "initial load completed for ";
-        result_msg += anna::functions::entriesAsString(processed, "message");
+        opt_response_content = "initial load completed for ";
+        opt_response_content += anna::functions::entriesAsString(processed, "message");
       }
     } else if(param1 == "push") {
       if(param2 == "") throw anna::RuntimeException("Missing load amount for burst push operation", ANNA_FILE_LOCATION);
       }
     } else if(param1 == "push") {
       if(param2 == "") throw anna::RuntimeException("Missing load amount for burst push operation", ANNA_FILE_LOCATION);
@@ -1522,8 +1557,8 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       int pushed = getWorkingNode()->pushBurst(atoi(param2.c_str()));
 
       if(pushed > 0) {
       int pushed = getWorkingNode()->pushBurst(atoi(param2.c_str()));
 
       if(pushed > 0) {
-        result_msg = "pushed ";
-        result_msg += anna::functions::entriesAsString(pushed, "message");
+        opt_response_content = "pushed ";
+        opt_response_content += anna::functions::entriesAsString(pushed, "message");
       }
     } else if(param1 == "pop") {
       if(param2 == "") throw anna::RuntimeException("Missing amount for burst pop operation", ANNA_FILE_LOCATION);
       }
     } else if(param1 == "pop") {
       if(param2 == "") throw anna::RuntimeException("Missing amount for burst pop operation", ANNA_FILE_LOCATION);
@@ -1532,39 +1567,39 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       int popped = getWorkingNode()->popBurst(releaseLoad);
 
       if(popped > 0) {
       int popped = getWorkingNode()->popBurst(releaseLoad);
 
       if(popped > 0) {
-        result_msg = "burst popped for ";
-        result_msg += anna::functions::entriesAsString(popped, "message");
+        opt_response_content = "burst popped for ";
+        opt_response_content += anna::functions::entriesAsString(popped, "message");
       }
     } else if(param1 == "stop") {
       int left = getWorkingNode()->stopBurst();
 
       if(left != -1) {
       }
     } else if(param1 == "stop") {
       int left = getWorkingNode()->stopBurst();
 
       if(left != -1) {
-        result_msg += anna::functions::entriesAsString(left, "message");
-        result_msg += " left to the end of the cycle";
+        opt_response_content += anna::functions::entriesAsString(left, "message");
+        opt_response_content += " left to the end of the cycle";
       }
     } else if(param1 == "repeat") {
       if(param2 == "") param2 = "yes";
 
       bool repeat = (param2 == "yes");
       getWorkingNode()->repeatBurst(repeat);
       }
     } else if(param1 == "repeat") {
       if(param2 == "") param2 = "yes";
 
       bool repeat = (param2 == "yes");
       getWorkingNode()->repeatBurst(repeat);
-      result_msg += (repeat ? "repeat enabled" : "repeat disabled");
+      opt_response_content += (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 = getWorkingNode()->sendBurst(atoi(param2.c_str()));
 
       if(sent > 0) {
     } else if(param1 == "send") {
       if(param2 == "") throw anna::RuntimeException("Missing amount for burst send operation", ANNA_FILE_LOCATION);
 
       int sent = getWorkingNode()->sendBurst(atoi(param2.c_str()));
 
       if(sent > 0) {
-        result_msg = "sent ";
-        result_msg += anna::functions::entriesAsString(sent, "message");
+        opt_response_content = "sent ";
+        opt_response_content += anna::functions::entriesAsString(sent, "message");
       }
     } else if(param1 == "goto") {
       if(param2 == "") throw anna::RuntimeException("Missing order position for burst goto operation", ANNA_FILE_LOCATION);
 
       }
     } else if(param1 == "goto") {
       if(param2 == "") throw anna::RuntimeException("Missing order position for burst goto operation", ANNA_FILE_LOCATION);
 
-      result_msg = getWorkingNode()->gotoBurst(atoi(param2.c_str()));
+      opt_response_content = getWorkingNode()->gotoBurst(atoi(param2.c_str()));
     } else if(param1 == "look") {
       int order = ((param2 != "") ? atoi(param2.c_str()) : -1);
     } else if(param1 == "look") {
       int order = ((param2 != "") ? atoi(param2.c_str()) : -1);
-      result_msg = "\n\n";
-      result_msg += getWorkingNode()->lookBurst(order);
+      opt_response_content = "\n\n";
+      opt_response_content += getWorkingNode()->lookBurst(order);
     } else {
       throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). See help", ANNA_FILE_LOCATION);
     }
     } else {
       throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). See help", ANNA_FILE_LOCATION);
     }
@@ -1586,12 +1621,12 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
       bool success = ((param2 != "") ? testManager.configureTTPS(atoi(param2.c_str())) : false);
       if (success) {
 
       bool success = ((param2 != "") ? testManager.configureTTPS(atoi(param2.c_str())) : false);
       if (success) {
-        result_msg = "assigned new test launch rate to ";
-        result_msg += anna::functions::asString(atoi(param2.c_str()));
-        result_msg += " events per second";
+        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";
       }
       else {
       }
       else {
-        result_msg += "unable to configure the test rate provided";
+        opt_response_content += "unable to configure the test rate provided";
       }
     }
     else if(param1 == "ip-limit") {
       }
     }
     else if(param1 == "ip-limit") {
@@ -1602,16 +1637,16 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       if (param2 != "") {
         limit = atoi(param2.c_str());
         testManager.setInProgressLimit(limit);
       if (param2 != "") {
         limit = atoi(param2.c_str());
         testManager.setInProgressLimit(limit);
-        result_msg = "new in-progress limit: ";
-        result_msg += (limit != UINT_MAX) ? anna::functions::asString(limit) : "<no limit>";
+        opt_response_content = "new in-progress limit: ";
+        opt_response_content += (limit != UINT_MAX) ? anna::functions::asString(limit) : "<no limit>";
       }
       else {
       }
       else {
-        result_msg = "in-progress limit amount: ";
+        opt_response_content = "in-progress limit amount: ";
         limit = testManager.getInProgressLimit();
         limit = testManager.getInProgressLimit();
-        result_msg += (limit != UINT_MAX) ? anna::functions::asString(limit) : "<no limit>";
-        result_msg += "; currently there are ";
-        result_msg += anna::functions::asString(testManager.getInProgressCount());
-        result_msg += " test cases running";
+        opt_response_content += (limit != UINT_MAX) ? anna::functions::asString(limit) : "<no limit>";
+        opt_response_content += "; currently there are ";
+        opt_response_content += anna::functions::asString(testManager.getInProgressCount());
+        opt_response_content += " test cases running";
       }
     }
     else if(param1 == "repeat") {
       }
     }
     else if(param1 == "repeat") {
@@ -1620,7 +1655,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
       if(param2 == "") param2 = "yes";
       testManager.setPoolRepeat((param2 == "yes"));
 
       if(param2 == "") param2 = "yes";
       testManager.setPoolRepeat((param2 == "yes"));
-      result_msg += (testManager.getPoolRepeat() ? "repeat enabled" : "repeat disabled");
+      opt_response_content += (testManager.getPoolRepeat() ? "repeat enabled" : "repeat disabled");
     }
     else if(param1 == "report") {
       if (numParams > 2)
     }
     else if(param1 == "report") {
       if (numParams > 2)
@@ -1628,7 +1663,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
       if(param2 == "") param2 = "yes";
       testManager.setDumpReports((param2 == "yes"));
 
       if(param2 == "") param2 = "yes";
       testManager.setDumpReports((param2 == "yes"));
-      result_msg += (testManager.getDumpReports() ? "report enabled" : "report disabled");
+      opt_response_content += (testManager.getDumpReports() ? "report enabled" : "report disabled");
     }
     else if(param1 == "goto") {
       if (numParams > 2)
     }
     else if(param1 == "goto") {
       if (numParams > 2)
@@ -1637,13 +1672,13 @@ void 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)) {
       if(param2 == "") throw anna::RuntimeException("Missing id for test goto operation", ANNA_FILE_LOCATION);
       int id = atoi(param2.c_str());
       if (testManager.gotoTestCase(id)) {
-        result_msg = "position updated for id provided (";
+        opt_response_content = "position updated for id provided (";
       }
       else {
       }
       else {
-        result_msg = "cannot found test id (";
+        opt_response_content = "cannot found test id (";
       }
       }
-      result_msg += anna::functions::asString(id);
-      result_msg += ")";
+      opt_response_content += anna::functions::asString(id);
+      opt_response_content += ")";
     }
     else if(param1 == "look") {
       if (numParams > 2)
     }
     else if(param1 == "look") {
       if (numParams > 2)
@@ -1653,17 +1688,17 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       TestCase *testCase = testManager.findTestCase(id);
 
       if (testCase) {
       TestCase *testCase = testManager.findTestCase(id);
 
       if (testCase) {
-        result_msg = "\n\n";
-        result_msg += testCase->asXMLString();
+        response_content = testCase->asXMLString();
+        return;
       }
       else {
         if (id == -1) {
       }
       else {
         if (id == -1) {
-          result_msg = "no current test case detected (testing started ?)";
+          opt_response_content = "no current test case detected (testing started ?)";
         }
         else {
         }
         else {
-          result_msg = "cannot found test id (";
-          result_msg += anna::functions::asString(id);
-          result_msg += ")";
+          opt_response_content = "cannot found test id (";
+          opt_response_content += anna::functions::asString(id);
+          opt_response_content += ")";
         }
       }
     }
         }
       }
     }
@@ -1679,21 +1714,21 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
 
       if (testCase) {
         bool done = testCase->reset((param2 == "hard") ? true:false);
 
       if (testCase) {
         bool done = testCase->reset((param2 == "hard") ? true:false);
-        result_msg = "test ";
-        result_msg += param2;
-        result_msg += " reset for id ";
-        result_msg += anna::functions::asString(id);
-        result_msg += done ? ": done": ": not done";
+        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";
       }
       else {
         if (id == -1) {
           bool anyReset = testManager.resetPool((param2 == "hard") ? true:false);
       }
       else {
         if (id == -1) {
           bool anyReset = testManager.resetPool((param2 == "hard") ? true:false);
-          result_msg = "reset have been sent to all programmed tests: "; result_msg += anyReset ? "some/all was actually reset" : "nothing was reset";
+          opt_response_content = "reset have been sent to all programmed tests: "; opt_response_content += anyReset ? "some/all was actually reset" : "nothing was reset";
         }
         else {
         }
         else {
-          result_msg = "cannot found test id (";
-          result_msg += anna::functions::asString(id);
-          result_msg += ")";
+          opt_response_content = "cannot found test id (";
+          opt_response_content += anna::functions::asString(id);
+          opt_response_content += ")";
         }
       }
     }
         }
       }
     }
@@ -1702,10 +1737,10 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
 
       if (testManager.clearPool()) {
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
 
       if (testManager.clearPool()) {
-        result_msg = "all the programmed test cases have been dropped";
+        opt_response_content = "all the programmed test cases have been dropped";
       }
       else {
       }
       else {
-        result_msg = "there are not programmed test cases to be removed";
+        opt_response_content = "there are not programmed test cases to be removed";
       }
     }
     else {
       }
     }
     else {
@@ -1787,9 +1822,6 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       else {
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
       }
       else {
         throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
       }
-
-      result_msg = "new step added to test id ";
-      result_msg += anna::functions::asString(id);
     }
 
   } else if((opType == "sendxml2c") || (opType == "sendhex2c")) {
     }
 
   } else if((opType == "sendxml2c") || (opType == "sendhex2c")) {
@@ -1821,8 +1853,8 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
     }
   } else if(opType == "loadxml") {
     codecMsg.loadXML(param1);
     }
   } else if(opType == "loadxml") {
     codecMsg.loadXML(param1);
-    std::string xmlString = codecMsg.asXMLString();
-    std::cout << xmlString << std::endl;
+    response_content = codecMsg.asXMLString();
+    return;
   } else if(opType == "diameterServerSessions") {
     int diameterServerSessions = atoi(param1.c_str());
 
   } else if(opType == "diameterServerSessions") {
     int diameterServerSessions = atoi(param1.c_str());
 
@@ -1836,8 +1868,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       throw anna::RuntimeException("Operation not applicable (no own diameter server has been configured)", ANNA_FILE_LOCATION);
 
     if(param1 == "") { // programmed answers FIFO's to stdout
       throw anna::RuntimeException("Operation not applicable (no own diameter server has been configured)", ANNA_FILE_LOCATION);
 
     if(param1 == "") { // programmed answers FIFO's to stdout
-      std::cout << localServer->getReactingAnswers()->asString("ANSWERS TO CLIENT") << std::endl;
-      response_content = "Programmed answers dumped on stdout\n";
+      response_content = localServer->getReactingAnswers()->asString("ANSWERS TO CLIENT");
       return;
     } else if (param1 == "rotate") {
       localServer->getReactingAnswers()->rotate(true);
       return;
     } else if (param1 == "rotate") {
       localServer->getReactingAnswers()->rotate(true);
@@ -1866,8 +1897,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
       throw anna::RuntimeException("Operation not applicable (no diameter entity has been configured)", ANNA_FILE_LOCATION);
 
     if(param1 == "") { // programmed answers FIFO's to stdout
       throw anna::RuntimeException("Operation not applicable (no diameter entity has been configured)", ANNA_FILE_LOCATION);
 
     if(param1 == "") { // programmed answers FIFO's to stdout
-      std::cout << entity->getReactingAnswers()->asString("ANSWERS TO ENTITY") << std::endl;
-      response_content = "Programmed answers dumped on stdout\n";
+      response_content = entity->getReactingAnswers()->asString("ANSWERS TO ENTITY");
       return;
     } else if (param1 == "rotate") {
       entity->getReactingAnswers()->rotate(true);
       return;
     } else if (param1 == "rotate") {
       entity->getReactingAnswers()->rotate(true);
@@ -1896,8 +1926,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   }
 
   // HTTP response
   }
 
   // HTTP response
-  response_content = "Operation correctly processed: "; response_content += operation; response_content += " => ";
-  response_content += result_msg;
+  response_content = "Operation correctly processed: "; response_content += operation;
+  if (opt_response_content != "") {
+    response_content += " => ";
+    response_content += opt_response_content;
+  }
 }
 
 anna::xml::Node* Launcher::asXML(anna::xml::Node* parent) const
 }
 
 anna::xml::Node* Launcher::asXML(anna::xml::Node* parent) const
index 21c3d25..204459a 100644 (file)
@@ -53,6 +53,7 @@ class Launcher : public anna::comm::Application {
   // Core engines:
   MyCommunicator *a_communicator;
   anna::diameter::codec::Engine *a_codecEngine;
   // Core engines:
   MyCommunicator *a_communicator;
   anna::diameter::codec::Engine *a_codecEngine;
+  anna::diameter::stack::Dictionary *a_baseProtocolDictionary;
   anna::timex::Engine* a_timeEngine;
   MyCounterRecorder *a_counterRecorder;
   anna::Millisecond a_admlMinResolution;
   anna::timex::Engine* a_timeEngine;
   MyCounterRecorder *a_counterRecorder;
   anna::Millisecond a_admlMinResolution;
@@ -79,6 +80,7 @@ public:
   void startServices() throw(anna::RuntimeException);
 
   anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
   void startServices() throw(anna::RuntimeException);
 
   anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
+  //anna::diameter::stack::Dictionary *getBaseProtocolDictionary() const throw() { return a_baseProtocolDictionary; }
   RealmNode *getWorkingNode() const throw(anna::RuntimeException); // management operations working node
   bool setWorkingNode(const std::string &name) throw(); // we could update ignoreFlagsOnValidation/integrationAndDebugging over the global codec engine
                                                         //  but finally, that configuration issues will be global to the process.
   RealmNode *getWorkingNode() const throw(anna::RuntimeException); // management operations working node
   bool setWorkingNode(const std::string &name) throw(); // we could update ignoreFlagsOnValidation/integrationAndDebugging over the global codec engine
                                                         //  but finally, that configuration issues will be global to the process.
index 29b3c1b..d7c9b07 100644 (file)
 #include <MyLocalServer.hpp>
 
 
 #include <MyLocalServer.hpp>
 
 
+namespace anna {
+  namespace diameter {
+    namespace stack {
+      class Dictionary;
+    }
+  }
+}
+
 class MyDiameterEngine : public anna::diameter::comm::Engine {
 public:
 
 class MyDiameterEngine : public anna::diameter::comm::Engine {
 public:
 
-  MyDiameterEngine(const char *className = "MyDiameterEngine") : Engine(className, NULL /* we will assign the base protocol codec engine later*/) {;}
+  MyDiameterEngine(const char *className, const anna::diameter::stack::Dictionary *baseProtocolDictionary) : Engine(className, baseProtocolDictionary) {;}
 
 // Default implementation is enough
 //   void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {;} // DPA is not replied
 
 // Default implementation is enough
 //   void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {;} // DPA is not replied
index 630ab8f..d3a2b89 100644 (file)
 #include <RealmNode.hpp>
 #include <MyDiameterEngine.hpp>
 
 #include <RealmNode.hpp>
 #include <MyDiameterEngine.hpp>
 
+namespace anna {
+  namespace diameter {
+    namespace stack {
+      class Dictionary;
+    }
+  }
+}
 
 
-
-RealmNode::RealmNode(const std::string &originRealm, unsigned int applicationId, anna::diameter::codec::Engine *codecEngine) :
-  a_originRealm(originRealm), a_applicationId(applicationId), a_codecEngine(codecEngine) {
+RealmNode::RealmNode(const std::string &originRealm, anna::diameter::codec::Engine *codecEngine, const anna::diameter::stack::Dictionary *baseProtocolDictionary) :
+  a_originRealm(originRealm), a_codecEngine(codecEngine) {
 
   std::string commEngineName = a_originRealm + "_DiameterCommEngine";
 
   std::string commEngineName = a_originRealm + "_DiameterCommEngine";
-  a_commEngine = new MyDiameterEngine(commEngineName.c_str());
+  a_commEngine = new MyDiameterEngine(commEngineName.c_str(), baseProtocolDictionary);
   a_commEngine->setAutoBind(false);  // allow to create client-sessions without binding them, in order to set timeouts.
   a_commEngine->setAutoBind(false);  // allow to create client-sessions without binding them, in order to set timeouts.
-  a_commEngine->setBaseProtocolCodecEngine(getCodecEngine());
 
   a_logFile = "";
   a_burstLogFile = "";
 
   a_logFile = "";
   a_burstLogFile = "";
@@ -56,7 +61,7 @@ RealmNode::RealmNode(const std::string &originRealm, unsigned int applicationId,
 }
 
 
 }
 
 
-void RealmNode::createEntity(const std::string &entityRepresentation, const anna::Millisecond &bindTimeout, const anna::Millisecond &applicationTimeout) throw() {
+void RealmNode::createEntity(const std::string &entityRepresentation, const anna::Millisecond &bindTimeout, const anna::Millisecond &applicationTimeout) throw(anna::RuntimeException) {
 
   anna::socket_v servers = anna::functions::getSocketVectorFromString(entityRepresentation);
   std::string entityDescription = "Launcher diameter entity for "; entityDescription += a_originRealm;
 
   anna::socket_v servers = anna::functions::getSocketVectorFromString(entityRepresentation);
   std::string entityDescription = "Launcher diameter entity for "; entityDescription += a_originRealm;
@@ -402,7 +407,6 @@ throw() {
   anna::xml::Node* result = parent->createChild("RealmNode");
 
   result->createAttribute("OriginRealm", a_originRealm);
   anna::xml::Node* result = parent->createChild("RealmNode");
 
   result->createAttribute("OriginRealm", a_originRealm);
-  result->createAttribute("ApplicationId", a_applicationId);
   result->createAttribute("LogFile", a_logFile);
   result->createAttribute("SplitLog", a_splitLog ? "yes" : "no");
   result->createAttribute("DetailedLog", a_detailedLog ? "yes" : "no");
   result->createAttribute("LogFile", a_logFile);
   result->createAttribute("SplitLog", a_splitLog ? "yes" : "no");
   result->createAttribute("DetailedLog", a_detailedLog ? "yes" : "no");
index a8a49fd..774e858 100644 (file)
@@ -25,6 +25,9 @@ namespace anna {
     namespace codec {
       class Engine;
     }
     namespace codec {
       class Engine;
     }
+    namespace stack {
+      class Dictionary;
+    }
     namespace comm {
       class Message;
     }
     namespace comm {
       class Message;
     }
@@ -50,7 +53,6 @@ class RealmNode {
 
   // main
   std::string a_originRealm;
 
   // main
   std::string a_originRealm;
-  unsigned int a_applicationId;
 
   // Timming
   anna::Millisecond a_allowedInactivityTime;
 
   // Timming
   anna::Millisecond a_allowedInactivityTime;
@@ -74,13 +76,13 @@ class RealmNode {
   int a_burstPopCounter;
 
 public:
   int a_burstPopCounter;
 
 public:
-  RealmNode(const std::string &originRealm, unsigned int applicationId, anna::diameter::codec::Engine *codecEngine);
+  RealmNode(const std::string &originRealm, anna::diameter::codec::Engine *codecEngine, const anna::diameter::stack::Dictionary *baseProtocolDictionary);
   ~RealmNode() {;}
 
   // Core resources:
   MyDiameterEngine* getMyDiameterEngine() const throw() { return a_commEngine; }
   anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
   ~RealmNode() {;}
 
   // Core resources:
   MyDiameterEngine* getMyDiameterEngine() const throw() { return a_commEngine; }
   anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
-  void createEntity(const std::string &entityRepresentation, const anna::Millisecond &bindTimeout, const anna::Millisecond &applicationTimeout) throw();
+  void createEntity(const std::string &entityRepresentation, const anna::Millisecond &bindTimeout, const anna::Millisecond &applicationTimeout) throw(anna::RuntimeException);
   MyDiameterEntity *getEntity() const throw() { return a_entity; }
   void startDiameterServer(const std::string &serverRepresentation, int sessions, const anna::Millisecond &inactivityTimeout) throw(anna::RuntimeException);
   MyLocalServer* getDiameterServer() throw() { return a_diameterServer; }
   MyDiameterEntity *getEntity() const throw() { return a_entity; }
   void startDiameterServer(const std::string &serverRepresentation, int sessions, const anna::Millisecond &inactivityTimeout) throw(anna::RuntimeException);
   MyLocalServer* getDiameterServer() throw() { return a_diameterServer; }
index 8c9ce85..d312981 100755 (executable)
@@ -18,10 +18,10 @@ PID=`cat .pid`
 
 # Send operation:
 [ "$1" = "" ] && _exit "Usage: $0 <operation string>; i.e.: $0 help"
 
 # Send operation:
 [ "$1" = "" ] && _exit "Usage: $0 <operation string>; i.e.: $0 help"
-echo $1 > sigusr2.tasks.input
+echo $1 > sigusr2.in
 kill -s SIGUSR2 $PID
 
 kill -s SIGUSR2 $PID
 
-#echo "You could see results on '`pwd`/sigusr2.tasks.output' file."
-cat `pwd`/sigusr2.tasks.output 2>/dev/null
+#echo "You could see results on '`pwd`/sigusr2.out' file."
+cat `pwd`/sigusr2.out 2>/dev/null
 echo
 
 echo
 
index d7bfbc6..a7d3f30 100644 (file)
@@ -3,7 +3,7 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-balancer" applicationId="0" entity="192.168.12.11:3868,192.168.12.21:3868" diameterServer="localhost:3868" balance="yes"/>
-  <!-- <node originRealm="ADML-proxy" applicationId="0" entity="localhost:3868" diameterServer="localhost:3870"/> -->
+  <node originRealm="ADML-balancer" entity="192.168.12.11:3868,192.168.12.21:3868" diameterServer="localhost:3868" balance="yes"/>
+  <!-- <node originRealm="ADML-proxy" entity="localhost:3868" diameterServer="localhost:3870"/> -->
 </services>
 
 </services>
 
index dfbb943..4c5e019 100644 (file)
@@ -3,6 +3,6 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-client" applicationId="0" entity="localhost:3868"/>
+  <node originRealm="ADML-client" entity="localhost:3868"/>
 </services>
 
 </services>
 
index f1602be..c09c529 100644 (file)
@@ -3,6 +3,6 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-dummy" applicationId="0"/>
+  <node originRealm="ADML-dummy"/>
 </services>
 
 </services>
 
index 795143f..a47db65 100644 (file)
@@ -3,11 +3,12 @@
   <stack id="16777236" dictionary="dictionaryRx.xml"/>
   <stack id="16777238" dictionary="dictionaryGx.xml"/>
   <stack id="16777302" dictionary="dictionarySy.xml"/>
   <stack id="16777236" dictionary="dictionaryRx.xml"/>
   <stack id="16777238" dictionary="dictionaryGx.xml"/>
   <stack id="16777302" dictionary="dictionarySy.xml"/>
+  <stack id="0" dictionary="dictionaryBase.xml"/>
 
   <!-- Nodes -->
 
   <!-- Nodes -->
-  <node originRealm="afNode" applicationId="16777236" entity="192.168.12.11:3868,192.168.12.21:3868"/>
-  <node originRealm="ggsnNode" applicationId="16777238" entity="192.168.12.11:3868,192.168.12.21:3868"/>
-  <node originRealm="ggsn2Node" applicationId="16777238" entity="192.168.12.11:3868,192.168.12.21:3868"/>
-  <node originRealm="ocsNode" applicationId="16777302" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="afNode" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="ggsnNode" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="ggsn2Node" entity="192.168.12.11:3868,192.168.12.21:3868"/>
+  <node originRealm="ocsNode" entity="192.168.12.11:3868,192.168.12.21:3868"/>
 </services>
 
 </services>
 
index c257afc..e615c4a 100644 (file)
@@ -3,6 +3,6 @@
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
   <stack id="0" dictionary="dictionary.xml"/>
 
   <!-- Nodes -->
-  <node originRealm="ADML-server" applicationId="0" diameterServer="localhost:3868"/>
+  <node originRealm="ADML-server" diameterServer="localhost:3868"/>
 </services>
 
 </services>
 
index 05edb86..6dd31ed 100755 (executable)
@@ -8,19 +8,18 @@
 <!--
    Stack record
 
 <!--
    Stack record
 
-   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed.
+   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed
                (in multistack applications, it shall be mandatory respect such association to know the stack used
                for processed messages).
    dictionary: Path to the dictionary file
 -->
 
 <!ELEMENT node EMPTY>
                (in multistack applications, it shall be mandatory respect such association to know the stack used
                for processed messages).
    dictionary: Path to the dictionary file
 -->
 
 <!ELEMENT node EMPTY>
-<!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost 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>
+<!ATTLIST node originRealm CDATA #REQUIRED originHost 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>
 <!--
    Node record
 
    originRealm:                             Node identifier (Origin-Realm name).
 <!--
    Node record
 
    originRealm:                             Node identifier (Origin-Realm name).
-   applicationId:                           The Application-Id provided must exists as a registered 'stack id'.
    originHost:                              Diameter application host name (system name). If missing, process sets o.s. hostname
                                             Note that if you have two or more realms, the names must be different.
    cer:                                     User defined CER path file to be encoded to establish diameter connections.
    originHost:                              Diameter application host name (system name). If missing, process sets o.s. hostname
                                             Note that if you have two or more realms, the names must be different.
    cer:                                     User defined CER path file to be encoded to establish diameter connections.
index ccb9b42..1c5beeb 100644 (file)
@@ -343,6 +343,7 @@ TestStepWait *TestCase::searchNextWaitConditionFulfilled(const anna::DataBlock &
   TestStepWait *result;
   for (std::vector<TestStep*>::const_iterator it = a_stepsIt /* current */; it != a_steps.end(); it++) {
     if ((*it)->getType() != TestStep::Type::Wait) continue;
   TestStepWait *result;
   for (std::vector<TestStep*>::const_iterator it = a_stepsIt /* current */; it != a_steps.end(); it++) {
     if ((*it)->getType() != TestStep::Type::Wait) continue;
+    if ((*it)->isCompleted()) continue;
     result = (TestStepWait*)(*it);
     if ((result->getCondition().receivedFromEntity() == waitFromEntity) && (result->fulfilled(message)))
       return result;
     result = (TestStepWait*)(*it);
     if ((result->getCondition().receivedFromEntity() == waitFromEntity) && (result->fulfilled(message)))
       return result;
index ca45e9c..97a0d4f 100644 (file)
@@ -232,6 +232,7 @@ bool TestManager::tick() throw() {
     return false;
   }
 
     return false;
   }
 
+  // Synchronous sendings per tick:
   int count = a_synchronousAmount;
   while (count > 0) {
     if (!nextTestCase()) return false; // stop the clock
   int count = a_synchronousAmount;
   while (count > 0) {
     if (!nextTestCase()) return false; // stop the clock
@@ -271,21 +272,29 @@ bool TestManager::nextTestCase() throw() {
       }
     }
 
       }
     }
 
-    // Hard reset, because normally a cycle takes more time that a single test case lifetime. We can consider that never
-    //  going to break a in-progress test case due to cycle repeat
+    // Soft reset to initialize already finished (in previous cycle) test cases:
     a_currentTestIt->second->reset(false);
 
     // Process test case:
     LOGDEBUG(anna::Logger::debug(anna::functions::asString("Processing test case id = %llu, currently '%s' state", a_currentTestIt->first, TestCase::asText(a_currentTestIt->second->getState())), ANNA_FILE_LOCATION));
     if (a_currentTestIt->second->getState() != TestCase::State::InProgress) {
       a_currentTestIt->second->process();
     a_currentTestIt->second->reset(false);
 
     // Process test case:
     LOGDEBUG(anna::Logger::debug(anna::functions::asString("Processing test case id = %llu, currently '%s' state", a_currentTestIt->first, TestCase::asText(a_currentTestIt->second->getState())), ANNA_FILE_LOCATION));
     if (a_currentTestIt->second->getState() != TestCase::State::InProgress) {
       a_currentTestIt->second->process();
-      return true;
+      return true; // is not probably to reach still In-Progress test cases from previous cycles due to the whole
+                   //  time for complete the test cases pool regarding the single test case lifetime. You shouldn't
+                   //  forget to programm a test case timeout with a reasonable value
     }
   }
 }
 
     }
   }
 }
 
-TestCase *TestManager::getTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) throw(anna::RuntimeException) {
-  sessionId = anna::diameter::helpers::base::functions::getSessionId(message);
+TestCase *TestManager::getTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) throw() {
+  try {
+    sessionId = anna::diameter::helpers::base::functions::getSessionId(message);
+  }
+  catch (anna::RuntimeException &ex) {
+    //ex.trace();
+    LOGWARNING(anna::Logger::warning("Cannot get the Session-Id from received DataBlock in order to identify the Test Case", ANNA_FILE_LOCATION));
+    return NULL;
+  }
   std::map<std::string /* session id's */, TestCase*>::const_iterator sessionIdIt = a_sessionIdTestCaseMap.find(sessionId);
   if (sessionIdIt != a_sessionIdTestCaseMap.end())
     return sessionIdIt->second;
   std::map<std::string /* session id's */, TestCase*>::const_iterator sessionIdIt = a_sessionIdTestCaseMap.find(sessionId);
   if (sessionIdIt != a_sessionIdTestCaseMap.end())
     return sessionIdIt->second;
index 313e15f..614cb1e 100644 (file)
@@ -117,7 +117,7 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
     TestCase *getTestCase(unsigned int id) throw(); // creates/reuses a test case
 
     // Main logic
     TestCase *getTestCase(unsigned int id) throw(); // creates/reuses a test case
 
     // Main logic
-    TestCase *getTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) throw(anna::RuntimeException);
+    TestCase *getTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) throw();
     void receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException);
     void receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException);
 
     void receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ClientSession *clientSession) throw(anna::RuntimeException);
     void receiveMessage(const anna::DataBlock &message, const anna::diameter::comm::ServerSession *serverSession) throw(anna::RuntimeException);
 
index 076a227..c4ec2e5 100644 (file)
@@ -75,20 +75,20 @@ std::string TestStep::asXMLString() const throw() {
 }
 
 bool TestStep::execute() throw() {
 }
 
 bool TestStep::execute() throw() {
-  LOGDEBUG(anna::Logger::debug(anna::functions::asString("EXECUTING %s for Test Case %llu (%p) (%p)", asText(a_type), a_testCase->getId(), (TestCaseStep*)this, this), ANNA_FILE_LOCATION));
+  LOGDEBUG(anna::Logger::debug(anna::functions::asString("EXECUTING %s (step number %d) for Test Case %llu (%p) (%p)", asText(a_type), a_number, a_testCase->getId(), (TestCaseStep*)this, this), ANNA_FILE_LOCATION));
   setBeginTimestamp(anna::functions::millisecond());
   return do_execute();
 }
 
 void TestStep::complete() throw() {
   setBeginTimestamp(anna::functions::millisecond());
   return do_execute();
 }
 
 void TestStep::complete() throw() {
-  LOGDEBUG(anna::Logger::debug(anna::functions::asString("COMPLETE %s for Test Case %llu (%p) (%p)", asText(a_type), a_testCase->getId(), (TestCaseStep*)this, this), ANNA_FILE_LOCATION));
+  LOGDEBUG(anna::Logger::debug(anna::functions::asString("COMPLETE %s (step number %d) for Test Case %llu (%p) (%p)", asText(a_type), a_number, a_testCase->getId(), (TestCaseStep*)this, this), ANNA_FILE_LOCATION));
   a_completed = true;
   setEndTimestamp(anna::functions::millisecond());
   do_complete();
 }
 
 void TestStep::reset() throw() {
   a_completed = true;
   setEndTimestamp(anna::functions::millisecond());
   do_complete();
 }
 
 void TestStep::reset() throw() {
-  LOGDEBUG(anna::Logger::debug(anna::functions::asString("RESET %s for Test Case %llu (%p) (%p)", asText(a_type), a_testCase->getId(), (TestCaseStep*)this, this), ANNA_FILE_LOCATION));
+  LOGDEBUG(anna::Logger::debug(anna::functions::asString("RESET %s (step number %d) for Test Case %llu (%p) (%p)", asText(a_type), a_number, a_testCase->getId(), (TestCaseStep*)this, this), ANNA_FILE_LOCATION));
   // type and testCase kept
   a_completed = false;
   a_beginTimestamp = 0;
   // type and testCase kept
   a_completed = false;
   a_beginTimestamp = 0;
@@ -193,62 +193,56 @@ bool TestStepSendxml::do_execute() throw() {
   bool success = false;
   std::string failReason, s_warn;
 
   bool success = false;
   std::string failReason, s_warn;
 
-  // Update sequence for answers:
-  if (a_waitForRequestStepNumber != -1) { // is an answer: try to copy sequence information; alert about Session-Id discrepance
-    // Request which was received:
-    const TestStepWait *tsw = (const TestStepWait*)(a_testCase->getStep(a_waitForRequestStepNumber));
-    const anna::DataBlock &request = tsw->getMsgDataBlock();
-    anna::diameter::HopByHop hbh = anna::diameter::codec::functions::getHopByHop(request);
-    anna::diameter::EndToEnd ete = anna::diameter::codec::functions::getEndToEnd(request);
-    // Update sequence:
-    anna::diameter::codec::functions::setHopByHop(a_message, hbh);
-    anna::diameter::codec::functions::setEndToEnd(a_message, ete);
-
-    // Check Session-Id for warning ...
-    std::string sessionIdAnswer = anna::diameter::helpers::base::functions::getSessionId(a_message);
-    std::string sessionIdRequest = anna::diameter::helpers::base::functions::getSessionId(request);
-    if (sessionIdRequest != sessionIdAnswer) {
-      s_warn = anna::functions::asString("Sending an answer which Session-Id (%s) is different than supposed corresponding request (%s)", sessionIdAnswer.c_str(), sessionIdRequest.c_str());
-      LOGWARNING(anna::Logger::warning(s_warn, ANNA_FILE_LOCATION));
-      a_testCase->addDebugSummaryHint(s_warn);
+  try {
+    // Update sequence for answers:
+    if (a_waitForRequestStepNumber != -1) { // is an answer: try to copy sequence information; alert about Session-Id discrepance
+      // Request which was received:
+      const TestStepWait *tsw = (const TestStepWait*)(a_testCase->getStep(a_waitForRequestStepNumber));
+      const anna::DataBlock &request = tsw->getMsgDataBlock();
+      anna::diameter::HopByHop hbh = anna::diameter::codec::functions::getHopByHop(request);
+      anna::diameter::EndToEnd ete = anna::diameter::codec::functions::getEndToEnd(request);
+      // Update sequence:
+      anna::diameter::codec::functions::setHopByHop(a_message, hbh);
+      anna::diameter::codec::functions::setEndToEnd(a_message, ete);
+
+      // Check Session-Id for warning ...
+      std::string sessionIdAnswer = anna::diameter::helpers::base::functions::getSessionId(a_message);
+      std::string sessionIdRequest = anna::diameter::helpers::base::functions::getSessionId(request);
+      if (sessionIdRequest != sessionIdAnswer) {
+        s_warn = anna::functions::asString("Sending an answer which Session-Id (%s) is different than supposed corresponding request (%s)", sessionIdAnswer.c_str(), sessionIdRequest.c_str());
+        LOGWARNING(anna::Logger::warning(s_warn, ANNA_FILE_LOCATION));
+        a_testCase->addDebugSummaryHint(s_warn);
+      }
     }
     }
-  }
 
 
-  if (getType() == Type::Sendxml2e) {
-    MyDiameterEntity *entity = a_realmNode->getEntity();
-    if (entity) {
-      try {
+    if (getType() == Type::Sendxml2e) {
+      MyDiameterEntity *entity = a_realmNode->getEntity();
+      if (entity) {
         //msg->clearBody();
         msg->setBody(a_message);
         /* response = NULL =*/entity->send(msg);
         success = true;
         //msg->clearBody();
         msg->setBody(a_message);
         /* response = NULL =*/entity->send(msg);
         success = true;
-      } catch(anna::RuntimeException &ex) {
-        ex.trace();
-        failReason = ex.asString();
+      }
+      else {
+        failReason = "There is no diameter entity currently configured. Unable to send the message";
+        LOGWARNING(anna::Logger::warning(failReason, ANNA_FILE_LOCATION));
       }
     }
       }
     }
-    else {
-      failReason = "There is no diameter entity currently configured. Unable to send the message";
-      LOGWARNING(anna::Logger::warning(failReason, ANNA_FILE_LOCATION));
-    }
-  }
-  else if (getType() == Type::Sendxml2c) {
-    MyLocalServer *localServer = a_realmNode->getDiameterServer();
-    if (localServer) {
-      try {
+    else if (getType() == Type::Sendxml2c) {
+      MyLocalServer *localServer = a_realmNode->getDiameterServer();
+      if (localServer) {
         //msg->clearBody();
         msg->setBody(a_message);
         /* response = NULL =*/localServer->send(msg);
         success = true;
         //msg->clearBody();
         msg->setBody(a_message);
         /* response = NULL =*/localServer->send(msg);
         success = true;
-      } catch(anna::RuntimeException &ex) {
-        ex.trace();
-        failReason = ex.asString();
+      }
+      else {
+        failReason = "There is no diameter local server currently configured. Unable to send the message";
+        LOGWARNING(anna::Logger::warning(failReason, ANNA_FILE_LOCATION));
       }
     }
       }
     }
-    else {
-      failReason = "There is no diameter local server currently configured. Unable to send the message";
-      LOGWARNING(anna::Logger::warning(failReason, ANNA_FILE_LOCATION));
-    }
+  } catch(anna::RuntimeException &ex) {
+    failReason = ex.asString();
   }
 
   // release msg
   }
 
   // release msg
@@ -265,10 +259,6 @@ bool TestStepSendxml::do_execute() throw() {
   return success; // go next if sent was OK
 }
 
   return success; // go next if sent was OK
 }
 
-void TestStepSendxml::do_complete() throw() {
-  next();
-}
-
 void TestStepSendxml::do_reset() throw() {
   a_expired = false;
   //a_message.clear();
 void TestStepSendxml::do_reset() throw() {
   a_expired = false;
   //a_message.clear();
@@ -302,7 +292,7 @@ bool TestStepDelay::do_execute() throw() {
 
 void TestStepDelay::do_complete() throw() {
   a_timer = NULL;
 
 void TestStepDelay::do_complete() throw() {
   a_timer = NULL;
-  next();
+  next(); // next() invoked here because execute() is always false for delay and never dvance the iterator
 }
 
 void TestStepDelay::do_reset() throw() {
 }
 
 void TestStepDelay::do_reset() throw() {
@@ -371,7 +361,7 @@ bool TestStepWait::do_execute() throw() {
 }
 
 void TestStepWait::do_complete() throw() {
 }
 
 void TestStepWait::do_complete() throw() {
-  next();
+  next(); // next() invoked here because execute() never do this.
 }
 
 bool TestStepWait::fulfilled(const anna::DataBlock &db/*, bool matchSessionId*/) throw() {
 }
 
 bool TestStepWait::fulfilled(const anna::DataBlock &db/*, bool matchSessionId*/) throw() {
index 90b64aa..3473c54 100644 (file)
@@ -132,7 +132,7 @@ class TestStepSendxml : public TestStep {
 
     // virtuals
     bool do_execute() throw();
 
     // virtuals
     bool do_execute() throw();
-    void do_complete() throw();
+    void do_complete() throw() {;}
     void do_reset() throw();
     anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
 };
     void do_reset() throw();
     anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
 };
index 8ec2757..742c0fc 100644 (file)
 
 // STL
 #include <map>
 
 // STL
 #include <map>
+#include <vector>
 #include <string>
 #include <algorithm>
 
 #include <anna/app/Component.hpp>
 #include <anna/core/util/Recycler.hpp>
 
 #include <string>
 #include <algorithm>
 
 #include <anna/app/Component.hpp>
 #include <anna/core/util/Recycler.hpp>
 
+#include <anna/diameter/codec/Engine.hpp>
 #include <anna/diameter.comm/Server.hpp>
 #include <anna/diameter.comm/ServerSession.hpp>
 #include <anna/config/defines.hpp>
 #include <anna/diameter.comm/Server.hpp>
 #include <anna/diameter.comm/ServerSession.hpp>
 #include <anna/config/defines.hpp>
@@ -47,9 +49,13 @@ namespace codec {
 class Engine;
 }
 
 class Engine;
 }
 
-namespace comm {
+namespace stack {
+class Dictionary;
+}
 
 
+namespace comm {
 
 
+class Response;
 class Entity;
 class Server;
 class LocalServer;
 class Entity;
 class Server;
 class LocalServer;
@@ -94,27 +100,6 @@ class LocalServer;
 class Engine : public anna::app::Component {
 public:
 
 class Engine : public anna::app::Component {
 public:
 
-  /**
-   * Sets the base protocol codec engine used internally
-   *
-   * @param baseProtocolCodecEngine This will be used internally during invokation of @readCEA, @readDPA and @readDWA on servers,
-   * and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL but you must be
-   * sure that neither of the former situations are going to happen or an exception will be thrown. It is recommended to register
-   * a codec engine pointed to a base protocol stack (you can use the files 'avps_ietf.xml' and 'commands_baseProtocol.xml'
-   * located on ANNA suite project under 'source/diameter/stack/setups', or perhaps you can create your own dictionary from
-   * file or directly with the dictionay creation API. Even you can use a greater dictionary (application dictionary), the
-   * only condition is that must contain the resources to build base protocol messages. You could provide this in engine constructor,
-   * but don't forget it.
-  */
-  void setBaseProtocolCodecEngine(codec::Engine *baseProtocolCodecEngine) throw() { a_baseProtocolCodecEngine = baseProtocolCodecEngine; }
-
-  /**
-   * Gets the base protocol codec engine used internally
-   *
-   * @see setBaseProtocolCodecEngine
-   */
-  codec::Engine * getBaseProtocolCodecEngine() const throw() { return a_baseProtocolCodecEngine; }
-
   /**
      Diameter application node realm name (used to be the site domain name).
 
   /**
      Diameter application node realm name (used to be the site domain name).
 
@@ -632,6 +617,19 @@ public:
   */
   virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw();
 
   */
   virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw();
 
+  /**
+   * DRA basics: CER information is gathered on every server session managed by the diameter comm engine. You could send the message to a
+   * specific realm, and optionally you could restrict a host inside it. This is common for requests (answers are normally sent through
+   * the same source server session where the request was received). Exception will be thrown if not found an available server session
+   * for the Destination-Realm and/or Destination-Host provided
+   *
+   * @param destinationRealm If empty, NULL is returned, because is nonsense to specify a host out of realm context
+   * @param destinationHost If empty, no restriction is applied within the target realm node. Random delivery is applied for the available server sessions
+   *
+   * @return transactional response reference, or NULL if answer is sent
+   */
+  const Response* sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost = "") throw(anna::RuntimeException);
+
   /**
      Reset engine statistics.
      At the moment, only diameter servers processing time is observed.
   /**
      Reset engine statistics.
      At the moment, only diameter servers processing time is observed.
@@ -653,17 +651,15 @@ protected:
      Constructor.
 
      @param className Component class name
      Constructor.
 
      @param className Component class name
-     @param baseProtocolCodecEngine This will be used internally during invokation of @readCEA, @readDPA and @readDWA on servers,
-     and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL but you must be
-     sure that neither of the former situations are going to happen or an exception will be thrown. It is recommended to register
-     a codec engine pointed to a base protocol stack (you can use the files 'avps_ietf.xml' and 'commands_baseProtocol.xml'
-     located on ANNA suite project under 'source/diameter/stack/setups', or perhaps you can create your own dictionary from
-     file or directly with the dictionay creation API. Even you can use a greater dictionary (application dictionary), the
-     only condition is that must contain the resources to build base protocol messages. You could use @setBaseProtocolCodecEngine
-     to set this reference later; don't forget it.
+     @param baseProtocolDictionary This will be used internally when calling \@readCEA, \@readDPA and \@readDWA on
+     servers, and also used during base protocol messages tracing (if debug traces are enabled). You could provide
+     NULL, but you must be sure that neither of the former situations are going to happen or an exception will be
+     thrown (using setClientCERandDWR with DataBlock arguments, expects externally encoded messages and could help).
+     It is recommended to set a base protocol dictionary loading 'source/diameter/stack/setups' dictionaries (for
+     example 'avps_ietf.xml' plus 'commands_baseProtocol.xml'), or using the dictionary creation API. The dictionary
+     could also be an application stack, the only condition is containing the resources to build base protocol messages.
   */
   */
-  Engine(const char *className, codec::Engine *baseProtocolCodecEngine);
-
+  Engine(const char *className, const stack::Dictionary *baseProtocolDictionary);
 
   // INTERNAL CREATORS AND CLOSE METHODS
   Server *createServer(Entity*, const socket_t&) throw(anna::RuntimeException);
 
   // INTERNAL CREATORS AND CLOSE METHODS
   Server *createServer(Entity*, const socket_t&) throw(anna::RuntimeException);
@@ -712,11 +708,10 @@ protected:
   virtual void releaseLocalServer(LocalServer*) throw() {;}
 
 
   virtual void releaseLocalServer(LocalServer*) throw() {;}
 
 
-
 private:
 
   // Internal use: tracing and readCEA/DPA/DWA
 private:
 
   // Internal use: tracing and readCEA/DPA/DWA
-  codec::Engine *a_baseProtocolCodecEngine;
+  codec::Engine a_baseProtocolCodecEngine;
 
   std::string a_realm;
   std::string a_host;
 
   std::string a_realm;
   std::string a_host;
@@ -756,8 +751,17 @@ private:
 
   // Integrity:
   void checkEntityCollision(const socket_v &) throw(anna::RuntimeException);
 
   // Integrity:
   void checkEntityCollision(const socket_v &) throw(anna::RuntimeException);
+  void assertBaseProtocolHealth() throw(anna::RuntimeException); // checks the dictionary
 
 
 
 
+  //  Gets the base protocol codec engine used internally.
+  //  This engine is initializaed on constructor with the base protocol dictionary.
+  //  The reason to not reuse any other codec engine from the application is to have this one isolated with no interference
+  //  regarding configuration changes (validation depth/mode, fix mode, etc.).
+  //
+  //  @return Pointer to the internal base protocol codec engine
+  codec::Engine *getBaseProtocolCodecEngine() const throw() { return const_cast<codec::Engine *>(&a_baseProtocolCodecEngine); }
+
   //////////////////////////
   // CLIENT FUNCTIONALITY //
   //////////////////////////
   //////////////////////////
   // CLIENT FUNCTIONALITY //
   //////////////////////////
@@ -830,10 +834,22 @@ private:
   const_localServer_iterator localServer_end() const throw() { return a_localServers.end(); }
   static const LocalServer* localServer(const_localServer_iterator ii) throw() { return ii->second; }
 
   const_localServer_iterator localServer_end() const throw() { return a_localServers.end(); }
   static const LocalServer* localServer(const_localServer_iterator ii) throw() { return ii->second; }
 
-  // Server sessions are managed within LocalServer (not at engine) due to dynamic cration nature
-
+  // Server sessions are managed within LocalServer (not at engine) due to dynamic creation nature
+  // Here we maintain the Destination-Realm / Destination-Host maps for DRA basics:
+  typedef std::vector<ServerSession*> server_sessions_vector_t;
+  typedef server_sessions_vector_t::const_iterator server_sessions_it_t;
+  typedef server_sessions_vector_t::iterator server_sessions_nc_it_t;
+  typedef std::map <std::string /* Destination-Host */, server_sessions_vector_t> dh_server_sessions_map_t;
+  typedef dh_server_sessions_map_t::const_iterator dh_server_sessions_it_t;
+  typedef dh_server_sessions_map_t::iterator dh_server_sessions_nc_it_t;
+  typedef std::map <std::string /* Destination-Realm */, dh_server_sessions_map_t> dr_dh_server_sessions_map_t;
+  typedef dr_dh_server_sessions_map_t::const_iterator dr_dh_server_sessions_it_t;
+  typedef dr_dh_server_sessions_map_t::iterator dr_dh_server_sessions_nc_it_t;
+  dr_dh_server_sessions_map_t a_dr_dh_server_sessions;
+  void manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw();
 
   friend class Session;
 
   friend class Session;
+  friend class ClientSession;
   friend class ServerSession;
   friend class ServerSocket;
   friend class Server;
   friend class ServerSession;
   friend class ServerSocket;
   friend class Server;
index 1884083..b973e8d 100644 (file)
@@ -238,8 +238,9 @@ public:
   * this to have the commonly recommended way to choose the stack: using the Application-Id value.
   *
   * @warning do not activate in case of multithreaded applications.
   * this to have the commonly recommended way to choose the stack: using the Application-Id value.
   *
   * @warning do not activate in case of multithreaded applications.
+  * @warning must register the base protocol stack (with id = 0 = application-id) to manage base protocol messages.
   * @param enable Activates/deactivates the stack selection from the Application-Id value within the message header.
   * @param enable Activates/deactivates the stack selection from the Application-Id value within the message header.
-  *               False by default.
+  *               False by default on engine construction.
   */
   void selectStackWithApplicationId (bool enable) throw() { a_selectStackWithApplicationId = enable; }
 
   */
   void selectStackWithApplicationId (bool enable) throw() { a_selectStackWithApplicationId = enable; }
 
index a3916f7..48d2b84 100644 (file)
@@ -263,7 +263,7 @@ public:
      Sets the message application id.
 
      The codec engine could be configured to force a stack selection based in this field value: see #selectStackWithApplicationId.
      Sets the message application id.
 
      The codec engine could be configured to force a stack selection based in this field value: see #selectStackWithApplicationId.
-     In multistack applications (which also shall be monothreaded), you only have to take care about how to apply this method: the thing
+     In multistack applications (in case of being monothread), you only have to take care about how to apply this method: the thing
      is that you must not interleave message builds which belongs to different stacks. For example, you could think about setting the
      message header for message A using stack A. Then, start to add the message header fields for a second message B using another stack B.
      Following you would add the message A avps, but then, the stack is not going to be automatically changed (this is only done through this
      is that you must not interleave message builds which belongs to different stacks. For example, you could think about setting the
      message header for message A using stack A. Then, start to add the message header fields for a second message B using another stack B.
      Following you would add the message A avps, but then, the stack is not going to be automatically changed (this is only done through this
index 3a7f843..9bfaf60 100644 (file)
@@ -5,9 +5,11 @@
 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
 
 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
 
+// Standard
+#include <stdlib.h> // rand()
 
 
-#include <anna/diameter.comm/Engine.hpp>
 
 
+#include <anna/diameter.comm/Engine.hpp>
 #include <anna/core/tracing/Logger.hpp>
 #include <anna/core/tracing/TraceMethod.hpp>
 #include <anna/xml/Node.hpp>
 #include <anna/core/tracing/Logger.hpp>
 #include <anna/core/tracing/TraceMethod.hpp>
 #include <anna/xml/Node.hpp>
 #include <anna/diameter/helpers/helpers.hpp>
 #include <anna/diameter/codec/Message.hpp>
 #include <anna/diameter/codec/Avp.hpp>
 #include <anna/diameter/helpers/helpers.hpp>
 #include <anna/diameter/codec/Message.hpp>
 #include <anna/diameter/codec/Avp.hpp>
+#include <anna/diameter.comm/Response.hpp>
 
 // STD
 #include <map>
 
 using namespace std;
 
 // STD
 #include <map>
 
 using namespace std;
-using namespace anna::diameter::comm;
+using namespace anna::diameter;
+
 
 
+namespace anna {
+  namespace diameter {
+    namespace stack {
+      class Dictionary;
+    }
+  }
+}
 
 
-Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
+comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtocolDictionary) :
   anna::app::Component(className),
   anna::app::Component(className),
-  a_baseProtocolCodecEngine(baseProtocolCodecEngine),
   a_autoBind(true),
   a_availableForEntities(false),
   a_availableForLocalServers(false),
   a_autoBind(true),
   a_availableForEntities(false),
   a_availableForLocalServers(false),
@@ -49,19 +59,34 @@ Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
 //      a_dwa(true),
   a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
   a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
 //      a_dwa(true),
   a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
   a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
-  a_numberOfClientSessionsPerServer(1) {
+  a_numberOfClientSessionsPerServer(1),
+  a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str())
+{
   anna::diameter::sccs::activate();
   a_realm = anna::functions::getDomainname();
   a_host = anna::functions::getHostname();
   anna::diameter::sccs::activate();
   a_realm = anna::functions::getDomainname();
   a_host = anna::functions::getHostname();
+
+  // Internal base protocol codec engine:
+  a_baseProtocolCodecEngine.setDictionary(baseProtocolDictionary);
+  a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding
 }
 
 }
 
-Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); }
-void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
-ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
-void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
+
+void comm::Engine::assertBaseProtocolHealth() throw(anna::RuntimeException) {
+  if (!getBaseProtocolCodecEngine()->getDictionary())
+    throw anna::RuntimeException("Invalid diameter::comm::Engine object: base protocol dictionary provided on constructor was NULL", ANNA_FILE_LOCATION);
+  // it would be interesting to check and identify certain base protocol elements in the dictionary ...
+  //  but these things will be checked in runtime and will fail if they should.
+}
+
+
+comm::Server* comm::Engine::allocateServer() throw() { return a_serversRecycler.create(); }
+void comm::Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
+comm::ClientSession* comm::Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
+void comm::Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
 
 
 
 
-void Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
+void comm::Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
   if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
     throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
   }
   if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
     throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
   }
@@ -74,11 +99,10 @@ void Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlo
   a_dwr = dwr;
 }
 
   a_dwr = dwr;
 }
 
-void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
+void comm::Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
 
 
-  // Check for base protocol codec engine:
-  if (!getBaseProtocolCodecEngine())
-    throw anna::RuntimeException("Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow base protocol messages encoding, or use setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) which expect externally encoded messages", ANNA_FILE_LOCATION);
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
 
   // Build CER
   //   <CER> ::= < Diameter Header: 257, REQ >
 
   // Build CER
   //   <CER> ::= < Diameter Header: 257, REQ >
@@ -155,7 +179,7 @@ void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr
   setClientCERandDWR(diameterCER.code(), diameterDWR.code());
 }
 
   setClientCERandDWR(diameterCER.code(), diameterDWR.code());
 }
 
-void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
+void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
   if(wp < ClientSession::DefaultWatchdogPeriod) {
     throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
   }
   if(wp < ClientSession::DefaultWatchdogPeriod) {
     throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
   }
@@ -163,7 +187,7 @@ void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::Runtime
   a_watchdogPeriod = wp;
 }
 
   a_watchdogPeriod = wp;
 }
 
-void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
+void comm::Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
   socket_v::const_iterator it;
   socket_v::const_iterator it_min(v.begin());
   socket_v::const_iterator it_max(v.end());
   socket_v::const_iterator it;
   socket_v::const_iterator it_min(v.begin());
   socket_v::const_iterator it_max(v.end());
@@ -184,7 +208,7 @@ void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeExceptio
     throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
 }
 
     throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
 }
 
-Entity* Engine::createEntity(const socket_v & socketList, const std::string &description)
+comm::Entity* comm::Engine::createEntity(const socket_v & socketList, const std::string &description)
 throw(anna::RuntimeException) {
   Entity* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
 throw(anna::RuntimeException) {
   Entity* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
@@ -233,7 +257,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
+comm::LocalServer *comm::Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
 throw(anna::RuntimeException) {
   LocalServer* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
 throw(anna::RuntimeException) {
   LocalServer* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
@@ -268,7 +292,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
+comm::Entity* comm::Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
 throw(anna::RuntimeException) {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
 throw(anna::RuntimeException) {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
@@ -277,7 +301,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-Server* Engine::createServer(Entity *entity, const socket_t & socket)
+comm::Server* comm::Engine::createServer(Entity *entity, const socket_t & socket)
 throw(anna::RuntimeException) {
   Server* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
 throw(anna::RuntimeException) {
   Server* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
@@ -309,7 +333,7 @@ throw(anna::RuntimeException) {
 
 
 // Lohacemos privado
 
 
 // Lohacemos privado
-ClientSession* Engine::createClientSession(Server *server, int socketId)
+comm::ClientSession* comm::Engine::createClientSession(Server *server, int socketId)
 throw(anna::RuntimeException) {
   ClientSession* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
 throw(anna::RuntimeException) {
   ClientSession* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
@@ -355,7 +379,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
+bool comm::Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
   bool allok = true;
   bool ok;
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
   bool allok = true;
   bool ok;
@@ -374,7 +398,7 @@ bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeExcept
   return allok;
 }
 
   return allok;
 }
 
-bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
+bool comm::Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
   bool allok = true;
   bool ok;
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
   bool allok = true;
   bool ok;
@@ -393,7 +417,7 @@ bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeEx
   return allok;
 }
 
   return allok;
 }
 
-bool Engine::bind() throw(anna::RuntimeException) {
+bool comm::Engine::bind() throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
   bool result = true; // all OK return
 
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
   bool result = true; // all OK return
 
@@ -409,12 +433,12 @@ bool Engine::bind() throw(anna::RuntimeException) {
   return result;
 }
 
   return result;
 }
 
-ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
+comm::ClientSession* comm::Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
 }
 
 throw(anna::RuntimeException) {
   return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
 }
 
-ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
+comm::ClientSession* comm::Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
   clientSession_iterator ii = clientSession_find(key);
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
   clientSession_iterator ii = clientSession_find(key);
@@ -438,7 +462,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
+comm::Server* comm::Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
   server_iterator ii = server_find(server_key(addr, port));
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
   server_iterator ii = server_find(server_key(addr, port));
@@ -462,7 +486,7 @@ throw(anna::RuntimeException) {
   return NULL;
 }
 
   return NULL;
 }
 
-Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
+comm::Entity* comm::Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
   entity_key key(getEntityKey(socketList));
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
   entity_key key(getEntityKey(socketList));
@@ -486,7 +510,7 @@ throw(anna::RuntimeException) {
   return NULL;
 }
 
   return NULL;
 }
 
-Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
+comm::Entity* comm::Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
 throw(anna::RuntimeException) {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
@@ -509,7 +533,7 @@ throw(anna::RuntimeException) {
 //}
 
 
 //}
 
 
-LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
+comm::LocalServer* comm::Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
   socket_t key(addr, port);
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
   socket_t key(addr, port);
@@ -535,7 +559,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
+comm::ServerSession* comm::Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
   ServerSession *result;
 
   anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
   ServerSession *result;
 
@@ -562,7 +586,7 @@ ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v
 }
 
 
 }
 
 
-void Engine::closeClientSession(ClientSession* clientSession, bool destroy)
+void comm::Engine::closeClientSession(comm::ClientSession* clientSession, bool destroy)
 throw(anna::RuntimeException) {
   if(clientSession == NULL)
     return;
 throw(anna::RuntimeException) {
   if(clientSession == NULL)
     return;
@@ -600,7 +624,7 @@ throw(anna::RuntimeException) {
 
 
 
 
 
 
-void Engine::closeServer(Server* server, bool destroy)
+void comm::Engine::closeServer(comm::Server* server, bool destroy)
 throw(anna::RuntimeException) {
   if(server == NULL)
     return;
 throw(anna::RuntimeException) {
   if(server == NULL)
     return;
@@ -632,7 +656,7 @@ throw(anna::RuntimeException) {
 }
 
 
 }
 
 
-void Engine::closeEntity(Entity* entity, bool destroy)
+void comm::Engine::closeEntity(comm::Entity* entity, bool destroy)
 throw(anna::RuntimeException) {
   if(entity == NULL)
     return;
 throw(anna::RuntimeException) {
   if(entity == NULL)
     return;
@@ -667,7 +691,7 @@ throw(anna::RuntimeException) {
 
 
 
 
 
 
-void Engine::closeLocalServer(LocalServer* localServer, bool destroy)
+void comm::Engine::closeLocalServer(comm::LocalServer* localServer, bool destroy)
 throw(anna::RuntimeException) {
   if(localServer == NULL)
     return;
 throw(anna::RuntimeException) {
   if(localServer == NULL)
     return;
@@ -700,7 +724,7 @@ throw(anna::RuntimeException) {
 
 
 
 
 
 
-void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
+void comm::Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
   anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
 
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
   anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
 
@@ -708,7 +732,7 @@ void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
     closeEntity(entity(it), destroy);
 }
 
     closeEntity(entity(it), destroy);
 }
 
-void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
+void comm::Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
   anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
 
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
   anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
 
@@ -716,7 +740,7 @@ void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
     closeLocalServer(localServer(it), destroy);
 }
 
     closeLocalServer(localServer(it), destroy);
 }
 
-void Engine::eraseDeprecatedIdleEntities() throw() {
+void comm::Engine::eraseDeprecatedIdleEntities() throw() {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
   Entity *et;
 
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
   Entity *et;
 
@@ -727,7 +751,7 @@ void Engine::eraseDeprecatedIdleEntities() throw() {
   }
 }
 
   }
 }
 
-int Engine::getOTARequestsForEntities() const throw() {
+int comm::Engine::getOTARequestsForEntities() const throw() {
   int result = 0;
 
   for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
   int result = 0;
 
   for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
@@ -736,7 +760,7 @@ int Engine::getOTARequestsForEntities() const throw() {
   return result;
 }
 
   return result;
 }
 
-int Engine::getOTARequestsForLocalServers() const throw() {
+int comm::Engine::getOTARequestsForLocalServers() const throw() {
   int result = 0;
 
   for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
   int result = 0;
 
   for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
@@ -746,31 +770,31 @@ int Engine::getOTARequestsForLocalServers() const throw() {
 }
 
 
 }
 
 
-void Engine::setRealm(const std::string & name) throw() {
+void comm::Engine::setRealm(const std::string & name) throw() {
   a_realm = ((name != "") ? name : anna::functions::getDomainname());
 }
 
 
   a_realm = ((name != "") ? name : anna::functions::getDomainname());
 }
 
 
-void Engine::setHost(const std::string & name) throw() {
+void comm::Engine::setHost(const std::string & name) throw() {
   a_host = ((name != "") ? name : anna::functions::getHostname());
 }
 
 
 
   a_host = ((name != "") ? name : anna::functions::getHostname());
 }
 
 
 
-void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
+void comm::Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
 
   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
     entity(it)->raiseAutoRecovery(autoRecovery);
 }
 
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
 
   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
     entity(it)->raiseAutoRecovery(autoRecovery);
 }
 
-void Engine::do_stop()
+void comm::Engine::do_stop()
 throw() {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
   close(true /* destroy */);
 }
 
 throw() {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
   close(true /* destroy */);
 }
 
-std::string Engine::asString(void) const throw() {
+std::string comm::Engine::asString(void) const throw() {
   std::string trace;
   trace =  "\n================================";
   trace += "\nDiameter comm Engine information";
   std::string trace;
   trace =  "\n================================";
   trace += "\nDiameter comm Engine information";
@@ -811,7 +835,7 @@ std::string Engine::asString(void) const throw() {
 }
 
 
 }
 
 
-anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const
+anna::xml::Node* comm::Engine::asXML(anna::xml::Node* parent) const
 throw() {
   parent = anna::app::Component::asXML(parent);
   anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
 throw() {
   parent = anna::app::Component::asXML(parent);
   anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
@@ -834,33 +858,57 @@ throw() {
   for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
     localServer(it)->asXML(localServers);
 
   for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
     localServer(it)->asXML(localServers);
 
+  // DRA Basics
+  // Aspect:
+  //  <Engine.RemoteRealm Name="afNodeHostRealm.com">
+  //     <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:4"/>
+  //  </Engine.RemoteRealm>
+  //  <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
+  //     <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:6"/>
+  //  </Engine.RemoteRealm>
+  for (dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.begin(); drit != a_dr_dh_server_sessions.end(); drit++) {
+    anna::xml::Node* remoteRealm = result->createChild("Engine.RemoteRealm");
+    remoteRealm->createAttribute("Name", drit->first);
+    dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
+    for (dh_server_sessions_it_t dhit = dhServerSessions->begin(); dhit != dhServerSessions->end(); dhit++) {
+      anna::xml::Node* remoteRealmHost = remoteRealm->createChild("Engine.RemoteRealmHost");
+      remoteRealmHost->createAttribute("Name", dhit->first);
+      server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
+      for (server_sessions_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
+        std::string socket = anna::functions::socketLiteralAsString((*ssit)->getAddress(), (*ssit)->getPort());
+        std::string ss_desc = socket + anna::functions::asString("|ServerSessionId:%d", (*ssit)->getSocketId());
+        remoteRealmHost->createAttribute("ServerSession", ss_desc);
+      }
+    }
+  }
+
   return result;
 }
 
   return result;
 }
 
-Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() {
+comm::Engine::clientSession_iterator comm::Engine::clientSession_find(const clientSession_key &key) throw() {
   return a_clientSessions.find(key);
 }
 
   return a_clientSessions.find(key);
 }
 
-Engine::server_iterator Engine::server_find(const server_key &key) throw() {
+comm::Engine::server_iterator comm::Engine::server_find(const server_key &key) throw() {
   return a_servers.find(key);
 }
 
   return a_servers.find(key);
 }
 
-Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() {
+comm::Engine::entity_iterator comm::Engine::entity_find(const entity_key &key) throw() {
   return a_entities.find(key);
 }
 
   return a_entities.find(key);
 }
 
-Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() {
+comm::Engine::localServer_iterator comm::Engine::localServer_find(const socket_t &key) throw() {
   return a_localServers.find(key);
 }
 
   return a_localServers.find(key);
 }
 
-Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
+comm::Engine::entity_key comm::Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
   dualList.push_back(socket_t(addr2, port2));
   return (getEntityKey(dualList));
 }
 
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
   dualList.push_back(socket_t(addr2, port2));
   return (getEntityKey(dualList));
 }
 
-Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
+comm::Engine::entity_key comm::Engine::getEntityKey(const socket_v &v) const throw() {
   std::string result;
   socket_v::const_iterator it;
   socket_v::const_iterator it_min(v.begin());
   std::string result;
   socket_v::const_iterator it;
   socket_v::const_iterator it_min(v.begin());
@@ -877,7 +925,7 @@ Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
 }
 
 
 }
 
 
-void Engine::availabilityLostForEntities() throw() {
+void comm::Engine::availabilityLostForEntities() throw() {
   a_availableForEntities = false;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
   a_availableForEntities = false;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
@@ -894,7 +942,7 @@ void Engine::availabilityLostForEntities() throw() {
 }
 
 
 }
 
 
-void Engine::availabilityRecoveredForEntities() throw() {
+void comm::Engine::availabilityRecoveredForEntities() throw() {
   a_availableForEntities = true;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
   a_availableForEntities = true;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
@@ -911,7 +959,7 @@ void Engine::availabilityRecoveredForEntities() throw() {
 }
 
 
 }
 
 
-void Engine::availabilityLostForLocalServers() throw() {
+void comm::Engine::availabilityLostForLocalServers() throw() {
   a_availableForLocalServers = false;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
   a_availableForLocalServers = false;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
@@ -928,7 +976,7 @@ void Engine::availabilityLostForLocalServers() throw() {
 }
 
 
 }
 
 
-void Engine::availabilityRecoveredForLocalServers() throw() {
+void comm::Engine::availabilityRecoveredForLocalServers() throw() {
   a_availableForLocalServers = true;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
   a_availableForLocalServers = true;
   LOGDEBUG(
     std::string msg = "diameter::comm::Engine { Realm: ";
@@ -945,7 +993,7 @@ void Engine::availabilityRecoveredForLocalServers() throw() {
 }
 
 
 }
 
 
-bool Engine::refreshAvailabilityForEntities() throw() {
+bool comm::Engine::refreshAvailabilityForEntities() throw() {
   // Here available
   if(a_availableForEntities) {  // check not-bound state for all client-sessions:
     bool isolate = true;
   // Here available
   if(a_availableForEntities) {  // check not-bound state for all client-sessions:
     bool isolate = true;
@@ -971,7 +1019,7 @@ bool Engine::refreshAvailabilityForEntities() throw() {
   return false;
 }
 
   return false;
 }
 
-bool Engine::refreshAvailabilityForLocalServers() throw() {
+bool comm::Engine::refreshAvailabilityForLocalServers() throw() {
   // Here available
   if(a_availableForLocalServers) {  // check not-bound state for all client-sessions:
     bool isolate = true;
   // Here available
   if(a_availableForLocalServers) {  // check not-bound state for all client-sessions:
     bool isolate = true;
@@ -998,7 +1046,11 @@ bool Engine::refreshAvailabilityForLocalServers() throw() {
 }
 
 
 }
 
 
-void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
+void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
+
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
+
   // Default DPA implementation:
   //
   //   'Disconnect-Peer-Answer' (282,answer)
   // Default DPA implementation:
   //
   //   'Disconnect-Peer-Answer' (282,answer)
@@ -1044,7 +1096,11 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw()
 }
 
 
 }
 
 
-void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
+void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
+
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
+
   // Default CEA implementation:
   //
   //   'Capabilities-Exchange-Answer' (257,answer)
   // Default CEA implementation:
   //
   //   'Capabilities-Exchange-Answer' (257,answer)
@@ -1109,8 +1165,71 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw()
   }
 }
 
   }
 }
 
+void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw() {
+
+  // Decode CER (TODO: use raw buffer helpers)
+  std::string destinationRealm, destinationHost;
+  codec::Message codecMsg(getBaseProtocolCodecEngine());
+  try {
+    codecMsg.decode(ss->a_cer);
+    destinationRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
+    destinationHost = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->getValue();
+  }
+  catch(anna::RuntimeException &ex) {
+    ex.trace();
+    return;
+  }
+
+  dr_dh_server_sessions_nc_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
+  if (drit != a_dr_dh_server_sessions.end()) { // found
+    dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
+    dh_server_sessions_nc_it_t dhit = dhServerSessions->find(destinationHost);
+    if (dhit != dhServerSessions->end()) { // found
+      server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
+      if (register_or_desregister) { // REGISTER
+        serverSessions->push_back(ss);
+      }
+      else { // DESREGISTER
+        // Sequential search the specific server session:
+        for (server_sessions_nc_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
+          if ((*ssit)->getAddress() != ss->getAddress()) continue;
+          if ((*ssit)->getPort() != ss->getPort()) continue;
+          if ((*ssit)->getSocketId() != ss->getSocketId()) continue;
+          serverSessions->erase(ssit);  // if it is the last server session removed in DR-DH path, the XML will show this tree empty
+                                        // (it could be a hint for past registerings):
+                                        //          <Engine.RemoteRealm Name="afNodeHostRealm.com">
+                                        //             <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com"/>
+                                        //          </Engine.RemoteRealm>
+                                        //          <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
+                                        //             <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com"/>
+                                        //          </Engine.RemoteRealm>
+
+          break;
+        }
+      }
+    }
+    else {
+      if (!register_or_desregister) return; // strange (host not found)
+      server_sessions_vector_t ssVector;
+      ssVector.push_back(ss);
+      (*dhServerSessions)[destinationHost] = ssVector;
+    }
+  }
+  else {
+    if (!register_or_desregister) return; // strange (realm not found)
+    server_sessions_vector_t ssVector;
+    ssVector.push_back(ss);
+    dh_server_sessions_map_t dhServerSessions;
+    dhServerSessions[destinationHost] = ssVector;
+    a_dr_dh_server_sessions[destinationRealm] = dhServerSessions;
+  }
+}
+
+void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
+
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
 
 
-void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
   // Default DWA implementation:
   //
   //   'Device-Watchdog-Answer' (280,answer)
   // Default DWA implementation:
   //
   //   'Device-Watchdog-Answer' (280,answer)
@@ -1156,7 +1275,7 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw()
   }
 }
 
   }
 }
 
-void Engine::resetStatistics() throw() {
+void comm::Engine::resetStatistics() throw() {
   for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
     server(it)->resetStatistics();
 
   for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
     server(it)->resetStatistics();
 
@@ -1164,12 +1283,58 @@ void Engine::resetStatistics() throw() {
     localServer(it)->resetStatistics();
 }
 
     localServer(it)->resetStatistics();
 }
 
-void Engine::do_initialize() throw(RuntimeException) {
+void comm::Engine::do_initialize() throw(RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
   LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
 }
 
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
   LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
 }
 
-void Engine::lazyInitialize() throw(RuntimeException) {
+void comm::Engine::lazyInitialize() throw(RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
   anna::app::Component::initialize(); // this will invoke do_initialize
 }
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
   anna::app::Component::initialize(); // this will invoke do_initialize
 }
+
+// Not tested yet
+const comm::Response* comm::Engine::sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost) throw(anna::RuntimeException) {
+
+  if (destinationRealm == "")
+    throw anna::RuntimeException("Unable to resolve the destination: empty provided Destination-Realm name", ANNA_FILE_LOCATION);
+
+  // Get the server sessions which fulfill the restrictions:
+  dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
+  if (drit == a_dr_dh_server_sessions.end())
+    throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: Destination-Realm name is not registered (no remote clients have been connected to '%s')", destinationRealm.c_str()), ANNA_FILE_LOCATION);
+
+  dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
+  // randomize between all server sessions for all hosts:
+  dh_server_sessions_nc_it_t dhit;
+  int hostsN = dhServerSessions->size();
+  if (hostsN == 0) // avoids next division by cero (rand() % 0)
+    throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: neither Destination-Host currently connected to Destination-Realm '%s'", destinationRealm.c_str()), ANNA_FILE_LOCATION);
+
+  if (destinationHost == "") {
+    // in this case, randomize the host:
+    dhit = dhServerSessions->begin();
+    int randomHostIndx = rand() % hostsN; // number between 0 and the number of hosts - 1
+    std::advance (dhit, randomHostIndx);
+  }
+  else {
+    dhit = dhServerSessions->find(destinationHost);
+    if (dhit == dhServerSessions->end())
+      throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: Destination-Host '%s' is not registered for Destination-Realm '%s'", destinationHost.c_str(), destinationRealm.c_str()), ANNA_FILE_LOCATION);
+  }
+
+  // Now, randomize the available server sessions:
+  server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
+  int serverSessionN = serverSessions->size();
+  if (serverSessionN == 0) { // avoids next division by cero (rand() % 0)
+    std::string aux = "";
+    if (destinationHost != "") { aux = "to Destination-Host '"; aux += destinationHost; aux += "'"; }
+    std::string msg = anna::functions::asString("Unable to resolve the destination: neither server session currently connected%s within Destination-Realm '%s'", aux.c_str(), destinationRealm.c_str());
+    throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+  }
+
+  server_sessions_nc_it_t ssit = serverSessions->begin();
+  int randomServerSessionIndx = rand() % serverSessionN; // number between 0 and the number of server sessions - 1
+  std::advance (ssit, randomServerSessionIndx);
+  return (*ssit)->send(message);
+}
index 985e4a8..a14b3c6 100644 (file)
@@ -305,6 +305,10 @@ throw(anna::RuntimeException) {
   if(ii == serverSession_end())
     return;
 
   if(ii == serverSession_end())
     return;
 
+  // Remove origin-realm / origin-host for server session in delivery map
+  // This is related to http://redmine.teslayout.com/issues/41
+  a_engine->manageDrDhServerSession(serverSession, false /* desregister */);
+
   try {
     //serverSession->setState(ServerSession::State::Closing); NOT MANAGED WITH SERVER SESSIONS
     serverSession->unbind(true /* always forceDisconnect on server sessions ... */);
   try {
     //serverSession->setState(ServerSession::State::Closing); NOT MANAGED WITH SERVER SESSIONS
     serverSession->unbind(true /* always forceDisconnect on server sessions ... */);
index 1e2728c..ad0b15a 100644 (file)
@@ -55,7 +55,7 @@ const anna::Millisecond ServerSession::DefaultAllowedInactivityTime(90000); // I
 ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"),
   a_receiverFactory(this),
   a_cer(ClassCode::Bind),
 ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"),
   a_receiverFactory(this),
   a_cer(ClassCode::Bind),
-  a_dwr(ClassCode::ApplicationMessage) // realmente no es necesario, los Message son por defecto de aplicacion
+  a_dwr(ClassCode::ApplicationMessage) // not actually needed; Message is application type by default
 { initialize(); }
 
 void ServerSession::initialize() throw() {
 { initialize(); }
 
 void ServerSession::initialize() throw() {
@@ -81,7 +81,6 @@ int ServerSession::getPort() const throw() {
   return a_parent->getKey().second;
 }
 
   return a_parent->getKey().second;
 }
 
-
 const Response* ServerSession::send(const Message* message) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION));
 
 const Response* ServerSession::send(const Message* message) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION));
 
@@ -398,6 +397,9 @@ throw(anna::RuntimeException) {
       }
 
       a_cer.setBody(db);
       }
 
       a_cer.setBody(db);
+      // Basic DRA:
+      getParent()->getEngine()->manageDrDhServerSession(this, true /* register */);
+
       sendCEA();
       //activateTimer(); // Ya se invoca al inicio de este metodo ::receive
       //bool changes = a_parent->refreshAvailability();
       sendCEA();
       //activateTimer(); // Ya se invoca al inicio de este metodo ::receive
       //bool changes = a_parent->refreshAvailability();