Multistack launcher
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 7 Jun 2015 22:06:29 +0000 (00:06 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Mon, 27 Jul 2015 21:14:28 +0000 (23:14 +0200)
42 files changed:
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/Launcher.hpp
example/diameter/launcher/MyDiameterEntity.cpp
example/diameter/launcher/Node.cpp [new file with mode: 0644]
example/diameter/launcher/Node.hpp [new file with mode: 0644]
example/diameter/launcher/deployments/basic/hex_examples [new symlink]
example/diameter/launcher/deployments/basic/hex_examples/aar-bad.hex [deleted file]
example/diameter/launcher/deployments/basic/hex_examples/aar.hex [deleted file]
example/diameter/launcher/deployments/basic/hex_examples/aar2-bad.hex [deleted file]
example/diameter/launcher/deployments/basic/hex_examples/aar3-bad.hex [deleted file]
example/diameter/launcher/deployments/basic/hex_examples/readme.txt [deleted file]
example/diameter/launcher/deployments/basic/hex_examples/tspCCA.hex [deleted file]
example/diameter/launcher/deployments/basic/hex_examples/tspCCR.hex [deleted file]
example/diameter/launcher/deployments/basic/operation.sh [changed from file to symlink]
example/diameter/launcher/deployments/basic/xml_examples [new symlink]
example/diameter/launcher/deployments/basic/xml_examples/aaa.xml [deleted file]
example/diameter/launcher/deployments/basic/xml_examples/aar.xml [deleted file]
example/diameter/launcher/deployments/basic/xml_examples/aar2.xml [deleted file]
example/diameter/launcher/deployments/basic/xml_examples/ccr.xml [deleted file]
example/diameter/launcher/deployments/ft-client/hex_examples
example/diameter/launcher/deployments/ft-client/operation.sh
example/diameter/launcher/deployments/ft-client/xml_examples
example/diameter/launcher/main.cpp
example/diameter/launcher/resources/hex_examples/aar-bad.hex [new file with mode: 0644]
example/diameter/launcher/resources/hex_examples/aar.hex [new file with mode: 0644]
example/diameter/launcher/resources/hex_examples/aar2-bad.hex [new file with mode: 0644]
example/diameter/launcher/resources/hex_examples/aar3-bad.hex [new file with mode: 0644]
example/diameter/launcher/resources/hex_examples/readme.txt [new file with mode: 0644]
example/diameter/launcher/resources/hex_examples/tspCCA.hex [new file with mode: 0644]
example/diameter/launcher/resources/hex_examples/tspCCR.hex [new file with mode: 0644]
example/diameter/launcher/resources/pcap2diameterHex.sh [deleted file]
example/diameter/launcher/resources/scripts/operation_curl.sh [new file with mode: 0755]
example/diameter/launcher/resources/scripts/operation_signal.sh [new file with mode: 0755]
example/diameter/launcher/resources/scripts/operation_tps.sh [new file with mode: 0755]
example/diameter/launcher/resources/scripts/pcap2diameterHex.sh [new file with mode: 0755]
example/diameter/launcher/resources/xml_examples/aaa.xml [new file with mode: 0644]
example/diameter/launcher/resources/xml_examples/aar.xml [new file with mode: 0644]
example/diameter/launcher/resources/xml_examples/aar2.xml [new file with mode: 0644]
example/diameter/launcher/resources/xml_examples/ccr.xml [new file with mode: 0644]
include/anna/diameter/codec/EngineImpl.hpp
source/diameter/codec/EngineImpl.cpp
source/diameter/codec/Message.cpp

index 59f5202..f5fac98 100644 (file)
@@ -12,7 +12,6 @@
 #include <anna/http/Transport.hpp>
 #include <anna/diameter/stack/Engine.hpp>
 #include <anna/diameter/helpers/base/functions.hpp>
-#include <anna/diameter/helpers/dcca/functions.hpp>
 #include <anna/time/functions.hpp>
 #include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
 
 #define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.tasks.output"
 #define DIAMETER_CODEC_ENGINE_NAME_PREFIX "MyCodecEngine"
 
+const char *ServicesDTD = "\
+<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<!-- Diameter services DTD -->\n\
+\n\
+<!ELEMENT services (stack*, node*)>\n\
+\n\
+<!ELEMENT stack EMPTY>\n\
+<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>\n\
+<!--\n\
+   Stack record\n\
+\n\
+   id:         Normally the id corresponds to the Application-Id for which the dictionary provided is designed\n\
+   dictionary: Path to the dictionary file\n\
+-->\n\
+\n\
+<!ELEMENT node EMPTY>\n\
+<!ATTLIST node name CDATA #REQUIRED application-id CDATA #REQUIRED cer CDATA #IMPLIED dwr CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED ignoreFlags (yes | no) #IMPLIED ignoreErrors (yes | no) #IMPLIED>\n\
+<!--\n\
+   Node record\n\
+\n\
+   name:                                    Each node will be named normally with the Origin-Realm value\n\
+   application-id:                          The Application-Id provided must exists as a registered 'stack id'\n\
+   cer:                                     User defined CER path file to be encoded to establish diameter connections. If missing, will be harcoded\n\
+   dwr:                                     User defined DWR path file to be encoded for diameter protocol keep alive. If missing, will be harcoded\n\
+   entity:                                  Target diameter entity (comma-separated '<address>:<port>' format). For example: 10.20.30.40:3868,10.20.30.41:3868. If missing, no entity will be enabled\n\
+   entityServerSessions:                    Diameter entity server sessions (0: diameter entity disabled). Default value of 1\n\
+   diameterServer:                          Diameter own server address in '<address>:<port>' format. For example: 10.20.30.40:3868. If missing, no local server will be enabled\n\
+   diameterServerSessions:                  Diameter own server available connections (0: diameter server disabled). Default value of 1\n\
+   balance:                                 Balance over entity servers instead of doing standard behaviour (first primary, secondary if fails, etc.). Default value 'no'\n\
+   ignoreErrors:                            Local server skips requests errors analysis which would prepare automatic answers for them when a problem is found. If no answer is programmed and entity is configured, a failed request would be forwarded (delegates at the end point) even if this parameter is missing. Default value 'no'\n\
+-->\n\
+\n\
+";
+
+
 Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "1.1"), a_communicator(NULL) {
   a_myDiameterEngine = new MyDiameterEngine();
   a_myDiameterEngine->setRealm("ADL.ericsson.com");
@@ -40,6 +74,8 @@ Launcher::Launcher() : anna::comm::Application("launcher", "DiameterLauncher", "
   a_diameterLocalServer = NULL;
   a_cerPathfile = "cer.xml";
   a_dwrPathfile = "dwr.xml";
+  a_workingStackId = 0;
+
   // Burst
   a_burstCycle = 1;
   a_burstRepeat = false;
@@ -341,36 +377,49 @@ throw(anna::RuntimeException) {
   // Stack:
   a_codecEngine = new anna::diameter::codec::Engine(DIAMETER_CODEC_ENGINE_NAME_PREFIX);
   anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
-  anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* stack id; its value don't mind, is not used (ADL is monostack) */);
-  // Analyze comma-separated list:
-  anna::Tokenizer lst;
-  std::string dictionaryParameter = cl.getValue("dictionary");
-  lst.apply(dictionaryParameter, ",");
-
-  if(lst.size() >= 1) {  // always true (at least one, because --dictionary is mandatory)
-    anna::Tokenizer::const_iterator tok_min(lst.begin());
-    anna::Tokenizer::const_iterator tok_max(lst.end());
-    anna::Tokenizer::const_iterator tok_iter;
-    std::string pathFile;
-    d->allowUpdates();
-
-    for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
-      pathFile = anna::Tokenizer::data(tok_iter);
-      d->load(pathFile);
+  std::string stacks = cl.getValue("stacks");
+  bool multistack = false;
+  try {
+    anna::Tokenizer stacksTok;
+    stacksTok.apply(stacks, "#");
+    anna::Tokenizer::const_iterator stacks_it, stack_it;
+
+    for(stacks_it = stacksTok.begin(); stacks_it != stacksTok.end(); stacks_it++) {
+      std::string stack = anna::Tokenizer::data(stacks_it);
+      anna::Tokenizer stackTok;
+      stackTok.apply(stack, ",");
+
+      if(stackTok.size() == 1) {
+        if(stacksTok.size() != 1)
+          throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION);
+
+        anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* no matter */, stack); // the stack is the dictionary
+        codecEngine->setDictionary(d);
+        break;
+      }
+
+      if(stackTok.size() != 2)
+        throw anna::RuntimeException("Each stack must be in the form '<application-id>,<xml dictionary pathfile>'", ANNA_FILE_LOCATION);
+
+      multistack = true;
+      stack_it = stackTok.begin();
+      unsigned int stackId = atoll(anna::Tokenizer::data(stack_it));
+      stack_it++;
+      std::string file = anna::Tokenizer::data(stack_it);
+      anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(stackId, file);
     }
-  }
 
-  getCodecEngine()->setDictionary(d); // XXXX esto cambiara...
-  LOGDEBUG(anna::Logger::debug(getCodecEngine()->asString(), ANNA_FILE_LOCATION));
+    // Auto stack selection based on Application-ID:
+    if (multistack) getCodecEngine()->selectStackWithApplicationId(true);
 
-  if(lst.size() > 1) {
-    std::string all_in_one = "./dictionary-all-in-one.xml";
-    std::ofstream out(all_in_one.c_str(), std::ifstream::out);
-    std::string buffer = d->asXMLString();
-    out.write(buffer.c_str(), buffer.size());
-    out.close();
-    std::cout << "Written accumulated '" << all_in_one << "' (provide it next time to be more comfortable)." << std::endl;
+    std::cout << "Stacks provided:          " << std::endl;
+    std::cout << anna::functions::tab(stackEngine.asString(false /* light */));
+    std::cout << std::endl;
+  } catch(anna::RuntimeException &ex) {
+    _exit(ex.asString());
   }
+  //LOGDEBUG(anna::Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION));
+
 
   ///////////////////////////////
   // Diameter library COUNTERS //
@@ -952,7 +1001,7 @@ std::string Launcher::help() const throw() {
   result += "\n   vi /var/tmp/anna.context.<pid>";
   result += "\n";
   result += "\nA complete xml report will show all the context information (counters, alarms, statistics,";
-  result += "\n handlers, diameter dictionary, etc.), and a powerful log module could dump all the events";
+  result += "\n handlers, diameter stacks, etc.), and a powerful log module could dump all the events";
   result += "\n processed and flow information. Statistics could be analized at context dump and optionally";
   result += "\n written to disk as sample files (useful for graphs and spreadsheet reports) with all the";
   result += "\n measurements.";
@@ -967,8 +1016,8 @@ std::string Launcher::help() const throw() {
   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";
-  result += "\nAs mandatory, the stack definition given through the xml dictionary:";
-  result += "\n   --dictionary <path to dictionary file>";
+  result += "\nAs mandatory, the stacks enabled given through the application-id and the xml dictionary:";
+  result += "\n   --stacks <appid1,dictionary1#appid2,dictionary2#...#appidN,dictionaryN>";
   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";
@@ -998,6 +1047,11 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\nhelp                                 This help. Startup information-level traces also dump this help.";
   result += "\n";
+  result += "\n--------------------------------------------------------------------------------------- Stack selection";
+  result += "\n";
+  result += "\nstack|<id>                           Select current working stack id (node selection). Many operations";
+  result += "                                        could use this value if proceed, in multistack configurations.";
+  result += "\n";
   result += "\n------------------------------------------------------------------------------------ Parsing operations";
   result += "\n";
   result += "\ncode|<source_file>|<target_file>     Encodes source file (pathfile) into target file (pathfile).";
@@ -1075,14 +1129,14 @@ std::string Launcher::help() const throw() {
   result += "\n    to the peer which sent the request. If user wants to test a specific answer without changing it,";
   result += "\n    use sendxml/sendhex operations better than programming.";
   result += "\n";
-  result += "\nBalance ('-balance' command line parameter) could be used to forward server socket receptions through";
+  result += "\nBalance ('--balance' command line parameter) could be used to forward server socket receptions through";
   result += "\n entity servers by mean a round-robin algorithm. Both diameter server socket and entity targets should";
   result += "\n have been configured, that is to say: launcher acts as client and server. If no balance is used, an";
   result += "\n standard delivery is performed: first primary entity server, secondary when fails, etc.";
   result += "\n";
   result += "\n--------------------------------------------------------------------------- Processing types (log tags)";
   result += "\n";
-  result += "\nUsed as log file extensions (when '-splitLog' is provided on command line) and context preffixes on log";
+  result += "\nUsed as log file extensions (when '--splitLog' is provided on command line) and context preffixes on log";
   result += "\n details when unique log file is dumped:";
   result += "\n";
   result += "\n   [sent2e/send2eError]   Send to entity (success/error)";
@@ -1115,7 +1169,7 @@ std::string Launcher::help() const throw() {
   result += "\n   burst|push|<load amount>    Sends specific non-aynchronous load.";
   result += "\n   burst|pop|<release amount>  Skip send burst messages in order to reduce over-the-air requests.";
   result += "\n                               Popping all OTA requests implies burst stop because no more answer";
-  result += "\n                                will arrive to the process. Burst output file (-burstLog command";
+  result += "\n                                will arrive to the process. Burst output file (--burstLog command";
   result += "\n                                line parameter) shows popped messages with crosses (x). Each cross";
   result += "\n                                represents one received answer for which no new request is sent.";
   result += "\n   burst|stop                  Stops the burst cycle. You can resume pushing 1 load amount.";
@@ -1135,7 +1189,7 @@ std::string Launcher::help() const throw() {
   result += "\n------------------------------------------------------------------------- Operations via HTTP interface";
   result += "\n";
   result += "\nAll the operations described above can be used through the optional HTTP interface. You only have";
-  result += "\n to define the http server at the command line with something like: '-httpServer localhost:9000'.";
+  result += "\n to define the http server at the command line with something like: '--httpServer localhost:9000'.";
   result += "\nTo send the task, we shall build the http request body with the operation string. Some examples";
   result += "\n using curl client could be:";
   result += "\n";
@@ -1685,3 +1739,4 @@ throw() {
   anna::statistics::Engine::instantiate().asXML(result);
   return result;
 }
+
index d7e4bba..f5f1eb9 100644 (file)
@@ -50,14 +50,15 @@ class Launcher : public anna::comm::Application {
   anna::timex::Engine* a_timeEngine;
   MyCounterRecorder *a_counterRecorder;
   MyCounterRecorderClock *a_counterRecorderClock;
-  std::string a_cerPathfile;
-  std::string a_dwrPathfile;
+  std::string a_cerPathfile; // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  std::string a_dwrPathfile; // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  std::string a_workingNode; // this is the node name (usually equals to the Origin-Realm value
 
   // Burst feature
   int a_burstCycle;
   bool a_burstRepeat;
   bool a_burstActive;
-  std::map < int /* dummy, p.e. used for order number */, anna::diameter::comm::Message* > a_burstMessages;
+  std::map < int /* dummy, p.e. used for order number */, anna::diameter::comm::Message* > a_burstMessages; // XXXXXXXXXXXXXXXXXXXXX
   int a_burstLoadIndx;
   std::map<int, anna::diameter::comm::Message*>::const_iterator a_burstDeliveryIt;
   int a_otaRequest;
@@ -67,7 +68,7 @@ class Launcher : public anna::comm::Application {
   anna::Recycler<anna::diameter::comm::Message> a_commMessages;
 
   anna::comm::ServerSocket* a_httpServerSocket; // HTTP
-  MyLocalServer* a_diameterLocalServer; // DIAMETER
+  MyLocalServer* a_diameterLocalServer; // DIAMETER  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   void checkTimeMeasure(const char * commandLineParameter, bool optional = true) throw(anna::RuntimeException);
   void initialize() throw(anna::RuntimeException); // HTTP
   void run() throw(anna::RuntimeException);
@@ -75,22 +76,24 @@ class Launcher : public anna::comm::Application {
 public:
   Launcher();
 
-  anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; } // XXXXXXXXXXXXXXXXX El del nodo de trabajo
+  anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; }
+  std::string getWorkingNode() const throw() { return a_workingNode; }
+  void setWorkingNode(const std::string &node) throw() { a_workingNode = node; }
   MyCommunicator *getCommunicator() throw() { return a_communicator; }
   MyDiameterEngine* getMyDiameterEngine() const throw() { return (a_myDiameterEngine); }
-  void baseProtocolSetupAsClient() throw(anna::RuntimeException);
-  MyDiameterEntity *getEntity() throw() { return a_entity; }
-  MyLocalServer* getDiameterLocalServer() throw() { return a_diameterLocalServer; }
+  void baseProtocolSetupAsClient(void) throw(anna::RuntimeException);
+  MyDiameterEntity *getEntity() throw() { return a_entity; } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+  MyLocalServer* getDiameterLocalServer() throw() { return a_diameterLocalServer; } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   void eventOperation(const std::string &, std::string &) throw(anna::RuntimeException);
   bool logEnabled() const throw() { return (((a_logFile == "") || (a_logFile == "null")) ? false : true); }
-  void writeLogFile(const anna::DataBlock & db, const std::string &logExtension, const std::string &detail, anna::diameter::codec::Engine *codecEngine) const throw();
-  void writeLogFile(const anna::diameter::codec::Message & decodedMessage, const std::string &logExtension, const std::string &detail) const throw();
+  void writeLogFile(const anna::DataBlock & db, const std::string &logExtension, const std::string &detail) const throw(); // XXXXXXXXXXXXXXXXXXXXX
+  void writeLogFile(const anna::diameter::codec::Message & decodedMessage, const std::string &logExtension, const std::string &detail) const throw(); // XXXXXXXXXXXXXXXXXX
   void writeBurstLogFile(const std::string &buffer) throw();
   bool burstLogEnabled() const throw() { return (((a_burstLogFile == "") || (a_burstLogFile == "null")) ? false : true); }
-  void startDiameterServer(int) throw(anna::RuntimeException);
+  void startDiameterServer(int) throw(anna::RuntimeException); // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   void forceCountersRecord() throw(anna::RuntimeException) { if (a_counterRecorderClock) a_counterRecorderClock->tick(); }
 
-  anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
+  anna::xml::Node* asXML(anna::xml::Node* parent) const throw(); // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   void resetStatistics() throw() { a_myDiameterEngine->resetStatistics(); }
   void resetCounters() throw();
   void signalUSR2() throw(anna::RuntimeException);
index d16974b..6a27607 100644 (file)
@@ -11,6 +11,8 @@
 #include <anna/diameter/functions.hpp>
 #include <anna/time/functions.hpp>
 #include <anna/diameter.comm/Response.hpp>
+#include <anna/diameter/helpers/base/functions.hpp>
+#include <anna/diameter/helpers/dcca/functions.hpp>
 
 // Process
 #include "MyDiameterEntity.hpp"
@@ -45,6 +47,50 @@ void MyDiameterEntity::eventRequestRetransmission(const anna::diameter::comm::Cl
 }
 
 
+int MyDiameterEntity::readSocketId(const anna::diameter::comm::Message* message, int maxClientSessions) const throw() {
+  CommandLine& cl(anna::CommandLine::instantiate());
+  std::string sessionBasedModelsType = (cl.exists("sessionBasedModelsClientSocketSelection") ? cl.getValue("sessionBasedModelsClientSocketSelection") : "SessionIdLowPart");
+
+  if(sessionBasedModelsType == "RoundRobin") return -1;  // IEC also would return -1
+
+  try {
+    // Service-Context-Id:
+    anna::diameter::helpers::dcca::ChargingContext::_v chargingContext;
+    std::string scid = anna::diameter::helpers::dcca::functions::getServiceContextId(message->getBody(), chargingContext);
+
+    switch(chargingContext) {
+    case anna::diameter::helpers::dcca::ChargingContext::Data:
+    case anna::diameter::helpers::dcca::ChargingContext::Voice:
+    case anna::diameter::helpers::dcca::ChargingContext::Content: {
+      // Session-Id: '<DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>="">]'
+      std::string sid = anna::diameter::helpers::base::functions::getSessionId(message->getBody());
+      std::string diameterIdentity, optional;
+      anna::U32 high, low;
+      anna::diameter::helpers::base::functions::decodeSessionId(sid, diameterIdentity, high, low /* context-teid */, optional);
+
+      if(sessionBasedModelsType == "SessionIdLowPart") return (low % maxClientSessions);
+
+      if(sessionBasedModelsType == "SessionIdHighPart") return (high % maxClientSessions);
+
+      if(sessionBasedModelsType == "SessionIdOptionalPart") return (atoi(optional.c_str()) % maxClientSessions);
+    }
+    case anna::diameter::helpers::dcca::ChargingContext::SMS:
+    case anna::diameter::helpers::dcca::ChargingContext::MMS:
+    case anna::diameter::helpers::dcca::ChargingContext::Unknown:
+    default:
+       return -1; // IEC model and Unknown traffic types
+    }
+  } catch(anna::RuntimeException &ex) {
+    LOGDEBUG(
+      std::string msg = ex.getText();
+      msg += " | Round-robin between sessions will be used to send";
+      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+    );
+  }
+
+  return -1;
+}
+
 void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message)
 throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequest", ANNA_FILE_LOCATION));
diff --git a/example/diameter/launcher/Node.cpp b/example/diameter/launcher/Node.cpp
new file mode 100644 (file)
index 0000000..2d87d8a
--- /dev/null
@@ -0,0 +1,110 @@
+// ANNA - Anna is Not Nothingness Anymore                                                         //
+//                                                                                                //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
+//                                                                                                //
+// 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 <string>
+
+// Project
+//#include <anna/diameter/codec/Engine.hpp>
+
+// Process
+#include "Node.hpp"
+
+
+void Node::clear () throw() {
+  for (reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
+       anna::diameter::codec::Engine *engine = anna::functions::component <Engine> (ANNA_FILE_LOCATION);
+       engine->releaseMessage(*(it->second->begin()));
+       delete(it->second);
+  }
+  a_deques.clear();
+}
+
+void Node::dump () throw() {
+  std::string outfilename, xmlString;
+  for(reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
+       int sequence = 1;
+       for(codec_messages_deque_const_iterator itm = it->second->begin(); itm != it->second->end(); itm++) {
+         // programmed_answer.<code>.<sequence>
+         outfilename = "programmed_answer.";
+         outfilename += anna::functions::asString(it->first);
+         outfilename += ".";
+         outfilename += anna::functions::asString(sequence++);
+         outfilename += ".xml";
+         std::ofstream outfile(outfilename.c_str(), std::ifstream::out);
+         xmlString =  (*itm)->asXMLString();
+         outfile.write(xmlString.c_str(), xmlString.size());
+         outfile.close();
+       }
+  }
+}
+
+void Node::addMessage(int code, anna::diameter::codec::Message *message) throw() {
+  reacting_answers_const_iterator it = a_deques.find(code);
+  if (it != a_deques.end()) {
+       it->second->push_back(message);
+  }
+  else {
+       codec_messages_deque *deque = new codec_messages_deque;
+       a_deques[code] = deque;
+       deque->push_back(message);
+  }
+}
+
+anna::diameter::codec::Message* Node::getMessage(int code) const throw() { //get the front message (begin()), returns NULL if deque is empty
+  anna::diameter::codec::Message *result = NULL;
+  reacting_answers_const_iterator it = a_deques.find(code);
+  if (it != a_deques.end()) {
+       if (!it->second->empty()) result = *(it->second->begin());
+  }
+  return result;
+}
+
+void Node::nextMessage(int code) throw() { //pops the deque and release the message (when deque is not empty: deque::empty)
+  reacting_answers_const_iterator it = a_deques.find(code);
+  if (it != a_deques.end()) {
+       if (!it->second->empty()) {
+         anna::diameter::codec::Engine *engine = anna::functions::component <Engine> (ANNA_FILE_LOCATION);
+         if (a_rotate) {
+               addMessage(code, *(it->second->begin()));
+         }
+         else {
+               engine->releaseMessage(*(it->second->begin()));
+         }
+         it->second->pop_front();
+       }
+  }
+}
+
+std::string Node::asString(const char *queueName) const throw() {
+  std::string result = "";
+  std::string aux = "FIFO QUEUE '";
+  aux += queueName;
+  aux += "', Rotation ";
+  aux += a_rotate ? "enabled":"disabled";
+  result += anna::functions::highlightJustify(aux);
+  if(a_deques.size() != 0) {
+       for(reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) {
+         if (it->second->size() != 0) {
+               aux = "Answer code ";
+               aux += anna::functions::asString(it->first);
+               result += anna::functions::highlightJustify(aux, anna::functions::TextHighlightMode::OverAndUnderline,
+                                                                                                                anna::functions::TextJustifyMode::Left, '-');
+               for(codec_messages_deque_const_iterator itm = it->second->begin(); itm != it->second->end(); itm++) {
+                 result += (*itm)->asXMLString();
+                 result += "\n";
+               }
+               result += "\n";
+         }
+       }
+  }
+  else {
+       result = "No ocurrences found\n\n";
+  }
+  return result;
+}
diff --git a/example/diameter/launcher/Node.hpp b/example/diameter/launcher/Node.hpp
new file mode 100644 (file)
index 0000000..95b6af2
--- /dev/null
@@ -0,0 +1,48 @@
+// ANNA - Anna is Not Nothingness Anymore                                                         //
+//                                                                                                //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
+//                                                                                                //
+// 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 //
+
+
+#ifndef example_diameter_launcher_Node_hpp
+#define example_diameter_launcher_Node_hpp
+
+// Standard
+#include <string>
+
+// Process
+#include "MyDiameterEntity.hpp"
+#include "MyLocalServer.hpp"
+
+
+class Node {
+
+  std::string a_name;
+  unsigned int a_applicationId;
+  std::string a_cer; // path file
+  std::string a_dwr; // path file
+  MyDiameterEntity *a_entity;
+  MyLocalServer *a_diameterServer;
+  bool a_balance; // Balance over entity servers instead of doing standard behaviour (first primary, secondary if fails, etc.). Default: false.
+  bool a_ignoreErrors; // default: false
+
+
+public:
+  Node() { a_rotate = false; }
+  ~Node() { clear(); }
+
+
+  bool rotate() const throw() { return a_rotate; }
+  void rotate(bool r) throw() { a_rotate = r; }
+
+  void clear () throw();
+  void dump () throw();
+  void addMessage(int code, anna::diameter::codec::Message *message) throw();
+  anna::diameter::codec::Message* getMessage(int code) const throw();
+  void nextMessage(int code) throw();
+  std::string asString(const char *queueName) const throw();
+};
+
+#endif
diff --git a/example/diameter/launcher/deployments/basic/hex_examples b/example/diameter/launcher/deployments/basic/hex_examples
new file mode 120000 (symlink)
index 0000000..0a74a2d
--- /dev/null
@@ -0,0 +1 @@
+../../resources/hex_examples/
\ No newline at end of file
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/aar-bad.hex b/example/diameter/launcher/deployments/basic/hex_examples/aar-bad.hex
deleted file mode 100644 (file)
index 7588fa1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-01000150c000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c000006c000028af00000206c0000010000028af00000000000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000021000001c24000000c00000000000001bc4000001136323630333730393900000000000008400000133139322e3136382e302e31000000001e400000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/aar.hex b/example/diameter/launcher/deployments/basic/hex_examples/aar.hex
deleted file mode 100644 (file)
index 9a2aeb9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-01000150c000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c000006c000028af00000206c0000010000028af00000000000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000028000001c24000000c00000000000001bc4000001136323630333730393900000000000008400000133139322e3136382e302e31000000001e400000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/aar2-bad.hex b/example/diameter/launcher/deployments/basic/hex_examples/aar2-bad.hex
deleted file mode 100644 (file)
index 4b5c1ed..0000000
+++ /dev/null
@@ -1 +0,0 @@
-0100017cc000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c0000098000028af00000206c0000010000028af0000000000000207c000002c000028af000001fdc0000010000028af00000037000001ffc000000a000028af00000000000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000028000001c24000000c00000000000001bc4000001136323630333730393900000000000008000000133139322e3136382e302e31000000001e000000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/aar3-bad.hex b/example/diameter/launcher/deployments/basic/hex_examples/aar3-bad.hex
deleted file mode 100644 (file)
index 62f45ba..0000000
+++ /dev/null
@@ -1 +0,0 @@
-0100017cc000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c0000098000028af00000206c0000010000028af0000000000000207c000002c000028af000001fdc0000010000028af00000037000001ffc0000010000028af00000010000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000028000001c24000000c00000000000001bc4000001136323630333730393900000000000008000000133139322e3136382e302e31000000001e000000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/readme.txt b/example/diameter/launcher/deployments/basic/hex_examples/readme.txt
deleted file mode 100644 (file)
index 6b66557..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Bad messages:
-
-aar-bad.hex: comes from ../xml_examples/aar.xml
-             Consists in a deliberated bad length encoded on grouped Subscription-Id length field (not multiple of 4).
-
-aar2-bad.hex: comes from ../xml_examples/aar2.xml
-              Consists in a deliberated bad length encoded on enumerated Flow-Status avp 2-level nested inside Media-Component-Description:
-                         -> Media-Component-Description  (grouped)
-                            -> Media-Sub-Component       (grouped)
-                               -> Flow-Status            (enumerated)
-
-aar3-bad.hex: comes from ../xml_examples/aar2.xml
-              Consists in a deliberated bad value (16) encoded on enumerated Flow-Status avp (range 0-15) 2-level nested inside Media-Component-Description:
-                         -> Media-Component-Description  (grouped)
-                            -> Media-Sub-Component       (grouped)
-                               -> Flow-Status            (enumerated)
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/tspCCA.hex b/example/diameter/launcher/deployments/basic/hex_examples/tspCCA.hex
deleted file mode 100644 (file)
index 401687a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-0100018c4000011001000016ff7f245e9b81ce71000001074000003f63302d31302d37302d3233382d37342d7735703176657067312e766570632e6572696373736f6e2e73653b313430323932373534343b33000000010c4000000c000007d10000010840000019657063322e6570637265616c6d2e636f6d00000000000128400000146570637265616c6d2e636f6d000001026000000c01000016000001a06000000c000000010000019f6000000c00000000000003f8c000002c000028af00000410c0000010000028af004e200000000411c0000010000028af0007d00000000419c0000058000028af00000404c0000010000028af000000060000040ac000003c000028af00000416c0000010000028af000000030000041780000010000028af000000010000041880000010000028af000000000000027480000038000028af0000010a4000000c000028af0000027580000010000028af000000010000027680000010000028af00000003000003ffc0000010000028af00000002000001164000000c00000005
diff --git a/example/diameter/launcher/deployments/basic/hex_examples/tspCCR.hex b/example/diameter/launcher/deployments/basic/hex_examples/tspCCR.hex
deleted file mode 100644 (file)
index 492384a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-010002e8c000011001000016ff7f245e9b81ce71000001074000003f63302d31302d37302d3233382d37342d7735703176657067312e766570632e6572696373736f6e2e73653b313430323932373534343b3300000001026000000c01000016000001084000003263302d31302d37302d3233382d37342d7735703176657067312e766570632e6572696373736f6e2e736500000000012840000018766570632e6572696373736f6e2e73650000011b600000146570637265616c6d2e636f6d000001a06000000c000000010000019f6000000c0000000000000017c000000e000028af80010000000001166000000c00000000000001bb60000028000001c26000000c00000000000001bc60000013343637303139343034313800000000086000000c0a46ee6200000403c0000010000028af0000000500000015e000000d000028af060000000000040880000010000028af000003ec000001ca6000002c000001cb2000000c00000000000001cc2000001833353734373330343030363632383030000003f8c000002c000028af0000041080000010000028af08f0d1800000041180000010000028af02faf0800000041980000058000028af00000404c0000010000028af000000090000040ac000003c000028af0000041680000010000028af000000020000041780000010000028af000000010000041880000010000028af0000000000000012e0000011000028af32343039390000000000041a80000012000028af00010a46ee3a000000000016c0000019000028af8242f099006742f0990186a4010000000000001e6000000d7665706731000000000003e8c0000010000028af0000000000000400c0000010000028af00000001000001f5c0000012000028af00010a46ee3a0000000003fec0000020000028af000001f7c0000013000028af34383030303438000000027480000038000028af0000010a4000000c000028af0000027580000010000028af000000010000027680000010000028af00000003
deleted file mode 100755 (executable)
index 5f3afc0bae38abbc087f68cf9fad252c0c5f7eb4..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-
-#############
-# FUNCTIONS #
-#############
-_exit () {
-  echo
-  echo -e $1
-  echo
-  exit 1
-}
-
-#############
-# EXECUTION #
-#############
-cd `dirname $0`
-echo
-# Get the PID:
-[ ! -f .pid ] && _exit "Can't found '`pwd`/.pid'.\nTry to pgrep your process name and dump pid to that file."
-PID=`cat .pid`
-
-# Send operation:
-[ "$1" = "" ] && _exit "Use: $0 <operation string>; i.e.: $0 help"
-echo $1 > sigusr2.tasks.input
-kill -s SIGUSR2 $PID
-
-sleep 1
-echo
-echo
-echo "You could see results on '`pwd`/sigusr2.tasks.output' file."
-echo
-echo
-
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..c9b45aec9f2c541d286b37d67b94090a602174a8
--- /dev/null
@@ -0,0 +1 @@
+../../resources/scripts/operation_signal.sh
\ No newline at end of file
diff --git a/example/diameter/launcher/deployments/basic/xml_examples b/example/diameter/launcher/deployments/basic/xml_examples
new file mode 120000 (symlink)
index 0000000..c18402a
--- /dev/null
@@ -0,0 +1 @@
+../../resources/xml_examples
\ No newline at end of file
diff --git a/example/diameter/launcher/deployments/basic/xml_examples/aaa.xml b/example/diameter/launcher/deployments/basic/xml_examples/aaa.xml
deleted file mode 100644 (file)
index 4892138..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<message version="1" name="AA-Answer" application-id="16777236" hop-by-hop-id="202475" end-by-end-id="509476">
-   <avp name="Auth-Application-Id" data="16777236"/>
-   <avp name="Session-Id" data="test1;afNodeHostname.afNodeHostRealm.com;1;8033450"/>
-   <avp name="Origin-Host" data="sapcOwnHostId.operatorRealm.com"/>
-   <avp name="Origin-State-Id" data="1428633668"/>
-   <avp name="Origin-Realm" data="operatorRealm.com"/>
-   <avp name="Experimental-Result">
-      <avp name="Vendor-Id" data="10415"/>
-      <avp name="Experimental-Result-Code" data="5063"/>
-   </avp>
-</message>
diff --git a/example/diameter/launcher/deployments/basic/xml_examples/aar.xml b/example/diameter/launcher/deployments/basic/xml_examples/aar.xml
deleted file mode 100644 (file)
index 1201655..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<message version="1" name="AA-Request" p-bit="yes" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
-   <avp name="Session-Id" data="ocs3;1332774430;1;1332774430"/>
-   <avp name="Auth-Application-Id" data="16777236"/>
-   <avp name="Origin-Host" data="OCS3"/>
-   <avp name="Origin-Realm" data="OCS3"/>
-   <avp name="Destination-Realm" data="OCS3"/>
-   <avp name="Destination-Host" data="OCS3"/>
-   <avp name="AF-Application-Identifier" hex-data="313232"/>
-   <avp name="Media-Component-Description">
-      <avp name="Media-Component-Number" data="0"/>
-      <avp name="AF-Application-Identifier" hex-data="313232"/>
-      <avp name="Max-Requested-Bandwidth-UL" data="127"/>
-      <avp name="Max-Requested-Bandwidth-DL" data="133"/>
-      <avp name="Flow-Status" data="2" alias="ENABLED"/>
-      <avp name="Reservation-Priority" data="0" alias="DEFAULT"/>
-   </avp>
-   <avp name="Service-Info-Status" data="0" alias="FINAL_SERVICE_INFORMATION"/>
-   <avp name="Subscription-Id">
-      <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
-      <avp name="Subscription-Id-Data" data="626037099"/>
-   </avp>
-   <avp name="Framed-IP-Address" hex-data="3139322e3136382e302e31"/>
-   <avp name="Called-Station-Id" data="WAP.MOVISTAR"/>
-</message>
diff --git a/example/diameter/launcher/deployments/basic/xml_examples/aar2.xml b/example/diameter/launcher/deployments/basic/xml_examples/aar2.xml
deleted file mode 100644 (file)
index c163fb4..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<message version="1" name="AA-Request" p-bit="yes" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
-   <avp name="Session-Id" data="ocs3;1332774430;1;1332774430"/>
-   <avp name="Auth-Application-Id" data="16777236"/>
-   <avp name="Origin-Host" data="OCS3"/>
-   <avp name="Origin-Realm" data="OCS3"/>
-   <avp name="Destination-Realm" data="OCS3"/>
-   <avp name="Destination-Host" data="OCS3"/>
-   <avp name="AF-Application-Identifier" hex-data="313232"/>
-   <avp name="Media-Component-Description">
-      <avp name="Media-Component-Number" data="0"/>
-      <avp name="Media-Sub-Component">
-         <avp name="Flow-Number" data="55"/>
-         <avp name="Flow-Status" data="0" alias="ENABLED-UPLINK"/>
-      </avp>
-      <avp name="AF-Application-Identifier" hex-data="313232"/>
-      <avp name="Max-Requested-Bandwidth-UL" data="127"/>
-      <avp name="Max-Requested-Bandwidth-DL" data="133"/>
-      <avp name="Flow-Status" data="2" alias="ENABLED"/>
-      <avp name="Reservation-Priority" data="0" alias="DEFAULT"/>
-   </avp>
-   <avp name="Service-Info-Status" data="0" alias="FINAL_SERVICE_INFORMATION"/>
-   <avp name="Subscription-Id">
-      <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
-      <avp name="Subscription-Id-Data" data="626037099"/>
-   </avp>
-   <avp name="Framed-IP-Address" hex-data="3139322e3136382e302e31"/>
-   <avp name="Called-Station-Id" data="WAP.MOVISTAR"/>
-</message>
diff --git a/example/diameter/launcher/deployments/basic/xml_examples/ccr.xml b/example/diameter/launcher/deployments/basic/xml_examples/ccr.xml
deleted file mode 100644 (file)
index 46483a2..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<message version="1" name="Credit-Control-Request" p-bit="yes" application-id="4" hop-by-hop-id="1" end-by-end-id="1">
-   <avp name="Session-Id" data="module-2.PTS2-BOG.sandvine.com;1287115741;0;0"/>
-   <avp name="Origin-Host" data="module-2.PTS2-BOG.sandvine.com"/>
-   <avp name="Origin-Realm" data="sandvine.com"/>
-   <avp name="Destination-Realm" data="telefonica.com.co"/>
-   <avp name="Auth-Application-Id" data="4"/>
-   <avp name="Service-Context-Id" data="770.32251@3gpp.org"/>
-   <avp name="CC-Request-Type" data="1" alias="INITIAL_REQUEST"/>
-   <avp name="CC-Request-Number" data="0"/>
-   <avp name="User-Name" data="50583211675"/>
-   <avp name="Origin-State-Id" data="1339077627"/>
-   <avp name="Event-Timestamp" data="3548171033"/>
-   <avp name="Subscription-Id">
-      <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
-      <avp name="Subscription-Id-Data" data="50583211675"/>
-   </avp>
-   <avp name="Multiple-Services-Indicator" data="1" alias="MULTIPLE_SERVICES_SUPPORTED"/>
-   <avp name="User-Equipment-Info">
-      <avp name="User-Equipment-Info-Type" data="0" alias="IMEISV"/>
-      <avp name="User-Equipment-Info-Value" hex-data="33353430343630343130363438333030"/>
-   </avp>
-   <avp name="Service-Information">
-      <avp name="PS-Information">
-         <avp name="3GPP-Charging-Id" data="29"/>
-         <avp name="3GPP-PDP-Type" data="0" alias="IPV4"/>
-         <avp name="PDP-Address" data="10.193.49.133"/>
-         <avp name="3GPP-GPRS-Neg-QoS-Profile" data="05-1b921f7196fefe74fbfefe00"/>
-         <avp name="SGSN-Address" data="190.98.183.240"/>
-         <avp name="GGSN-Address" data="190.98.183.243"/>
-         <avp name="CG-Address" data="10.193.249.1"/>
-         <avp name="3GPP-IMSI-MCC-MNC" data="71204"/>
-         <avp name="3GPP-GGSN-MCC-MNC" data="71204"/>
-         <avp name="3GPP-NSAPI" data="5"/>
-         <avp name="Called-Station-Id" data="internet.movistar.ni"/>
-         <avp name="3GPP-Selection-Mode" data="0"/>
-         <avp name="3GPP-Charging-Characteristics" data="0800"/>
-         <avp name="3GPP-SGSN-MCC-MNC" data="33403"/>
-         <avp name="3GPP-MS-TimeZone" hex-data="4a00"/>
-         <avp name="3GPP-User-Location-Info" hex-data="0117f240a4780218"/>
-         <avp name="3GPP-Rat-Type" hex-data="01"/>
-         <avp name="PDP-Context-Type" data="0"/>
-      </avp>
-   </avp>
-</message>
index 9eee58b..74e9662 120000 (symlink)
@@ -1 +1 @@
-../basic/hex_examples
\ No newline at end of file
+../../resources/hex_examples
\ No newline at end of file
index a61ab5e..c9b45ae 120000 (symlink)
@@ -1 +1 @@
-../basic/operation.sh
\ No newline at end of file
+../../resources/scripts/operation_signal.sh
\ No newline at end of file
index 903e6fe..c18402a 120000 (symlink)
@@ -1 +1 @@
-../basic/xml_examples
\ No newline at end of file
+../../resources/xml_examples
\ No newline at end of file
index b27f4ee..f0d780d 100644 (file)
@@ -44,7 +44,7 @@ int main(int argc, const char** argv) {
     commandLine.add("entityServerSessions", anna::CommandLine::Argument::Optional, "Diameter entity server sessions (0: diameter entity disabled). Default value of 1");
     commandLine.add("balance", anna::CommandLine::Argument::Optional, "Balance over entity servers instead of doing standard behaviour (first primary, secondary if fails, etc.)", false);
     commandLine.add("sessionBasedModelsClientSocketSelection", anna::CommandLine::Argument::Optional, "By default, round-robin will be applied for IEC model (SMS/MMS), and Session-Id Low Part will be analyzed for ECUR/SCUR model (data, voice and content). You could change ECUR/SCUR analysis behaviour providing 'SessionIdHighPart', 'SessionIdOptionalPart' (atoi applied; usually subscriber id data, i.e. MSISDN or IMSI) and 'RoundRobin'.");
-    commandLine.add("dictionary", anna::CommandLine::Argument::Mandatory, "Diameter dictionary pathfiles (could be one or more ocurrences in a comma separated list, in order to accumulate loads). For example: avps_etsi.xml,avps_ietf.xml,avps_tgpp.xml,commands_qosControl.xml");
+    commandLine.add("stacks", anna::CommandLine::Argument::Mandatory, "<appid1,dictionary1#appid2,dictionary2#...#appidN,dictionaryN>: this is a list of #-separated stacks defined by a comma-separated pair <application-id,xml dictionary pathfile>. If only one stack is provided, application-id could be omitted and then, all the messages will be decoded with the dictionary regardless the value of the application-id (the stack will be registered with id=0).");
     commandLine.add("ignoreFlags", anna::CommandLine::Argument::Optional, "Ignore flags on validation (at the moment only bits M & P from AVPs, because V bit is too important; no operation flags could be checked). Also force compact xml presentation ignoring flags during dictionary elements identification", false);
     commandLine.add("ignoreErrors", anna::CommandLine::Argument::Optional, "Local server skips requests errors analysis which would prepare automatic answers for them when a problem is found. If no answer is programmed and entity is configured, a failed request would be forwarded (delegates at the end point) even if this parameter is missing", false);
     commandLine.add("allowedInactivityTime", anna::CommandLine::Argument::Optional, "Milliseconds for the maximum allowed inactivity time on server sessions born over the local server before being reset. If missing, default value of 90000 will be assigned");
@@ -70,3 +70,4 @@ int main(int argc, const char** argv) {
 
   return 0;
 }
+
diff --git a/example/diameter/launcher/resources/hex_examples/aar-bad.hex b/example/diameter/launcher/resources/hex_examples/aar-bad.hex
new file mode 100644 (file)
index 0000000..7588fa1
--- /dev/null
@@ -0,0 +1 @@
+01000150c000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c000006c000028af00000206c0000010000028af00000000000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000021000001c24000000c00000000000001bc4000001136323630333730393900000000000008400000133139322e3136382e302e31000000001e400000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/resources/hex_examples/aar.hex b/example/diameter/launcher/resources/hex_examples/aar.hex
new file mode 100644 (file)
index 0000000..9a2aeb9
--- /dev/null
@@ -0,0 +1 @@
+01000150c000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c000006c000028af00000206c0000010000028af00000000000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000028000001c24000000c00000000000001bc4000001136323630333730393900000000000008400000133139322e3136382e302e31000000001e400000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/resources/hex_examples/aar2-bad.hex b/example/diameter/launcher/resources/hex_examples/aar2-bad.hex
new file mode 100644 (file)
index 0000000..4b5c1ed
--- /dev/null
@@ -0,0 +1 @@
+0100017cc000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c0000098000028af00000206c0000010000028af0000000000000207c000002c000028af000001fdc0000010000028af00000037000001ffc000000a000028af00000000000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000028000001c24000000c00000000000001bc4000001136323630333730393900000000000008000000133139322e3136382e302e31000000001e000000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/resources/hex_examples/aar3-bad.hex b/example/diameter/launcher/resources/hex_examples/aar3-bad.hex
new file mode 100644 (file)
index 0000000..62f45ba
--- /dev/null
@@ -0,0 +1 @@
+0100017cc000010901000014000000000000000000000107400000246f6373333b313333323737343433303b313b31333332373734343330000001024000000c01000014000001084000000c4f435333000001284000000c4f4353330000011b4000000c4f435333000001254000000c4f435333000001f8c000000f000028af3132320000000205c0000098000028af00000206c0000010000028af0000000000000207c000002c000028af000001fdc0000010000028af00000037000001ffc0000010000028af00000010000001f8c000000f000028af3132320000000204c0000010000028af0000007f00000203c0000010000028af00000085000001ffc0000010000028af00000002000001ca80000010000032db000000000000020fc0000010000028af00000000000001bb40000028000001c24000000c00000000000001bc4000001136323630333730393900000000000008000000133139322e3136382e302e31000000001e000000145741502e4d4f564953544152
diff --git a/example/diameter/launcher/resources/hex_examples/readme.txt b/example/diameter/launcher/resources/hex_examples/readme.txt
new file mode 100644 (file)
index 0000000..6b66557
--- /dev/null
@@ -0,0 +1,16 @@
+Bad messages:
+
+aar-bad.hex: comes from ../xml_examples/aar.xml
+             Consists in a deliberated bad length encoded on grouped Subscription-Id length field (not multiple of 4).
+
+aar2-bad.hex: comes from ../xml_examples/aar2.xml
+              Consists in a deliberated bad length encoded on enumerated Flow-Status avp 2-level nested inside Media-Component-Description:
+                         -> Media-Component-Description  (grouped)
+                            -> Media-Sub-Component       (grouped)
+                               -> Flow-Status            (enumerated)
+
+aar3-bad.hex: comes from ../xml_examples/aar2.xml
+              Consists in a deliberated bad value (16) encoded on enumerated Flow-Status avp (range 0-15) 2-level nested inside Media-Component-Description:
+                         -> Media-Component-Description  (grouped)
+                            -> Media-Sub-Component       (grouped)
+                               -> Flow-Status            (enumerated)
diff --git a/example/diameter/launcher/resources/hex_examples/tspCCA.hex b/example/diameter/launcher/resources/hex_examples/tspCCA.hex
new file mode 100644 (file)
index 0000000..401687a
--- /dev/null
@@ -0,0 +1 @@
+0100018c4000011001000016ff7f245e9b81ce71000001074000003f63302d31302d37302d3233382d37342d7735703176657067312e766570632e6572696373736f6e2e73653b313430323932373534343b33000000010c4000000c000007d10000010840000019657063322e6570637265616c6d2e636f6d00000000000128400000146570637265616c6d2e636f6d000001026000000c01000016000001a06000000c000000010000019f6000000c00000000000003f8c000002c000028af00000410c0000010000028af004e200000000411c0000010000028af0007d00000000419c0000058000028af00000404c0000010000028af000000060000040ac000003c000028af00000416c0000010000028af000000030000041780000010000028af000000010000041880000010000028af000000000000027480000038000028af0000010a4000000c000028af0000027580000010000028af000000010000027680000010000028af00000003000003ffc0000010000028af00000002000001164000000c00000005
diff --git a/example/diameter/launcher/resources/hex_examples/tspCCR.hex b/example/diameter/launcher/resources/hex_examples/tspCCR.hex
new file mode 100644 (file)
index 0000000..492384a
--- /dev/null
@@ -0,0 +1 @@
+010002e8c000011001000016ff7f245e9b81ce71000001074000003f63302d31302d37302d3233382d37342d7735703176657067312e766570632e6572696373736f6e2e73653b313430323932373534343b3300000001026000000c01000016000001084000003263302d31302d37302d3233382d37342d7735703176657067312e766570632e6572696373736f6e2e736500000000012840000018766570632e6572696373736f6e2e73650000011b600000146570637265616c6d2e636f6d000001a06000000c000000010000019f6000000c0000000000000017c000000e000028af80010000000001166000000c00000000000001bb60000028000001c26000000c00000000000001bc60000013343637303139343034313800000000086000000c0a46ee6200000403c0000010000028af0000000500000015e000000d000028af060000000000040880000010000028af000003ec000001ca6000002c000001cb2000000c00000000000001cc2000001833353734373330343030363632383030000003f8c000002c000028af0000041080000010000028af08f0d1800000041180000010000028af02faf0800000041980000058000028af00000404c0000010000028af000000090000040ac000003c000028af0000041680000010000028af000000020000041780000010000028af000000010000041880000010000028af0000000000000012e0000011000028af32343039390000000000041a80000012000028af00010a46ee3a000000000016c0000019000028af8242f099006742f0990186a4010000000000001e6000000d7665706731000000000003e8c0000010000028af0000000000000400c0000010000028af00000001000001f5c0000012000028af00010a46ee3a0000000003fec0000020000028af000001f7c0000013000028af34383030303438000000027480000038000028af0000010a4000000c000028af0000027580000010000028af000000010000027680000010000028af00000003
diff --git a/example/diameter/launcher/resources/pcap2diameterHex.sh b/example/diameter/launcher/resources/pcap2diameterHex.sh
deleted file mode 100755 (executable)
index 355b70f..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/bin/bash
-
-# ANNA - Anna is Not Nothingness Anymore
-#
-# (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-#
-# http://redmine.teslayout.com/projects/anna-suite
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     *  Neither the name of the copyright holder nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: eduardo.ramos.testillano@gmail.com
-#          cisco.tierra@gmail.com
-
-
-#############
-# VARIABLES #
-#############
-tmpdir=$(mktemp -d)
-
-#############
-# FUNCTIONS #
-#############
-
-usage () {
-  echo "Usage: $0 <pcap_file> [results_dir]"
-  echo
-  echo "       pcap_file:   pcap formatted file to be processed."
-  echo "       results_dir: directory where results are stored."
-  echo "                    By default, pcap file dirname is used."
-  echo
-  echo "       The utility, dumps the extracted hexadecimal content"
-  echo "       and useful information as timestamps, source and"
-  echo "       destination:"
-  echo "          <results_dir>/<frame sequence>.hex"
-  echo "          <results_dir>/<frame sequence>.metadata"
-  echo
-  _exit
-}
-
-_exit () {
-  echo
-  echo -e $1
-  echo
-
-  # Cleanup
-  rm -rf $tmpdir
-
-  rc=1
-  [ -n "$2" ] && rc=$2
-  exit $rc
-}
-
-
-#############
-# EXECUTION #
-#############
-
-echo
-echo "============================================"
-echo "Diameter buffer extractor from PCAP raw file"
-echo "============================================"
-echo
-
-# Usage:
-[ "$1" = "" ] && usage
-
-# Pcap file:
-PCAP_FILE=$1
-[ ! -f $PCAP_FILE ] && _exit "Cannot found provided pcap file '$1' !!"
-
-# Optional result dir:
-RESULTS_DIR=`dirname $PCAP_FILE`
-[ "$2" != "" ] && RESULTS_DIR=$2
-[ ! -d $RESULTS_DIR ] && _exit "The results directory '$RESULTS_DIR' must exists !!"
-
-# Get the frames with diameter content (take care about '-2' two-pass option and don't add it, because we need to get reassembled parts in their corresponding frames):
-# Fields needed (we won't need diameter.hopbyhopid & diameter.endtoendid to verify diameter message as hint patterns; length management will be enough):
-FIELDS_DIAMETER="-e diameter.cmd.code -e diameter.flags.request -e diameter.applicationId -e diameter.hopbyhopid -e diameter.endtoendid -e diameter.length"
-FIELDS="-e frame.number -e frame.time_epoch -e ip.src_host -e ip.dst_host $FIELDS_DIAMETER -e tcp.len -e frame.protocols -e tcp.segment"
-tshark -E separator="|" -r $PCAP_FILE -N mntC -Tfields $FIELDS 2>/dev/null | grep -i diameter > $tmpdir/diameter_frames
-# Example output:
-#                                                                               /length\
-# frame     timestamp        src     dst   code R  App-ID   HopByHop   EndToEnd DIAM TCP          protocol                         segments 
-#   1|1427215933.697904000|gt_traf|vcbavipt|272|1|16777238|0x0004e6e6|0x000bd986|432|432|eth:ip:tcp:diameter:diameter:diameter3gpp|
-#   3|1427215934.449523000|vcbavipt|gt_traf|272|0|16777238|0x0004e6e6|0x000bd986|292|292|eth:ip:tcp:diameter:diameter:diameter3gpp|
-#   5|1427215934.456160000|gt_traf|vcbavipt|||||||1400|eth:ip:tcp:diameter|
-#   6|1427215934.456204000|gt_traf|vcbavipt|265|1|16777236|0x000c73c3|0x0004cee4|1972|572|eth:ip:tcp:diameter:diameter:diameter3gpp|5,6
-#   8|1427215935.123559000|vcbavipt|gt_traf|265|0|16777236|0x000c73c3|0x0004cee4|248|248|eth:ip:tcp:diameter:diameter:diameter3gpp|
-all_frames=( $(cat $tmpdir/diameter_frames | cut -d\| -f1) )
-needs_join=( $(cat $tmpdir/diameter_frames | cut -d\| -f13) )
-main_frames=( $(cat $tmpdir/diameter_frames | awk -F\| '{ if ($11 != "") print $1 }') )
-
-# Reassemble procedure (using frame 1 as example):
-# (for non segmented frames, it is enough with tcp or diameter length within the frame content itself)
-# 1) Get the TCP length: 432 bytes. 432*2 = 864 characters per byte in hexadecimal string format
-# 2) Get the frame length: `wc -c $tmpdir/block.$frame` => 997
-# 3) Get 864 from the tail: `cat $tmpdir/block.$frame | cut -c133
-
-# Dump the hex blocks for all the diameter frames:
-cat $PCAP_FILE | rawshark -s -r - -d proto:diameter -F data 2>/dev/null > $tmpdir/all_hex_data
-for frame in ${all_frames[@]}; do
-  grep "^$frame " $tmpdir/all_hex_data | cut -d\" -f2 | sed 's/://g' > $tmpdir/block.$frame
-  frame_info=$(grep "^${frame}|" $tmpdir/diameter_frames)
-
-  # Get the diameter part:
-  tcp_len=$(echo $frame_info | cut -d\| -f11)
-  frm_len=$(wc -c $tmpdir/block.$frame | awk '{ print $1 }')
-  cut_len=$((frm_len-2*tcp_len))
-  cat $tmpdir/block.$frame | cut -c${cut_len}- > $RESULTS_DIR/$frame.hex
-  echo -n "Created $RESULTS_DIR/$frame.hex"
-
-  # Metadata:
-  ts=$(echo $frame_info | cut -d\| -f2)
-  date=$(date -d @$ts)
-  src=$(echo $frame_info | cut -d\| -f3)
-  dst=$(echo $frame_info | cut -d\| -f4)
-  code=$(echo $frame_info | cut -d\| -f5)
-  isreq=$(echo $frame_info | cut -d\| -f6)
-  appid=$(echo $frame_info | cut -d\| -f7)
-  hbh=$(echo $frame_info | cut -d\| -f8)
-  e2e=$(echo $frame_info | cut -d\| -f9)
-  # To decimal:
-  hbh=$(printf "%d\n" $hbh)
-  e2e=$(printf "%d\n" $e2e)
-  echo "date=$date" > $RESULTS_DIR/$frame.metadata
-  echo "timestamp=$ts" >> $RESULTS_DIR/$frame.metadata
-  echo "src=$src" >> $RESULTS_DIR/$frame.metadata
-  echo "dst=$dst" >> $RESULTS_DIR/$frame.metadata
-  echo "code=$code" >> $RESULTS_DIR/$frame.metadata
-  echo "isrequest=$isreq" >> $RESULTS_DIR/$frame.metadata
-  echo "applicationid=$appid" >> $RESULTS_DIR/$frame.metadata
-  #echo "sequence=${hbh}.${e2e}" >> $RESULTS_DIR/$frame.metadata
-#  echo "hopbyhop=$hbh" >> $RESULTS_DIR/$frame.metadata
-#  echo "endtoend=$e2e" >> $RESULTS_DIR/$frame.metadata
-
-  echo " and $RESULTS_DIR/$frame.metadata"
-done
-
-# Join frames which need to be reassembled:
-for group in ${needs_join[@]}; do
-  echo "Grouping frames $group ..."
-  group_array=( $(echo $group | sed 's/,/ /g') )
-  for frame in ${group_array[@]}; do
-    cat $RESULTS_DIR/$frame.hex >> $tmpdir/diam.$group
-  done
-  cat $tmpdir/diam.$group | tr -d '\n' > $RESULTS_DIR/$frame.hex
-done
-
-# Delete superfluous metadata:
-echo "Deleting superfluous buffers & metadata ..."
-segments=( $(cat $tmpdir/diameter_frames | awk -F\| '{ if ($10 == "") print $1 }') )
-for s in ${segments[@]}; do rm $RESULTS_DIR/$s.*; done
-
-
-_exit "Done!" 0
-
diff --git a/example/diameter/launcher/resources/scripts/operation_curl.sh b/example/diameter/launcher/resources/scripts/operation_curl.sh
new file mode 100755 (executable)
index 0000000..5cff3c7
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+#############
+# FUNCTIONS #
+#############
+_exit () {
+  echo -e "\n$1\n"
+  exit 1
+}
+
+#############
+# EXECUTION #
+#############
+cd `dirname $0`
+echo
+# Get the HTTP Server:
+[ ! -f .httpServer ] && _exit "Can't found '`pwd`/.httpServer' to use with curl tool."
+SERVER=`cat .httpServer`
+
+# Send operation:
+[ "$1" = "" ] && _exit "Usage: $0 <operation string>; i.e.: $0 help"
+#> curl_log.txt
+#TRACE="--trace-ascii curl_log.txt"
+curl -m 1 --data "$1" $SERVER
+
diff --git a/example/diameter/launcher/resources/scripts/operation_signal.sh b/example/diameter/launcher/resources/scripts/operation_signal.sh
new file mode 100755 (executable)
index 0000000..c462a7e
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+#############
+# FUNCTIONS #
+#############
+_exit () {
+  echo -e "\n$1\n"
+  exit 1
+}
+
+#############
+# EXECUTION #
+#############
+cd `dirname $0`
+echo
+# Get the PID:
+[ ! -f .pid ] && _exit "Can't found '`pwd`/.pid'.\nTry to pgrep your process name and dump pid to that file."
+PID=`cat .pid`
+
+# Send operation:
+[ "$1" = "" ] && _exit "Usage: $0 <operation string>; i.e.: $0 help"
+echo $1 > sigusr2.tasks.input
+kill -s SIGUSR2 $PID
+
+sleep 1
+echo
+echo
+echo "You could see results on '`pwd`/sigusr2.tasks.output' file."
+echo
+echo
+
diff --git a/example/diameter/launcher/resources/scripts/operation_tps.sh b/example/diameter/launcher/resources/scripts/operation_tps.sh
new file mode 100755 (executable)
index 0000000..29f41eb
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+   echo "     sendXS <requests per second> [amount: default -1 (no limit)]:"
+   echo "        send messages from burst list with the TPS provided. User could hot change"
+   echo "        speed by mean 'echo <TPS> > .tps' at another shell. You can stop the load"
+   echo "        removing that hidden file or using CTRL+C from the shell where you launched"
+   echo "        the burst command. Real tps is dumped on '.real_tps' file during testing."
+   echo "        You could limit the amount of messages sent by mean the second parameter."
+   echo "        No limit is established by default (-1 or negative value)."
+> curl_log.txt
+TRACE="--trace-ascii curl_log.txt"
+SERVER=`cat .httpServer`
+
+use () {
+
+   echo "Use: $0 <xml_file> [2c]"
+   echo
+   echo "Sends 'xml_file' to the diameter server or to the client when '2c' parameter is provided."
+   echo
+   exit
+}
+
+   sendXS) [[ "$2" = "" ]] && uso
+         limit=$3
+         [[ "$limit" = "" ]] && limit=-1
+         entero $2
+         entero $limit
+         TPS=0
+         count=0
+         amount=1
+         echo $2 > .tps
+         while test -f .tps
+         do
+            [[ "$count" = "$limit" ]] && break
+            BEFORE_ns=`date +%s%N`
+            READ_TPS=`cat .tps`
+            # Hot change could make .tps still unavailable:
+            [[ "$READ_TPS" = "" ]] && READ_TPS=$TPS
+            # Volvemos a calcular medias (REAL_TPS) cada 10 segundos o cuando cambia el TPS en caliente:
+            [[ "$READ_TPS" != "$TPS" ]] && { BEGIN_ns=$BEFORE_ns ; count=0 ; }
+            [[ $count = $((10*TPS)) ]] && { BEGIN_ns=$BEFORE_ns ; count=0 ; }
+            TPS=$READ_TPS
+            [[ "$TPS" = "0" ]] && salir "Test stopped due to 0-tps value read"
+            # Background:
+            _curl "burst|send|$amount" &
+            count=$((count+amount))
+            AFTER_ns=`date +%s%N`
+            # Real tps:
+            REAL_TPS=$(calc "1000000000 * $count / ($AFTER_ns - $BEGIN_ns)")
+            echo $REAL_TPS > .real_tps
+            
+            COEF=1
+            [[ $(calc "$TPS > $REAL_TPS") = "1" ]] && COEF=$(calc "$REAL_TPS / $TPS")
+            K=$(calc "$COEF ^ 10")
+            amount=$(calc "scale=0;1/$K")
+            usleep $(calc "$K * 1000000/$TPS")
+         done
+   ;;
+echo
+[[ "$1" = "" ]] && use
+[[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; }
+echo
+operation="sendxml|$1"
+[[ "$2" = "2c" ]] && operation="sendxml2c|$1"
+
+curl -m 1 --data "$operation" $TRACE ${SERVER}
+
diff --git a/example/diameter/launcher/resources/scripts/pcap2diameterHex.sh b/example/diameter/launcher/resources/scripts/pcap2diameterHex.sh
new file mode 100755 (executable)
index 0000000..355b70f
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/bash
+
+# ANNA - Anna is Not Nothingness Anymore
+#
+# (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
+#
+# http://redmine.teslayout.com/projects/anna-suite
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     *  Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: eduardo.ramos.testillano@gmail.com
+#          cisco.tierra@gmail.com
+
+
+#############
+# VARIABLES #
+#############
+tmpdir=$(mktemp -d)
+
+#############
+# FUNCTIONS #
+#############
+
+usage () {
+  echo "Usage: $0 <pcap_file> [results_dir]"
+  echo
+  echo "       pcap_file:   pcap formatted file to be processed."
+  echo "       results_dir: directory where results are stored."
+  echo "                    By default, pcap file dirname is used."
+  echo
+  echo "       The utility, dumps the extracted hexadecimal content"
+  echo "       and useful information as timestamps, source and"
+  echo "       destination:"
+  echo "          <results_dir>/<frame sequence>.hex"
+  echo "          <results_dir>/<frame sequence>.metadata"
+  echo
+  _exit
+}
+
+_exit () {
+  echo
+  echo -e $1
+  echo
+
+  # Cleanup
+  rm -rf $tmpdir
+
+  rc=1
+  [ -n "$2" ] && rc=$2
+  exit $rc
+}
+
+
+#############
+# EXECUTION #
+#############
+
+echo
+echo "============================================"
+echo "Diameter buffer extractor from PCAP raw file"
+echo "============================================"
+echo
+
+# Usage:
+[ "$1" = "" ] && usage
+
+# Pcap file:
+PCAP_FILE=$1
+[ ! -f $PCAP_FILE ] && _exit "Cannot found provided pcap file '$1' !!"
+
+# Optional result dir:
+RESULTS_DIR=`dirname $PCAP_FILE`
+[ "$2" != "" ] && RESULTS_DIR=$2
+[ ! -d $RESULTS_DIR ] && _exit "The results directory '$RESULTS_DIR' must exists !!"
+
+# Get the frames with diameter content (take care about '-2' two-pass option and don't add it, because we need to get reassembled parts in their corresponding frames):
+# Fields needed (we won't need diameter.hopbyhopid & diameter.endtoendid to verify diameter message as hint patterns; length management will be enough):
+FIELDS_DIAMETER="-e diameter.cmd.code -e diameter.flags.request -e diameter.applicationId -e diameter.hopbyhopid -e diameter.endtoendid -e diameter.length"
+FIELDS="-e frame.number -e frame.time_epoch -e ip.src_host -e ip.dst_host $FIELDS_DIAMETER -e tcp.len -e frame.protocols -e tcp.segment"
+tshark -E separator="|" -r $PCAP_FILE -N mntC -Tfields $FIELDS 2>/dev/null | grep -i diameter > $tmpdir/diameter_frames
+# Example output:
+#                                                                               /length\
+# frame     timestamp        src     dst   code R  App-ID   HopByHop   EndToEnd DIAM TCP          protocol                         segments 
+#   1|1427215933.697904000|gt_traf|vcbavipt|272|1|16777238|0x0004e6e6|0x000bd986|432|432|eth:ip:tcp:diameter:diameter:diameter3gpp|
+#   3|1427215934.449523000|vcbavipt|gt_traf|272|0|16777238|0x0004e6e6|0x000bd986|292|292|eth:ip:tcp:diameter:diameter:diameter3gpp|
+#   5|1427215934.456160000|gt_traf|vcbavipt|||||||1400|eth:ip:tcp:diameter|
+#   6|1427215934.456204000|gt_traf|vcbavipt|265|1|16777236|0x000c73c3|0x0004cee4|1972|572|eth:ip:tcp:diameter:diameter:diameter3gpp|5,6
+#   8|1427215935.123559000|vcbavipt|gt_traf|265|0|16777236|0x000c73c3|0x0004cee4|248|248|eth:ip:tcp:diameter:diameter:diameter3gpp|
+all_frames=( $(cat $tmpdir/diameter_frames | cut -d\| -f1) )
+needs_join=( $(cat $tmpdir/diameter_frames | cut -d\| -f13) )
+main_frames=( $(cat $tmpdir/diameter_frames | awk -F\| '{ if ($11 != "") print $1 }') )
+
+# Reassemble procedure (using frame 1 as example):
+# (for non segmented frames, it is enough with tcp or diameter length within the frame content itself)
+# 1) Get the TCP length: 432 bytes. 432*2 = 864 characters per byte in hexadecimal string format
+# 2) Get the frame length: `wc -c $tmpdir/block.$frame` => 997
+# 3) Get 864 from the tail: `cat $tmpdir/block.$frame | cut -c133
+
+# Dump the hex blocks for all the diameter frames:
+cat $PCAP_FILE | rawshark -s -r - -d proto:diameter -F data 2>/dev/null > $tmpdir/all_hex_data
+for frame in ${all_frames[@]}; do
+  grep "^$frame " $tmpdir/all_hex_data | cut -d\" -f2 | sed 's/://g' > $tmpdir/block.$frame
+  frame_info=$(grep "^${frame}|" $tmpdir/diameter_frames)
+
+  # Get the diameter part:
+  tcp_len=$(echo $frame_info | cut -d\| -f11)
+  frm_len=$(wc -c $tmpdir/block.$frame | awk '{ print $1 }')
+  cut_len=$((frm_len-2*tcp_len))
+  cat $tmpdir/block.$frame | cut -c${cut_len}- > $RESULTS_DIR/$frame.hex
+  echo -n "Created $RESULTS_DIR/$frame.hex"
+
+  # Metadata:
+  ts=$(echo $frame_info | cut -d\| -f2)
+  date=$(date -d @$ts)
+  src=$(echo $frame_info | cut -d\| -f3)
+  dst=$(echo $frame_info | cut -d\| -f4)
+  code=$(echo $frame_info | cut -d\| -f5)
+  isreq=$(echo $frame_info | cut -d\| -f6)
+  appid=$(echo $frame_info | cut -d\| -f7)
+  hbh=$(echo $frame_info | cut -d\| -f8)
+  e2e=$(echo $frame_info | cut -d\| -f9)
+  # To decimal:
+  hbh=$(printf "%d\n" $hbh)
+  e2e=$(printf "%d\n" $e2e)
+  echo "date=$date" > $RESULTS_DIR/$frame.metadata
+  echo "timestamp=$ts" >> $RESULTS_DIR/$frame.metadata
+  echo "src=$src" >> $RESULTS_DIR/$frame.metadata
+  echo "dst=$dst" >> $RESULTS_DIR/$frame.metadata
+  echo "code=$code" >> $RESULTS_DIR/$frame.metadata
+  echo "isrequest=$isreq" >> $RESULTS_DIR/$frame.metadata
+  echo "applicationid=$appid" >> $RESULTS_DIR/$frame.metadata
+  #echo "sequence=${hbh}.${e2e}" >> $RESULTS_DIR/$frame.metadata
+#  echo "hopbyhop=$hbh" >> $RESULTS_DIR/$frame.metadata
+#  echo "endtoend=$e2e" >> $RESULTS_DIR/$frame.metadata
+
+  echo " and $RESULTS_DIR/$frame.metadata"
+done
+
+# Join frames which need to be reassembled:
+for group in ${needs_join[@]}; do
+  echo "Grouping frames $group ..."
+  group_array=( $(echo $group | sed 's/,/ /g') )
+  for frame in ${group_array[@]}; do
+    cat $RESULTS_DIR/$frame.hex >> $tmpdir/diam.$group
+  done
+  cat $tmpdir/diam.$group | tr -d '\n' > $RESULTS_DIR/$frame.hex
+done
+
+# Delete superfluous metadata:
+echo "Deleting superfluous buffers & metadata ..."
+segments=( $(cat $tmpdir/diameter_frames | awk -F\| '{ if ($10 == "") print $1 }') )
+for s in ${segments[@]}; do rm $RESULTS_DIR/$s.*; done
+
+
+_exit "Done!" 0
+
diff --git a/example/diameter/launcher/resources/xml_examples/aaa.xml b/example/diameter/launcher/resources/xml_examples/aaa.xml
new file mode 100644 (file)
index 0000000..4892138
--- /dev/null
@@ -0,0 +1,11 @@
+<message version="1" name="AA-Answer" application-id="16777236" hop-by-hop-id="202475" end-by-end-id="509476">
+   <avp name="Auth-Application-Id" data="16777236"/>
+   <avp name="Session-Id" data="test1;afNodeHostname.afNodeHostRealm.com;1;8033450"/>
+   <avp name="Origin-Host" data="sapcOwnHostId.operatorRealm.com"/>
+   <avp name="Origin-State-Id" data="1428633668"/>
+   <avp name="Origin-Realm" data="operatorRealm.com"/>
+   <avp name="Experimental-Result">
+      <avp name="Vendor-Id" data="10415"/>
+      <avp name="Experimental-Result-Code" data="5063"/>
+   </avp>
+</message>
diff --git a/example/diameter/launcher/resources/xml_examples/aar.xml b/example/diameter/launcher/resources/xml_examples/aar.xml
new file mode 100644 (file)
index 0000000..1201655
--- /dev/null
@@ -0,0 +1,24 @@
+<message version="1" name="AA-Request" p-bit="yes" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
+   <avp name="Session-Id" data="ocs3;1332774430;1;1332774430"/>
+   <avp name="Auth-Application-Id" data="16777236"/>
+   <avp name="Origin-Host" data="OCS3"/>
+   <avp name="Origin-Realm" data="OCS3"/>
+   <avp name="Destination-Realm" data="OCS3"/>
+   <avp name="Destination-Host" data="OCS3"/>
+   <avp name="AF-Application-Identifier" hex-data="313232"/>
+   <avp name="Media-Component-Description">
+      <avp name="Media-Component-Number" data="0"/>
+      <avp name="AF-Application-Identifier" hex-data="313232"/>
+      <avp name="Max-Requested-Bandwidth-UL" data="127"/>
+      <avp name="Max-Requested-Bandwidth-DL" data="133"/>
+      <avp name="Flow-Status" data="2" alias="ENABLED"/>
+      <avp name="Reservation-Priority" data="0" alias="DEFAULT"/>
+   </avp>
+   <avp name="Service-Info-Status" data="0" alias="FINAL_SERVICE_INFORMATION"/>
+   <avp name="Subscription-Id">
+      <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
+      <avp name="Subscription-Id-Data" data="626037099"/>
+   </avp>
+   <avp name="Framed-IP-Address" hex-data="3139322e3136382e302e31"/>
+   <avp name="Called-Station-Id" data="WAP.MOVISTAR"/>
+</message>
diff --git a/example/diameter/launcher/resources/xml_examples/aar2.xml b/example/diameter/launcher/resources/xml_examples/aar2.xml
new file mode 100644 (file)
index 0000000..c163fb4
--- /dev/null
@@ -0,0 +1,28 @@
+<message version="1" name="AA-Request" p-bit="yes" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
+   <avp name="Session-Id" data="ocs3;1332774430;1;1332774430"/>
+   <avp name="Auth-Application-Id" data="16777236"/>
+   <avp name="Origin-Host" data="OCS3"/>
+   <avp name="Origin-Realm" data="OCS3"/>
+   <avp name="Destination-Realm" data="OCS3"/>
+   <avp name="Destination-Host" data="OCS3"/>
+   <avp name="AF-Application-Identifier" hex-data="313232"/>
+   <avp name="Media-Component-Description">
+      <avp name="Media-Component-Number" data="0"/>
+      <avp name="Media-Sub-Component">
+         <avp name="Flow-Number" data="55"/>
+         <avp name="Flow-Status" data="0" alias="ENABLED-UPLINK"/>
+      </avp>
+      <avp name="AF-Application-Identifier" hex-data="313232"/>
+      <avp name="Max-Requested-Bandwidth-UL" data="127"/>
+      <avp name="Max-Requested-Bandwidth-DL" data="133"/>
+      <avp name="Flow-Status" data="2" alias="ENABLED"/>
+      <avp name="Reservation-Priority" data="0" alias="DEFAULT"/>
+   </avp>
+   <avp name="Service-Info-Status" data="0" alias="FINAL_SERVICE_INFORMATION"/>
+   <avp name="Subscription-Id">
+      <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
+      <avp name="Subscription-Id-Data" data="626037099"/>
+   </avp>
+   <avp name="Framed-IP-Address" hex-data="3139322e3136382e302e31"/>
+   <avp name="Called-Station-Id" data="WAP.MOVISTAR"/>
+</message>
diff --git a/example/diameter/launcher/resources/xml_examples/ccr.xml b/example/diameter/launcher/resources/xml_examples/ccr.xml
new file mode 100644 (file)
index 0000000..46483a2
--- /dev/null
@@ -0,0 +1,44 @@
+<message version="1" name="Credit-Control-Request" p-bit="yes" application-id="4" hop-by-hop-id="1" end-by-end-id="1">
+   <avp name="Session-Id" data="module-2.PTS2-BOG.sandvine.com;1287115741;0;0"/>
+   <avp name="Origin-Host" data="module-2.PTS2-BOG.sandvine.com"/>
+   <avp name="Origin-Realm" data="sandvine.com"/>
+   <avp name="Destination-Realm" data="telefonica.com.co"/>
+   <avp name="Auth-Application-Id" data="4"/>
+   <avp name="Service-Context-Id" data="770.32251@3gpp.org"/>
+   <avp name="CC-Request-Type" data="1" alias="INITIAL_REQUEST"/>
+   <avp name="CC-Request-Number" data="0"/>
+   <avp name="User-Name" data="50583211675"/>
+   <avp name="Origin-State-Id" data="1339077627"/>
+   <avp name="Event-Timestamp" data="3548171033"/>
+   <avp name="Subscription-Id">
+      <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
+      <avp name="Subscription-Id-Data" data="50583211675"/>
+   </avp>
+   <avp name="Multiple-Services-Indicator" data="1" alias="MULTIPLE_SERVICES_SUPPORTED"/>
+   <avp name="User-Equipment-Info">
+      <avp name="User-Equipment-Info-Type" data="0" alias="IMEISV"/>
+      <avp name="User-Equipment-Info-Value" hex-data="33353430343630343130363438333030"/>
+   </avp>
+   <avp name="Service-Information">
+      <avp name="PS-Information">
+         <avp name="3GPP-Charging-Id" data="29"/>
+         <avp name="3GPP-PDP-Type" data="0" alias="IPV4"/>
+         <avp name="PDP-Address" data="10.193.49.133"/>
+         <avp name="3GPP-GPRS-Neg-QoS-Profile" data="05-1b921f7196fefe74fbfefe00"/>
+         <avp name="SGSN-Address" data="190.98.183.240"/>
+         <avp name="GGSN-Address" data="190.98.183.243"/>
+         <avp name="CG-Address" data="10.193.249.1"/>
+         <avp name="3GPP-IMSI-MCC-MNC" data="71204"/>
+         <avp name="3GPP-GGSN-MCC-MNC" data="71204"/>
+         <avp name="3GPP-NSAPI" data="5"/>
+         <avp name="Called-Station-Id" data="internet.movistar.ni"/>
+         <avp name="3GPP-Selection-Mode" data="0"/>
+         <avp name="3GPP-Charging-Characteristics" data="0800"/>
+         <avp name="3GPP-SGSN-MCC-MNC" data="33403"/>
+         <avp name="3GPP-MS-TimeZone" hex-data="4a00"/>
+         <avp name="3GPP-User-Location-Info" hex-data="0117f240a4780218"/>
+         <avp name="3GPP-Rat-Type" hex-data="01"/>
+         <avp name="PDP-Context-Type" data="0"/>
+      </avp>
+   </avp>
+</message>
index bb7c6f5..1884083 100644 (file)
@@ -178,6 +178,7 @@ private:
   anna::xml::DTDMemory a_dtd;
   ValidationDepth::_v a_validationDepth;
   ValidationMode::_v a_validationMode;
+  bool a_singleFailedAVP;
   bool a_ignoreFlags;
   FixMode::_v a_fixMode;
   bool a_selectStackWithApplicationId; // default behaviour: let the user switch the stack (false for this boolean)
@@ -322,7 +323,20 @@ public:
    */
   FixMode::_v getFixMode() const throw() { return a_fixMode; }
 
+  /**
+   * Sets single FailedAVP. True by default. If false, and more than one wrong avp are found during message
+   * decoding and or validation, a new Failed-AVP will be added to the dynamic answer provided. The standard
+   * talks about only one but it is open to do this.
+   *
+   * \param single Single Failed-AVP boolean.
+   */
+  void setSingleFailedAVP(bool single = true)  throw() { a_singleFailedAVP = single; }
 
+  /**
+   * Returns single Failed-AVP boolean.
+   * \return Failed-AVP could be one (true) or more (false) in answer message.
+   */
+  bool getSingleFailedAVP() const throw() { return a_singleFailedAVP; }
 
   /**
      DTD document for xml message parsing
index 5d24eb9..c25bec0 100644 (file)
@@ -116,6 +116,7 @@ EngineImpl::EngineImpl(const char* className) :
   a_dictionary(NULL),
   a_validationDepth(ValidationDepth::FirstError),
   a_validationMode(ValidationMode::AfterDecoding),
+  a_singleFailedAVP(true),
   a_ignoreFlags(false),
   a_selectStackWithApplicationId(false),
   a_fixMode(FixMode::BeforeEncoding) {
@@ -191,6 +192,8 @@ std::string EngineImpl::asString(void) const throw() {
   result += asText(a_validationDepth);
   result += "\nValidationMode: ";
   result += asText(a_validationMode);
+  result += "\nSingle Failed-AVP: ";
+  result += a_singleFailedAVP ? "yes" : "no";
   result += "\nIgnore flags: ";
   result += a_ignoreFlags ? "yes" : "no";
   result += "\nFixMode: ";
@@ -209,6 +212,7 @@ throw() {
   anna::xml::Node* result = parent->createChild("diameter.codec.EngineImpl");
   result->createAttribute("ValidationDepth", asText(a_validationDepth));
   result->createAttribute("ValidationMode", asText(a_validationMode));
+  result->createAttribute("SingleFailedAVP", a_singleFailedAVP ? "yes" : "no");
   result->createAttribute("IgnoreFlags", a_ignoreFlags ? "yes" : "no");
   result->createAttribute("FixMode", asText(a_fixMode));
   anna::xml::Node* dictionary = result->createChild("EngineImpl.ActivatedDictionary");
index b9c4fbd..35db129 100644 (file)
@@ -471,11 +471,13 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron
   // most of the command codes as *[Failed-AVP], i think this is not a deliberate ambiguity.
   // Probably the RFC wants to give freedom to the application layer, but it is recommended to
   // have only one child (wrong avp) inside a unique message Failed-AVP to ease the Result-Code
-  // correspondence. Anyway, this behaviour could be easily  opened commenting condition block (*).
+  // correspondence. Anyway, this behaviour could be easily  opened by mean 'setSingleFailedAVP(false)'
   Avp *theFailedAvp = getAvp(helpers::base::AVPID__Failed_AVP, 1, anna::Exception::Mode::Ignore);
   if (theFailedAvp) {
-       LOGDEBUG(anna::Logger::debug("Failed-AVP has already been added. RFC 6733 Section 7.5 recommends to store only the first error found", ANNA_FILE_LOCATION));
-    return;
+    if (getEngine()->getSingleFailedAVP()) {
+      LOGDEBUG(anna::Logger::debug("Failed-AVP has already been added. RFC 6733 Section 7.5 recommends to store only the first error found", ANNA_FILE_LOCATION));
+      return;
+    }
   }
 
   // Section 7.5 RFC 6733: A Diameter message SHOULD contain one Failed-AVP AVP