New ApplicationMessageOamModule in diameter::comm, to dynamically manage application...
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 24 May 2015 17:33:10 +0000 (19:33 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 24 May 2015 17:33:10 +0000 (19:33 +0200)
15 files changed:
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/MyDiameterEntity.cpp
example/diameter/launcher/MyLocalServer.cpp
include/anna/core/define.autoenum.hpp
include/anna/core/oam/Module.hpp
include/anna/diameter.comm/ApplicationMessageOamModule.hpp [new file with mode: 0644]
include/anna/diameter.comm/ClientSession.hpp
include/anna/diameter.comm/Message.hpp
include/anna/diameter.comm/OamModule.hpp
include/anna/diameter.comm/ServerSession.hpp
include/anna/diameter/codec/OamModule.hpp
source/diameter.comm/ApplicationMessageOamModule.cpp [new file with mode: 0644]
source/diameter.comm/ClientSession.cpp
source/diameter.comm/Message.cpp
source/diameter.comm/ServerSession.cpp

index e4ea4ca..edb1de0 100644 (file)
@@ -14,6 +14,7 @@
 #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>
 
 // Process
 #include "Launcher.hpp"
@@ -359,13 +360,85 @@ throw(anna::RuntimeException) {
   a_start_time.setNow();
   // Statistics:
   anna::statistics::Engine::instantiate().enable();
+
+  // Checking command line parameters
+  if(cl.exists("sessionBasedModelsClientSocketSelection")) {
+    std::string type = cl.getValue("sessionBasedModelsClientSocketSelection");
+
+    if((type != "SessionIdHighPart") && (type != "SessionIdOptionalPart") && (type != "RoundRobin")) {
+      throw anna::RuntimeException("Commandline option '-sessionBasedModelsClientSocketSelection' only accepts 'SessionIdHighPart'/'SessionIdOptionalPart'/'RoundRobin' as parameter values", ANNA_FILE_LOCATION);
+    }
+  }
+
+  // Tracing:
+  if(cl.exists("trace"))
+    anna::Logger::setLevel(anna::Logger::asLevel(cl.getValue("trace")));
+
+  LOGINFORMATION(
+    // Help on startup traces:
+    anna::Logger::information(help(), ANNA_FILE_LOCATION);
+    // Test messages dtd:
+    std::string msg = "\n                     ------------- TESTMESSAGES DTD -------------\n";
+    msg += anna::diameter::codec::MessageDTD;
+    anna::Logger::information(msg, ANNA_FILE_LOCATION);
+  );
+
+  // HTTP Server:
+  if(cl.exists("httpServer")) {
+    anna::comm::Network& network = anna::comm::Network::instantiate();
+    std::string address;
+    int port;
+    anna::functions::getAddressAndPortFromSocketLiteral(cl.getValue("httpServer"), address, port);
+    //const anna::comm::Device* device = network.find(Device::asAddress(address)); // here provide IP
+    const anna::comm::Device* device = *((network.resolve(address)->device_begin())); // trick to solve
+    a_httpServerSocket = new anna::comm::ServerSocket(anna::comm::INetAddress(device, port), cl.exists("httpServerShared") /* shared bind */, &anna::http::Transport::getFactory());
+  }
+
+  // Stack:
+  anna::diameter::codec::Engine *codecEngine = new anna::diameter::codec::Engine();
+  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);
+    }
+  }
+
+  codecEngine->setDictionary(d);
+  LOGDEBUG(anna::Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION));
+
+  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;
+  }
+
   ///////////////////////////////
   // Diameter library COUNTERS //
   ///////////////////////////////
   anna::diameter::comm::OamModule & oamDiameterComm = anna::diameter::comm::OamModule::instantiate();
   oamDiameterComm.initializeCounterScope(1);  // 1000 - 1999
+  oamDiameterComm.enableCounters();
+  oamDiameterComm.enableAlarms();
   anna::diameter::codec::OamModule & oamDiameterCodec = anna::diameter::codec::OamModule::instantiate();
   oamDiameterCodec.initializeCounterScope(2);  // 2000 - 2999
+  oamDiameterCodec.enableCounters();
+  oamDiameterCodec.enableAlarms();
   /////////////////
   // COMM MODULE //
   /////////////////
@@ -463,6 +536,18 @@ throw(anna::RuntimeException) {
   oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FailedRuleForCardinalityMoreThanNeeded,                 "", 17 /*2017*/);
   oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FailedGenericAvpRuleForCardinalityFoundDisregardedItem, "", 18 /*2018*/);
   oamDiameterCodec.registerCounter(anna::diameter::codec::OamModule::Counter::LevelValidation__FoundDisregardedItemsAndGenericAVPWasNotSpecified,      "", 19 /*2019*/);
+  ///////////////////////////////////////////
+  // APPLICATION MESSAGE OAM MODULE SCOPES //
+  ///////////////////////////////////////////
+  // We will register a scope per stack id registered. The counters will be dynamically registered at count method.
+  anna::diameter::comm::ApplicationMessageOamModule & appMsgOamModule = anna::diameter::comm::ApplicationMessageOamModule::instantiate();
+  int scope_id = 3;
+  for (anna::diameter::stack::Engine::const_stack_iterator it = stackEngine.stack_begin(); it != stackEngine.stack_end(); it++) {
+    appMsgOamModule.createStackCounterScope(scope_id, it->first);
+    scope_id++;
+  }
+  appMsgOamModule.enableCounters(); // this special module is disabled by default (the only)
+
 
   /////////////////////////////////
   // Counter recorder associated //
@@ -470,77 +555,10 @@ throw(anna::RuntimeException) {
   if(a_counterRecorderClock) {
     oamDiameterComm.setCounterRecorder(a_counterRecorder);
     oamDiameterCodec.setCounterRecorder(a_counterRecorder);
+    appMsgOamModule.setCounterRecorder(a_counterRecorder);
     a_timeEngine->activate(a_counterRecorderClock); // start clock
   }
 
-  // Checking command line parameters
-  if(cl.exists("sessionBasedModelsClientSocketSelection")) {
-    std::string type = cl.getValue("sessionBasedModelsClientSocketSelection");
-
-    if((type != "SessionIdHighPart") && (type != "SessionIdOptionalPart") && (type != "RoundRobin")) {
-      throw anna::RuntimeException("Commandline option '-sessionBasedModelsClientSocketSelection' only accepts 'SessionIdHighPart'/'SessionIdOptionalPart'/'RoundRobin' as parameter values", ANNA_FILE_LOCATION);
-    }
-  }
-
-  // Tracing:
-  if(cl.exists("trace"))
-    anna::Logger::setLevel(anna::Logger::asLevel(cl.getValue("trace")));
-
-  LOGINFORMATION(
-    // Help on startup traces:
-    anna::Logger::information(help(), ANNA_FILE_LOCATION);
-    // Test messages dtd:
-    std::string msg = "\n                     ------------- TESTMESSAGES DTD -------------\n";
-    msg += anna::diameter::codec::MessageDTD;
-    anna::Logger::information(msg, ANNA_FILE_LOCATION);
-  );
-
-  // HTTP Server:
-  if(cl.exists("httpServer")) {
-    anna::comm::Network& network = anna::comm::Network::instantiate();
-    std::string address;
-    int port;
-    anna::functions::getAddressAndPortFromSocketLiteral(cl.getValue("httpServer"), address, port);
-    //const anna::comm::Device* device = network.find(Device::asAddress(address)); // here provide IP
-    const anna::comm::Device* device = *((network.resolve(address)->device_begin())); // trick to solve
-    a_httpServerSocket = new anna::comm::ServerSocket(anna::comm::INetAddress(device, port), cl.exists("httpServerShared") /* shared bind */, &anna::http::Transport::getFactory());
-  }
-
-  // Stack:
-  anna::diameter::codec::Engine *codecEngine = new anna::diameter::codec::Engine();
-  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);
-    }
-  }
-
-  codecEngine->setDictionary(d);
-  LOGDEBUG(anna::Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION));
-
-  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;
-  }
-
-
 
   // Integration (validation 'Complete' for receiving messages) and debugging (validation also before encoding: 'Always').
   // If missing 'integrationAndDebugging', default behaviour at engine is: mode 'AfterDecoding', depth 'FirstError':
@@ -911,9 +929,9 @@ std::string Launcher::gotoBurst(int order) throw() {
 }
 
 void Launcher::resetCounters() throw() {
-  // Diameter::comm module:
-  anna::diameter::comm::OamModule & oamDiameterComm = anna::diameter::comm::OamModule::instantiate();
-  oamDiameterComm.resetCounters();
+  anna::diameter::comm::OamModule::instantiate().resetCounters();
+  anna::diameter::comm::ApplicationMessageOamModule::instantiate().resetCounters();
+  anna::diameter::codec::OamModule::instantiate().resetCounters();
 }
 
 void Launcher::signalUSR2() throw(anna::RuntimeException) {
@@ -1041,9 +1059,13 @@ std::string Launcher::help() const throw() {
   result += "\n";
   result += "\ndiameterServerSessions|<integer>     Updates the maximum number of accepted connections to diameter";
   result += "\n                                      server socket.";
+  result += "\ncontext|[target file]                Application context could also be written by mean this operation,";
+  result += "\n                                      and not only through SIGUSR1. If optional path file is missing,";
+  result += "\n                                      default '/var/tmp/anna.context.<pid>' will be used.";
   result += "\ncollect                              Reset statistics and counters to start a new test stage of";
-  result += "\n                                      performance measurement. Context data is written at";
-  result += "\n                                      '/var/tmp/anna.context.<pid>' by mean 'kill -10 <pid>'.";
+  result += "\n                                      performance measurement. Context data can be written at";
+  result += "\n                                      '/var/tmp/anna.context.<pid>' by mean 'kill -10 <pid>'";
+  result += "\n                                      or sending operation 'context|[target file]'.";
   result += "\nforceCountersRecord                  Forces dump to file the current counters of the process.";
   result += "\n";
   result += "\n<visibility action>|[<address>:<port>]|[socket id]";
@@ -1272,6 +1294,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons
   if(numParams == 2) { tok_iter++; param2 = Tokenizer::data(tok_iter); }
 
   // Operations:
+  if(opType == "context") {
+    std::string contextFile = ((numParams == 1) ? param1 : anna::functions::asString("/var/tmp/anna.context.%05d", getPid()));
+    writeContext(contextFile);
+    response_content = anna::functions::asString("Context dumped on file '%s'\n", contextFile.c_str());
+    return;
+  }
+
   if(opType == "code") {
     codecMsg.loadXML(param1);
     std::string hexString = anna::functions::asHexString(codecMsg.code());
@@ -1698,6 +1727,7 @@ throw() {
   (anna::functions::component <anna::diameter::codec::Engine> (ANNA_FILE_LOCATION))->asXML(result);
   // OAM:
   anna::diameter::comm::OamModule::instantiate().asXML(result);
+  anna::diameter::comm::ApplicationMessageOamModule::instantiate().asXML(result);
   anna::diameter::codec::OamModule::instantiate().asXML(result);
   // Statistics:
   anna::statistics::Engine::instantiate().asXML(result);
index 0535160..f6fce7b 100644 (file)
@@ -145,6 +145,7 @@ throw(anna::RuntimeException) {
       msg += anna::diameter::functions::commandIdAsPairString(request_cid);
       anna::Logger::debug(msg, ANNA_FILE_LOCATION);
     );
+
     // Write reception
     if(request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) {  // don't trace CEA
       if(my_app.logEnabled()) {
index 5e3ca1f..7db0d87 100644 (file)
@@ -105,7 +105,6 @@ throw(anna::RuntimeException) {
     if(my_app.logEnabled()) my_app.writeLogFile(*answer_message, "sent2c", serverSession->asString());
   } catch(anna::RuntimeException &ex) {
     ex.trace();
-
     if(my_app.logEnabled()) my_app.writeLogFile(*answer_message, "send2cError", serverSession->asString());
   }
 
@@ -180,7 +179,7 @@ throw(anna::RuntimeException) {
       anna::diameter::comm::ClientSession *usedClientSession = my_app.getMyDiameterEngine()->findClientSession(request->getRequestClientSessionKey());
       std::string detail;
 
-      if(my_app.logEnabled()) detail = usedClientSession ? usedClientSession->asString() : "<null client session>";  // esto no deberia ocurrir
+      if(my_app.logEnabled()) detail = usedClientSession ? usedClientSession->asString() : "<null client session>";  // this should not happen
 
       try {
         anna::diameter::comm::Message *msg = my_app.createCommMessage();
@@ -200,7 +199,6 @@ throw(anna::RuntimeException) {
         if(my_app.logEnabled()) my_app.writeLogFile(*message, "fwd2e", detail);  // forwarded
       } catch(anna::RuntimeException &ex) {
         ex.trace();
-
         if(my_app.logEnabled()) my_app.writeLogFile(*message, "fwd2eError", detail);  // forwarded
       }
     }
index 748dbce..9378110 100644 (file)
  */
 #define anna_declare_enum(name) \
    static const char* literal []; \
+   static int calculateSize () throw () { \
+      int ii = 0; \
+      while (literal [ii] != NULL) ii ++; \
+      return ii; \
+   } \
    static _v asEnum (const char* str) throw () { \
       for (int ii = 0; literal [ii] != NULL; ii ++) { \
          if (strcasecmp (str, literal [ii]) == 0) \
index 10e051f..39bc31c 100644 (file)
@@ -138,8 +138,8 @@ class Module {
   Handler *a_handler;              // Handler reference
 
   std::string a_className;         // module description
-  bool a_counters_enabled;         // Enable/Disable registered counters over this module (default is 'true')
-  bool a_alarms_enabled;           // Enable/Disable registered alarms over this module (default is 'true')
+  bool a_counters_enabled;         // Enable/Disable registered counters over this module (default is 'false')
+  bool a_alarms_enabled;           // Enable/Disable registered alarms over this module (default is 'false')
 
   // dynamic modifications over alarm text
   bool a_alarms_preffix_enabled;   // Show own module alarm preffix
@@ -202,10 +202,9 @@ class Module {
   alarm_iterator alarm_end() throw() { return a_alarms.end(); }
   void getAlarmPreffixSuffixAndZoneSeparator(std::string & preffix, std::string & suffix, char & zS) const throw();
 
-
 public:
 
-  static const int MaxScope = 100; /**< Numero maximo de ambitos */
+  static const int MaxScope = 1000; /**< Numero maximo de ambitos */
 
 
   /** Constructor
@@ -213,10 +212,10 @@ public:
    */
   Module(const std::string &className) :    a_className(className),
     a_handler(&a_defaultHandler),
-    a_counters_enabled(true),
+    a_counters_enabled(false),
     a_counterRecorder(NULL),
     a_counterRecording(false),
-    a_alarms_enabled(true),
+    a_alarms_enabled(false),
     a_alarms_preffix_enabled(true),
     a_alarms_suffix_enabled(true) {;}
 
@@ -250,6 +249,16 @@ public:
   */
   void disableAlarms(void) throw();
 
+  /**
+    Getter for counters enabled
+  */
+  bool countersEnabled() const throw() { return a_counters_enabled; }
+
+  /**
+    Getter for alarms enabled
+  */
+  bool alarmsEnabled() const throw() { return a_alarms_enabled; }
+
   /**
   * Show own module alarm preffix (enabled by default at constructor).
   * Usually managed at PROCCESS implementation
diff --git a/include/anna/diameter.comm/ApplicationMessageOamModule.hpp b/include/anna/diameter.comm/ApplicationMessageOamModule.hpp
new file mode 100644 (file)
index 0000000..c9c5b0d
--- /dev/null
@@ -0,0 +1,162 @@
+// 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 anna_diameter_comm_ApplicationMessageOamModule_hpp
+#define anna_diameter_comm_ApplicationMessageOamModule_hpp
+
+
+// Project
+#include <anna/core/mt/Mutex.hpp>
+#include <anna/core/Singleton.hpp>
+#include <anna/core/define.autoenum.hpp>
+#include <anna/core/oam/Module.hpp>
+
+// Standard
+#include <string>
+#include <map>
+
+namespace anna {
+
+namespace diameter {
+
+namespace comm {
+
+
+/**
+  Special OAM module which tracks a replica for a set of counter types for each different application message managed by the
+  communication layer in a specific stack id. For example, if one process is managing CCR/A, RAR/A for Gx and AAR/A, RAR/A for Rx,
+  then two counter scopes should be registered (one for Gx, another for Rx). Each scope will store counters sets for each diameter
+  message. Having N counters within each scope (for example N=14), the total capacity is N/(number of counter types) different
+  message codes:
+
+  <pre>
+    Scope for Gx:
+
+      Credit-Control-Request_SentOK_AsClient
+      Credit-Control-Request_SentNOK_AsClient
+      Credit-Control-Answer_SentOK_AsClient
+      Credit-Control-Answer_SentNOK_AsClient
+      Credit-Control-Request_Received_AsClient
+      Credit-Control-Answer_Received_AsClient
+      Credit-Control-Answer_UnknownReceived_AsClient
+      Credit-Control-Request_SentOK_AsServer
+      Credit-Control-Request_SentNOK_AsServer
+      Credit-Control-Answer_SentOK_AsServer
+      Credit-Control-Answer_SentNOK_AsServer
+      Credit-Control-Request_Received_AsServer
+      Credit-Control-Answer_Received_AsServer
+      Credit-Control-Answer_UnknownReceived_AsServer
+      Re-Auth-Request_SentOK_AsClient
+      Re-Auth-Request_SentNOK_AsClient
+      Re-Auth-Answer_SentOK_AsClient
+      Re-Auth-Answer_SentNOK_AsClient
+      Re-Auth-Request_Received_AsClient
+      Re-Auth-Answer_Received_AsClient
+      Re-Auth-Answer_UnknownReceived_AsClient
+      Re-Auth-Request_SentOK_AsServer
+      Re-Auth-Request_SentNOK_AsServer
+      Re-Auth-Answer_SentOK_AsServer
+      Re-Auth-Answer_SentNOK_AsServer
+      Re-Auth-Request_Received_AsServer
+      Re-Auth-Answer_Received_AsServer
+      Re-Auth-Answer_UnknownReceived_AsServer
+   
+    Scope for Rx:
+
+      AA-Request_SentOK_AsClient
+      AA-Request_SentNOK_AsClient
+      AA-Answer_SentOK_AsClient
+      AA-Answer_SentNOK_AsClient
+      AA-Request_Received_AsClient
+      AA-Answer_Received_AsClient
+      AA-Answer_UnknownReceived_AsClient
+      AA-Request_SentOK_AsServer
+      AA-Request_SentNOK_AsServer
+      AA-Answer_SentOK_AsServer
+      AA-Answer_SentNOK_AsServer
+      AA-Request_Received_AsServer
+      AA-Answer_Received_AsServer
+      AA-Answer_UnknownReceived_AsServer
+      Re-Auth-Request_SentOK_AsClient
+      Re-Auth-Request_SentNOK_AsClient
+      Re-Auth-Answer_SentOK_AsClient
+      Re-Auth-Answer_SentNOK_AsClient
+      Re-Auth-Request_Received_AsClient
+      Re-Auth-Answer_Received_AsClient
+      Re-Auth-Answer_UnknownReceived_AsClient
+      Re-Auth-Request_SentOK_AsServer
+      Re-Auth-Request_SentNOK_AsServer
+      Re-Auth-Answer_SentOK_AsServer
+      Re-Auth-Answer_SentNOK_AsServer
+      Re-Auth-Request_Received_AsServer
+      Re-Auth-Answer_Received_AsServer
+      Re-Auth-Answer_UnknownReceived_AsServer
+  </pre> 
+*/
+class ApplicationMessageOamModule : public anna::oam::Module, public anna::Singleton <ApplicationMessageOamModule> {
+
+  std::map<int /* message code */, int /* base offset */> a_messageMap;
+  std::map<unsigned int /* stack id */, int /* scope id */> a_stackMap;
+
+  int a_counter_types;
+
+  anna::Mutex a_mutex; // counter scope switch
+
+public:
+
+  struct Counter {
+    enum _v
+    {
+      None = -1,
+
+      Request_SentOK_AsClient,
+      Request_SentNOK_AsClient,
+      Answer_SentOK_AsClient,
+      Answer_SentNOK_AsClient,
+      Request_Received_AsClient,
+      Answer_Received_AsClient,
+      Answer_UnknownReceived_AsClient,
+
+      Request_SentOK_AsServer,
+      Request_SentNOK_AsServer,
+      Answer_SentOK_AsServer,
+      Answer_SentNOK_AsServer,
+      Request_Received_AsServer,
+      Answer_Received_AsServer,
+      Answer_UnknownReceived_AsServer
+    };
+
+    anna_declare_enum(Counter);
+  };
+
+  /* virtual */std::string getDefaultInternalCounterDescription(const int & counterType) const throw() { return Counter::asCString((Counter::_v)counterType); }
+
+  // map stack id with a scope id
+  void createStackCounterScope(int /* scope id */, unsigned int /* stack id */) throw(anna::RuntimeException);
+
+  // translate message code into offset and invoke parent class count method. The message applicationId will be used as stack id
+  void count (int messageCode, unsigned int stackId, const int & type, const int & amount = 1) throw(anna::RuntimeException);
+
+  // Number of different counter types for each message
+  int getCounterTypes() const throw() { return a_counter_types; }
+
+private:
+
+  // private constructor
+  ApplicationMessageOamModule() : anna::oam::Module("Application Message Comm OAM Events") { a_counter_types = Counter::calculateSize(); }
+
+
+  friend class anna::Singleton <ApplicationMessageOamModule>;
+};
+
+}
+}
+}
+
+#endif
+
index b343f53..93490cb 100644 (file)
@@ -222,7 +222,7 @@ private:
   // Activity:
   /* virtual */void updateIncomingActivityTime() throw();
   /* virtual */void updateOutgoingActivityTime() throw();
-  void countSendings(const diameter::CommandId & cid, bool ok) throw();
+  void countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok) throw();
 
   // Handlers:
   /**
index fe9da01..b5cb459 100644 (file)
@@ -105,6 +105,7 @@ public:
   void setRequestEndToEnd(EndToEnd ete) throw() { a_requestEndToEnd = ete; }
   CommandId getCommandId(bool &isRequest) const throw();
   CommandId getCommandId() const throw() { bool dummy; return getCommandId(dummy); }
+  ApplicationId getApplicationId() const throw();
 
   bool fixRequestSequence(HopByHop hbh, EndToEnd ete) throw();
 
index 346c12f..6566180 100644 (file)
 #define anna_diameter_comm_OamModule_hpp
 
 
+// Project
 #include <anna/core/Singleton.hpp>
 #include <anna/core/define.autoenum.hpp>
-
-// HTE
 #include <anna/core/oam/Module.hpp>
 
-// STL
+// Standard
 #include <string>
 
 
index 23d3ba6..5581a4b 100644 (file)
@@ -159,7 +159,7 @@ private:
   // Activity:
   /* virtual */void updateIncomingActivityTime() throw();
   /* virtual */void updateOutgoingActivityTime() throw();
-  void countSendings(const diameter::CommandId & cid, bool ok) throw();
+  void countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok) throw();
 
   // Handlers:
   /**
index 15e7b9f..0ef5aa4 100644 (file)
 #define anna_diameter_codec_OamModule_hpp
 
 
+// Project
 #include <anna/core/Singleton.hpp>
 #include <anna/core/define.autoenum.hpp>
-
-// HTE
 #include <anna/core/oam/Module.hpp>
 
-// STL
+// Standard
 #include <string>
 
 
diff --git a/source/diameter.comm/ApplicationMessageOamModule.cpp b/source/diameter.comm/ApplicationMessageOamModule.cpp
new file mode 100644 (file)
index 0000000..bba049c
--- /dev/null
@@ -0,0 +1,117 @@
+// 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 <algorithm>
+
+// Project
+#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
+#include <anna/core/mt/Guard.hpp>
+#include <anna/core/functions.hpp>
+#include <anna/core/oam/CounterScope.hpp>
+#include <anna/diameter/stack/Engine.hpp>
+
+
+anna_assign_enum(anna::diameter::comm::ApplicationMessageOamModule::Counter) = { \
+    "Request_SentOK_AsClient", \
+    "Request_SentNOK_AsClient", \
+    "Answer_SentOK_AsClient", \
+    "Answer_SentNOK_AsClient", \
+    "Request_Received_AsClient", \
+    "Answer_Received_AsClient", \
+    "Answer_UnknownReceived_AsClient", \
+
+    "Request_SentOK_AsServer", \
+    "Request_SentNOK_AsServer", \
+    "Answer_SentOK_AsServer", \
+    "Answer_SentNOK_AsServer", \
+    "Request_Received_AsServer", \
+    "Answer_Received_AsServer", \
+    "Answer_UnknownReceived_AsServer", \
+    NULL /* list end indicator */
+};
+
+void anna::diameter::comm::ApplicationMessageOamModule::createStackCounterScope(int scopeId, unsigned int stackId) throw(anna::RuntimeException) {
+
+  initializeCounterScope(scopeId, anna::functions::asString("Application Message Events for stack id %lu", stackId));
+
+  // Better to be enabled by application in order to be more conscious of the native disabled nature of this special oam module
+  //if (!countersEnabled()) enableCounters();
+  //enableAlarms(); not yet implemented
+
+  a_stackMap[stackId] = scopeId;
+}
+
+void anna::diameter::comm::ApplicationMessageOamModule::count (int messageCode, unsigned int stackId, const int & type, const int & amount) throw(anna::RuntimeException) {
+
+  // Optimization:
+  // Checkings
+  if(!countersEnabled()) {
+    LOGDEBUG
+    (
+      std::string msg = "Count operation ignored over module '";
+      msg += getClassName();
+      msg += "': counters are disabled";
+      anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+    );
+    return;
+  }
+
+  anna::Guard guard(a_mutex, "ApplicationMessageOamModule::count"); // counter scope switch
+
+  std::map<unsigned int /* stack id */, int /* scope id */>::const_iterator stackMap_it = a_stackMap.find(stackId);
+
+  if (stackMap_it == a_stackMap.end()) {
+    LOGDEBUG(anna::Logger::debug(anna::functions::asString("Unregistered stack id %lu", stackId), ANNA_FILE_LOCATION));
+    return;
+  }
+
+  // Select counter scope 
+  setActiveCounterScope(stackMap_it->second);
+  std::map<int /* message code */, int /* base offset */>::const_iterator messageMap_it = a_messageMap.find(messageCode);
+  int baseOffset = messageMap_it->second;
+     
+  if (messageMap_it == a_messageMap.end()) {
+    int capacity = anna::oam::CounterScope::MaxCounter / getCounterTypes();
+    if (a_messageMap.size() > capacity) {
+      LOGDEBUG(anna::Logger::debug(anna::functions::asString("No more holes to register new application message counters in the scope (up to %d message codes)", capacity), ANNA_FILE_LOCATION));
+      return;
+    }
+    baseOffset = getCounterTypes() * a_messageMap.size(); // N counter types for each message code
+    a_messageMap[messageCode] = baseOffset;
+
+    // Counter name:
+    std::string counterNamePrefix = anna::functions::asString("ApplicationMessageCode_%d", messageCode); // default
+    anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
+    const anna::diameter::stack::Dictionary *dictionary = stackEngine.getDictionary(stackId);
+    if (dictionary) {
+      anna::diameter::CommandId cidR(messageCode, true /* request */);
+      anna::diameter::CommandId cidA(messageCode, false /* answer */);
+      const anna::diameter::stack::Command *commandR = dictionary->getCommand(cidR);
+      const anna::diameter::stack::Command *commandA = dictionary->getCommand(cidA);
+      if (commandR && commandA) {
+        std::string string1 = commandR->getName();
+        std::string string2 = commandA->getName();
+        std::string intersection; // non-standard names will be also intersected: XXR and XXA gives XX
+        std::set_intersection(string1.begin(), string1.end(), string2.begin(), string2.end(), std::back_inserter(intersection));
+        counterNamePrefix = intersection;
+        // Special case:
+        if (counterNamePrefix == "") counterNamePrefix = string1 + "#" + string2;
+      }
+    } 
+
+    if (counterNamePrefix[counterNamePrefix.size() - 1] != '-') counterNamePrefix += "-";
+    for (int offset = 0; offset < getCounterTypes(); offset++)
+      registerCounter(baseOffset + offset, counterNamePrefix + getDefaultInternalCounterDescription(offset), baseOffset + offset);
+  }
+
+  // Count
+  Module::count(baseOffset + type, amount);
+}
+
index 91aa8cf..7974ae7 100644 (file)
@@ -22,6 +22,7 @@
 #include <anna/diameter.comm/Response.hpp>
 #include <anna/diameter.comm/Message.hpp>
 #include <anna/diameter.comm/OamModule.hpp>
+#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
 #include <anna/diameter.comm/TimerManager.hpp>
 #include <anna/diameter.comm/Timer.hpp>
 #include <anna/diameter.comm/ClientSessionReceiver.hpp>
@@ -153,6 +154,8 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
   // Command id:
   bool isRequest;
   diameter::CommandId cid = message->getCommandId(isRequest);
+  diameter::ApplicationId aid = message->getApplicationId();
+
   LOGDEBUG(
     std::string msg = "Sending diameter message: ";
     msg += anna::diameter::functions::commandIdAsPairString(cid);
@@ -296,7 +299,7 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
     //
     updateOutgoingActivityTime();
     // OAM
-    countSendings(cid, true /* send ok */);
+    countSendings(cid, aid, true /* send ok */);
     // Trace non-application messages:
     LOGDEBUG(
 
@@ -314,7 +317,7 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
     if(fixed) message_nc->restoreSequencesAfterFix();  // restore to application sequences after fix
 
     // OAM
-    countSendings(cid, false /* send no ok */);
+    countSendings(cid, aid, false /* send no ok */);
     throw;
   }
 
@@ -524,6 +527,9 @@ throw(anna::RuntimeException) {
     }
 
     try {
+      // application message counters
+      ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsClient);
+
       eventRequest(db);
     } catch(anna::RuntimeException& ex) {
       ex.trace();
@@ -624,6 +630,10 @@ throw(anna::RuntimeException) {
     oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
     oamModule.count(OamModule::Counter::AnswerReceivedOnClientSessionUnknown);
     oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnClientSessionUnknown);
+
+    // application message counters
+    ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsClient);
+
     eventUnknownResponse(db);
     string msg(asString());
     msg += anna::functions::asString(" | Response received from entity, for non registered context (HopByHop: %u)", hopByHop);
@@ -669,6 +679,11 @@ throw(anna::RuntimeException) {
       );
       diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
       diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
+
+      // application message counters
+      if(cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer)
+        ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsClient);
+
       eventResponse(*response);
     } catch(anna::RuntimeException& ex) {
       ex.trace();
@@ -922,8 +937,10 @@ void ClientSession::updateOutgoingActivityTime(void) throw() {
 //------------------------------------------------------------------------------
 //----------------------------------------------- ClientSession::countSendings()
 //------------------------------------------------------------------------------
-void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw() {
+void ClientSession::countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok)throw() {
   OamModule &oamModule = OamModule::instantiate();
+  ApplicationMessageOamModule &appMsgOamModule = ApplicationMessageOamModule::instantiate();
+
   bool isRequest = cid.second;
 
   if(ok) {
@@ -936,6 +953,10 @@ void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw
     else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK);  // not usual (dwr was received from server)
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
+    // Application messages:
+    else {
+      appMsgOamModule.count(cid.first, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentOK_AsClient : ApplicationMessageOamModule::Counter::Answer_SentOK_AsClient);
+    }
   } else {
     // Main counters:
     oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
@@ -946,6 +967,10 @@ void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw
     else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK);  // not usual (dwr was received from server)
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
+    // Application messages:
+    else {
+      appMsgOamModule.count(cid.first, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentNOK_AsClient : ApplicationMessageOamModule::Counter::Answer_SentNOK_AsClient);
+    }
   }
 }
 
index 0eef96c..88cbe91 100644 (file)
@@ -143,6 +143,11 @@ anna::diameter::CommandId Message::getCommandId(bool &isRequest) const throw() {
   return result;
 }
 
+anna::diameter::ApplicationId Message::getApplicationId() const throw() {
+  diameter::ApplicationId result = diameter::codec::functions::getApplicationId(getBody());
+  return result;
+}
+
 HopByHop Message::getHopByHop() const throw() {
   return (diameter::codec::functions::getHopByHop(getBody()));
 }
index 1be1470..3c493d0 100644 (file)
@@ -22,6 +22,7 @@
 #include <anna/diameter.comm/Response.hpp>
 #include <anna/diameter.comm/Message.hpp>
 #include <anna/diameter.comm/OamModule.hpp>
+#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
 #include <anna/diameter.comm/TimerManager.hpp>
 #include <anna/diameter.comm/Timer.hpp>
 #include <anna/diameter.comm/LocalServer.hpp>
@@ -90,6 +91,8 @@ const Response* ServerSession::send(const Message* message) throw(anna::RuntimeE
   // Command id:
   bool isRequest;
   diameter::CommandId cid = message->getCommandId(isRequest);
+  diameter::ApplicationId aid = message->getApplicationId();
+
   LOGDEBUG(
     std::string msg = "Sending diameter message: ";
     msg += anna::diameter::functions::commandIdAsPairString(cid);
@@ -208,7 +211,7 @@ const Response* ServerSession::send(const Message* message) throw(anna::RuntimeE
     //
     updateOutgoingActivityTime();
     // OAM
-    countSendings(cid, true /* send ok */);
+    countSendings(cid, aid, true /* send ok */);
     // Trace non-application messages:
     LOGDEBUG(
 
@@ -225,7 +228,7 @@ const Response* ServerSession::send(const Message* message) throw(anna::RuntimeE
     if(fixed) message_nc->restoreSequencesAfterFix();  // restore to application sequences after fix
 
     // OAM
-    countSendings(cid, false /* send no ok */);
+    countSendings(cid, aid, false /* send no ok */);
     throw;
   }
 
@@ -395,6 +398,9 @@ throw(anna::RuntimeException) {
     }
 
     try {
+      // application message counters
+      ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsServer);
+
       eventRequest(db);
     } catch(anna::RuntimeException& ex) {
       ex.trace();
@@ -444,7 +450,12 @@ throw(anna::RuntimeException) {
     oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
     oamModule.count(OamModule::Counter::AnswerReceivedOnServerSessionUnknown);
     oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnServerSessionUnknown);
+
+    // application message counters
+    ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsServer);
+
     eventUnknownResponse(db);
+
     string msg(asString());
     msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop);
     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
@@ -490,7 +501,12 @@ throw(anna::RuntimeException) {
       );
       diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
       diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
+
+      // application message counters
+      ApplicationMessageOamModule::instantiate().count(cid.first, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsServer);
+
       eventResponse(*response);
+
     } catch(anna::RuntimeException& ex) {
       ex.trace();
     }
@@ -696,8 +712,10 @@ void ServerSession::updateOutgoingActivityTime(void) throw() {
 //------------------------------------------------------------------------------
 //----------------------------------------------- ServerSession::countSendings()
 //------------------------------------------------------------------------------
-void ServerSession::countSendings(const diameter::CommandId & cid, bool ok)throw() {
+void ServerSession::countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok)throw() {
   OamModule &oamModule = OamModule::instantiate();
+  ApplicationMessageOamModule &appMsgOamModule = ApplicationMessageOamModule::instantiate();
+
   bool isRequest = cid.second;
 
   if(ok) {
@@ -710,6 +728,10 @@ void ServerSession::countSendings(const diameter::CommandId & cid, bool ok)throw
     else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK);  // not usual
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
+    // Application messages:
+    else {
+      appMsgOamModule.count(cid.first, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentOK_AsServer);
+    }
   } else {
     // Main counters:
     oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
@@ -720,6 +742,10 @@ void ServerSession::countSendings(const diameter::CommandId & cid, bool ok)throw
     else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK);  // not usual
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);
+    // Application messages:
+    else {
+      appMsgOamModule.count(cid.first, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentNOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentNOK_AsServer);
+    }
   }
 }