New rxSimpleTest example
[anna.git] / example / diameter / rxSimpleTest / rxSimpleTest.cpp
diff --git a/example/diameter/rxSimpleTest/rxSimpleTest.cpp b/example/diameter/rxSimpleTest/rxSimpleTest.cpp
new file mode 100755 (executable)
index 0000000..95a3580
--- /dev/null
@@ -0,0 +1,238 @@
+// 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 <sstream>      // std::istringstream
+#include <iostream>     // std::cout
+#include <math.h> // ceil
+#include <climits>
+#include <unistd.h> // chdir
+//#include <regex> TODO: use this from gcc4.9.0: http://stackoverflow.com/questions/8060025/is-this-c11-regex-error-me-or-the-compiler
+#include <stdio.h>
+
+// Project
+#include <anna/timex/Engine.hpp>
+#include <anna/statistics/Engine.hpp>
+#include <anna/diameter/codec/functions.hpp>
+#include <anna/diameter/codec/Engine.hpp>
+#include <anna/diameter/codec/EngineManager.hpp>
+#include <anna/diameter/stack/Engine.hpp>
+#include <anna/diameter/helpers/base/functions.hpp>
+#include <anna/time/functions.hpp>
+#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
+#include <anna/testing/defines.hpp>
+#include <anna/xml/xml.hpp>
+#include <anna/diameter.comm/OriginHost.hpp>
+#include <anna/diameter.comm/OriginHostManager.hpp>
+
+// Process
+#include <rxSimpleTest.hpp>
+#include <MyDiameterEngine.hpp>
+
+RxSimpleTest::RxSimpleTest() : anna::comm::Application("rxSimpleTest", "RxSimpleTest", "1.1"), a_communicator(NULL) {
+  a_timeEngine = NULL;
+  a_admlMinResolution = 2 * anna::timex::Engine::minResolution; // 2*10 = 20 ms; 1000/20 = 50 ticks per second;
+  //a_admlMinResolution = (anna::Millisecond)100;
+  a_workingNode = NULL;
+}
+
+void RxSimpleTest::startService() throw(anna::RuntimeException) {
+
+  // Stacks
+  anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
+  anna::diameter::stack::Dictionary *d;
+  const anna::diameter::stack::Dictionary *bpd = NULL; // base protocol dictionary
+
+  // Codec engine manager:
+  anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+  anna::diameter::codec::Engine *ce;
+
+  ///////////////////////////////////////////
+  // 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();
+  appMsgOamModule.enableCounters(); // this special module is disabled by default (the only)
+  int scope_id = 3;
+  unsigned int id_value = anna::diameter::helpers::APPID__3GPP_Rx; // 16777236
+
+  try {
+    d = stackEngine.createDictionary(id_value, "./dictionaryRx.xml");
+    LOGDEBUG(anna::Logger::debug(anna::functions::asString("Created dictionary (%p) for stack id %llu", d, id_value), ANNA_FILE_LOCATION));
+
+    // OAM module for counters:
+    appMsgOamModule.createStackCounterScope(scope_id, id_value /* application-id */);
+
+  } catch(anna::RuntimeException &ex) {
+    //_exit(ex.asString());
+    throw ex;
+  }
+
+  bpd = d; // base protocol dictionary in case of monostack
+
+  // Create codec engine and register it in the codec engine manager:
+  std::string codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", id_value);
+  ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d);
+  em.registerCodecEngine(id_value, ce);
+
+  // Codec engine configuration:
+
+  // Validation mode: BeforeEncoding, AfterDecoding, Always, Never
+  ce->setValidationMode(anna::diameter::codec::Engine::ValidationMode::AfterDecoding);
+
+  // Validation depth: Complete, FirstError
+  ce->setValidationDepth(anna::diameter::codec::Engine::ValidationDepth::FirstError);
+
+  // Fix mode: BeforeEncoding, AfterDecoding, Always, Never
+  ce->setFixMode(anna::diameter::codec::Engine::FixMode::BeforeEncoding);
+
+  // Ignore validation flags:
+  ce->ignoreFlagsOnValidation(true);
+
+  // Show loaded stacks:
+  std::cout << "Stacks currently loaded:" << std::endl;
+  std::cout << anna::functions::tab(stackEngine.asString(false /* light */)) << std::endl;
+
+  // REALMS:
+  unsigned int applicationId = id_value;
+  if (!stackEngine.getDictionary(applicationId)) {
+    std::string msg = anna::functions::asString("Cannot found a registered stack id with the value of applicationId provided: %u", applicationId);
+    throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+  }
+
+  // Engine time measures checking & assignment:
+  anna::Millisecond allowedInactivityTimeMs(90000);
+  anna::Millisecond tcpConnectDelayMs(200);
+  anna::Millisecond answersTimeoutMs(10000);
+  anna::Millisecond ceaTimeoutMs(10000);
+  anna::Millisecond watchdogPeriodMs(30000);
+
+  /////////////////////////////////////////////////////////////////////////////////////////////
+  // Diameter communication engine:
+  std::string originHostRealm = "nodeHostRealm";
+  std::string originHostName = "afNodeHostname."; originHostName += originHostRealm; originHostName += ".com";
+  std::string commEngineName = originHostName + "_DiameterCommEngine";
+  MyDiameterEngine *commEngine = new MyDiameterEngine(commEngineName.c_str(), bpd);
+  commEngine->setAutoBind(false);  // allow to create client-sessions without binding them, in order to set timeouts.
+  commEngine->setMaxConnectionDelay(tcpConnectDelayMs);
+  commEngine->setWatchdogPeriod(watchdogPeriodMs);
+  commEngine->setOriginHostName(originHostName);
+  commEngine->setOriginRealmName(originHostRealm);
+
+  // Origin host node:
+  a_workingNode = new anna::diameter::comm::OriginHost((anna::diameter::comm::Engine*)commEngine, applicationId);
+  // a_workingNode->setRequestRetransmissions(0);
+
+  // Diameter entity:
+  commEngine->setNumberOfClientSessionsPerServer(1);
+  //commEngine->setClientCERandDWR("./cer.xml", "./dwr.xml");
+  commEngine->setClientCERandDWR();
+
+  // Register one entity for this engine:
+  a_workingNode->createEntity("localhost:3868", ceaTimeoutMs, answersTimeoutMs);
+  a_workingNode->getEntity()->bind();
+
+  // Diameter server:
+  //a_workingNode->createDiameterServer("localhost:3869", 1, allowedInactivityTimeMs, answersTimeoutMs, "./cea.xml");
+
+  commEngine->lazyInitialize();
+
+  // Node and Codec Engine registration ///////////////////////////////////////////////////////
+  anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+  ohm.registerOriginHost(originHostName, a_workingNode);
+}
+
+anna::diameter::comm::OriginHost *RxSimpleTest::getOriginHost(const std::string &name) const throw(anna::RuntimeException) {
+  anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+  anna::diameter::comm::OriginHost *result = ohm.getOriginHost(name);
+
+  if (!result)
+  throw anna::RuntimeException(anna::functions::asString("There is no origin host registered as '%s' (set Origin-Host avp correctly or force a specific host with 'node' operation)", name.c_str()), ANNA_FILE_LOCATION);
+
+  return result;
+}
+
+MyDiameterEntity *RxSimpleTest::getEntity() const throw(anna::RuntimeException) {
+  MyDiameterEntity *result = (MyDiameterEntity *)(a_workingNode->getEntity());
+  if (!result)
+    throw anna::RuntimeException("No entity created", ANNA_FILE_LOCATION);
+  return result;
+}
+
+MyLocalServer *RxSimpleTest::getServer() const throw(anna::RuntimeException) {
+  MyLocalServer *result = (MyLocalServer *)(a_workingNode->getDiameterServer());
+  if (!result)
+    throw anna::RuntimeException("No local server created", ANNA_FILE_LOCATION);
+  return result;
+}
+
+void RxSimpleTest::initialize()
+throw(anna::RuntimeException) {
+  anna::comm::Application::initialize();
+  CommandLine& cl(anna::CommandLine::instantiate());
+  anna::comm::Communicator::WorkMode::_v workMode(anna::comm::Communicator::WorkMode::Single);
+  a_communicator = new MyCommunicator(workMode);
+  a_timeEngine = new anna::timex::Engine((anna::Millisecond)600000, a_admlMinResolution);
+
+  startService();
+}
+
+void RxSimpleTest::run()
+throw(anna::RuntimeException) {
+  LOGMETHOD(anna::TraceMethod tm("RxSimpleTest", "run", ANNA_FILE_LOCATION));
+  anna::diameter::stack::Engine::instantiate();
+
+  // Start time:
+  a_start_time.setNow();
+
+  // Initial working directory:
+  char cwd[1024];
+  if (getcwd(cwd, sizeof(cwd)) == NULL)
+    throw anna::RuntimeException("Cannot retrieve initial working directory !!", ANNA_FILE_LOCATION);
+  a_initialWorkingDirectory = cwd;
+
+  // Statistics:
+  anna::statistics::Engine::instantiate().enable();
+
+  // Start client connections //////////////////////////////////////////////////////////////////////////////////
+  MyDiameterEntity *entity;
+  anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+  for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
+    entity = (MyDiameterEntity *)(it->second->getEntity());
+    if (entity) entity->bind();
+  }
+
+  // Go into communicator poll
+  // Reconnection period (tcp reconnect retry time):
+  anna::Millisecond reconnectionPeriod = (anna::Millisecond)10000;
+
+  a_communicator->setRecoveryTime(reconnectionPeriod);
+  a_communicator->accept();
+}
+
+anna::xml::Node* RxSimpleTest::asXML(anna::xml::Node* parent) const
+throw() {
+  anna::xml::Node* result = parent->createChild("rxSimpleTest");
+  anna::comm::Application::asXML(result);
+  // Timming:
+  result->createAttribute("StartTime", a_start_time.asString());
+  result->createAttribute("InitialWorkingDirectory", a_initialWorkingDirectory);
+  result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000);
+  // Diameter:
+  anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+  for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
+    it->second->asXML(result);
+  }
+
+  // Registered codec engines:
+  anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
+  em.asXML(result);
+
+  return result;
+}
+