Fix local server for multiple applications
[anna.git] / example / diameter / rxSimpleTest / rxSimpleTest.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 // Standard
10 #include <sstream>      // std::istringstream
11 #include <iostream>     // std::cout
12 #include <math.h> // ceil
13 #include <climits>
14 #include <unistd.h> // chdir
15 //#include <regex> TODO: use this from gcc4.9.0: http://stackoverflow.com/questions/8060025/is-this-c11-regex-error-me-or-the-compiler
16 #include <stdio.h>
17
18 // Project
19 #include <anna/timex/Engine.hpp>
20 #include <anna/statistics/Engine.hpp>
21 #include <anna/diameter/codec/functions.hpp>
22 #include <anna/diameter/codec/Engine.hpp>
23 #include <anna/diameter/codec/EngineManager.hpp>
24 #include <anna/diameter/stack/Engine.hpp>
25 #include <anna/diameter/helpers/base/functions.hpp>
26 #include <anna/time/functions.hpp>
27 #include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
28 #include <anna/testing/defines.hpp>
29 #include <anna/xml/xml.hpp>
30 #include <anna/diameter.comm/OriginHost.hpp>
31 #include <anna/diameter.comm/OriginHostManager.hpp>
32
33 // Process
34 #include <rxSimpleTest.hpp>
35 #include <MyDiameterEngine.hpp>
36
37 RxSimpleTest::RxSimpleTest() : anna::comm::Application("rxSimpleTest", "RxSimpleTest", "1.1"), a_communicator(NULL) {
38   a_timeEngine = NULL;
39   a_admlMinResolution = 2 * anna::timex::Engine::minResolution; // 2*10 = 20 ms; 1000/20 = 50 ticks per second;
40   //a_admlMinResolution = (anna::Millisecond)100;
41   a_workingNode = NULL;
42 }
43
44 void RxSimpleTest::startService() noexcept(false) {
45
46   // Stacks
47   anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate();
48   anna::diameter::stack::Dictionary *d;
49   const anna::diameter::stack::Dictionary *bpd = NULL; // base protocol dictionary
50
51   // Codec engine manager:
52   anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
53   anna::diameter::codec::Engine *ce;
54
55   ///////////////////////////////////////////
56   // APPLICATION MESSAGE OAM MODULE SCOPES //
57   ///////////////////////////////////////////
58   // We will register a scope per stack id registered. The counters will be dynamically registered at count method.
59   anna::diameter::comm::ApplicationMessageOamModule & appMsgOamModule = anna::diameter::comm::ApplicationMessageOamModule::instantiate();
60   appMsgOamModule.enableCounters(); // this special module is disabled by default (the only)
61   int scope_id = 3;
62   unsigned int id_value = anna::diameter::helpers::APPID__3GPP_Rx; // 16777236
63
64   try {
65     d = stackEngine.createDictionary(id_value, "./dictionaryRx.xml");
66     LOGDEBUG(anna::Logger::debug(anna::functions::asString("Created dictionary (%p) for stack id %llu", d, id_value), ANNA_FILE_LOCATION));
67
68     // OAM module for counters:
69     appMsgOamModule.createStackCounterScope(scope_id, id_value /* application-id */);
70
71   } catch(anna::RuntimeException &ex) {
72     //_exit(ex.asString());
73     throw ex;
74   }
75
76   bpd = d; // base protocol dictionary in case of monostack
77
78   // Create codec engine and register it in the codec engine manager:
79   std::string codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", id_value);
80   ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d);
81   em.registerCodecEngine(id_value, ce);
82
83   // Codec engine configuration:
84
85   // Validation mode: BeforeEncoding, AfterDecoding, Always, Never
86   ce->setValidationMode(anna::diameter::codec::Engine::ValidationMode::AfterDecoding);
87
88   // Validation depth: Complete, FirstError
89   ce->setValidationDepth(anna::diameter::codec::Engine::ValidationDepth::FirstError);
90
91   // Fix mode: BeforeEncoding, AfterDecoding, Always, Never
92   ce->setFixMode(anna::diameter::codec::Engine::FixMode::BeforeEncoding);
93
94   // Ignore validation flags:
95   ce->ignoreFlagsOnValidation(true);
96
97   // Show loaded stacks:
98   std::cout << "Stacks currently loaded:" << std::endl;
99   std::cout << anna::functions::tab(stackEngine.asString(false /* light */)) << std::endl;
100
101   // REALMS:
102   unsigned int applicationId = id_value;
103   if (!stackEngine.getDictionary(applicationId)) {
104     std::string msg = anna::functions::asString("Cannot found a registered stack id with the value of applicationId provided: %u", applicationId);
105     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
106   }
107
108   // Engine time measures checking & assignment:
109   anna::Millisecond allowedInactivityTimeMs(90000);
110   anna::Millisecond tcpConnectDelayMs(200);
111   anna::Millisecond answersTimeoutMs(10000);
112   anna::Millisecond ceaTimeoutMs(10000);
113   anna::Millisecond watchdogPeriodMs(30000);
114
115   /////////////////////////////////////////////////////////////////////////////////////////////
116   // Diameter communication engine:
117   std::string originHostRealm = "nodeHostRealm";
118   std::string originHostName = "afNodeHostname."; originHostName += originHostRealm; originHostName += ".com";
119   std::string commEngineName = originHostName + "_DiameterCommEngine";
120   MyDiameterEngine *commEngine = new MyDiameterEngine(commEngineName.c_str(), bpd);
121   commEngine->setAutoBind(false);  // allow to create client-sessions without binding them, in order to set timeouts.
122   commEngine->setMaxConnectionDelay(tcpConnectDelayMs);
123   commEngine->setWatchdogPeriod(watchdogPeriodMs);
124   commEngine->setOriginHostName(originHostName);
125   commEngine->setOriginRealmName(originHostRealm);
126
127   // Origin host node:
128   a_workingNode = new anna::diameter::comm::OriginHost((anna::diameter::comm::Engine*)commEngine, applicationId);
129   // a_workingNode->setRequestRetransmissions(0);
130
131   // Diameter entity:
132   commEngine->setNumberOfClientSessionsPerServer(1);
133   commEngine->setClientCER(anna::diameter::helpers::APPID__3GPP_Rx);
134   commEngine->setClientDWR(); // default
135
136   // Register one entity for this engine:
137   a_workingNode->createEntity("localhost:3868", ceaTimeoutMs, answersTimeoutMs);
138   a_workingNode->getEntity()->bind();
139
140   // Diameter server:
141   //a_workingNode->createDiameterServer("localhost:3869", 1, allowedInactivityTimeMs, answersTimeoutMs, "./cea.xml");
142
143   commEngine->lazyInitialize();
144
145   // Node and Codec Engine registration ///////////////////////////////////////////////////////
146   anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
147   ohm.registerOriginHost(originHostName, a_workingNode);
148 }
149
150 anna::diameter::comm::OriginHost *RxSimpleTest::getOriginHost(const std::string &name) const noexcept(false) {
151   anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
152   anna::diameter::comm::OriginHost *result = ohm.getOriginHost(name);
153
154   if (!result)
155   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);
156
157   return result;
158 }
159
160 MyDiameterEntity *RxSimpleTest::getEntity() const noexcept(false) {
161   MyDiameterEntity *result = (MyDiameterEntity *)(a_workingNode->getEntity());
162   if (!result)
163     throw anna::RuntimeException("No entity created", ANNA_FILE_LOCATION);
164   return result;
165 }
166
167 MyLocalServer *RxSimpleTest::getServer() const noexcept(false) {
168   MyLocalServer *result = (MyLocalServer *)(a_workingNode->getDiameterServer());
169   if (!result)
170     throw anna::RuntimeException("No local server created", ANNA_FILE_LOCATION);
171   return result;
172 }
173
174 void RxSimpleTest::initialize()
175 noexcept(false) {
176   anna::comm::Application::initialize();
177   CommandLine& cl(anna::CommandLine::instantiate());
178   anna::comm::Communicator::WorkMode::_v workMode(anna::comm::Communicator::WorkMode::Single);
179   a_communicator = new MyCommunicator(workMode);
180   a_timeEngine = new anna::timex::Engine((anna::Millisecond)600000, a_admlMinResolution);
181
182   startService();
183 }
184
185 void RxSimpleTest::run()
186 noexcept(false) {
187   LOGMETHOD(anna::TraceMethod tm("RxSimpleTest", "run", ANNA_FILE_LOCATION));
188   anna::diameter::stack::Engine::instantiate();
189
190   // Start time:
191   a_start_time.setNow();
192
193   // Initial working directory:
194   char cwd[1024];
195   if (getcwd(cwd, sizeof(cwd)) == NULL)
196     throw anna::RuntimeException("Cannot retrieve initial working directory !!", ANNA_FILE_LOCATION);
197   a_initialWorkingDirectory = cwd;
198
199   // Statistics:
200   anna::statistics::Engine::instantiate().enable();
201
202   // Start client connections //////////////////////////////////////////////////////////////////////////////////
203   MyDiameterEntity *entity;
204   anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
205   for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
206     entity = (MyDiameterEntity *)(it->second->getEntity());
207     if (entity) entity->bind();
208   }
209
210   // Go into communicator poll
211   // Reconnection period (tcp reconnect retry time):
212   anna::Millisecond reconnectionPeriod = (anna::Millisecond)10000;
213
214   a_communicator->setRecoveryTime(reconnectionPeriod);
215   a_communicator->accept();
216 }
217
218 anna::xml::Node* RxSimpleTest::asXML(anna::xml::Node* parent) const
219 {
220   anna::xml::Node* result = parent->createChild("rxSimpleTest");
221   anna::comm::Application::asXML(result);
222   // Timming:
223   result->createAttribute("StartTime", a_start_time.asString());
224   result->createAttribute("InitialWorkingDirectory", a_initialWorkingDirectory);
225   result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000);
226   // Diameter:
227   anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
228   for (diameter::comm::origin_hosts_it it = ohm.begin(); it != ohm.end(); it++) {
229     it->second->asXML(result);
230   }
231
232   // Registered codec engines:
233   anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate();
234   em.asXML(result);
235
236   return result;
237 }
238