Dynamic realm registration
[anna.git] / source / diameter.comm / Engine.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 #include <anna/diameter.comm/Engine.hpp>
10
11 #include <anna/core/tracing/Logger.hpp>
12 #include <anna/core/tracing/TraceMethod.hpp>
13 #include <anna/xml/Node.hpp>
14 #include <anna/comm/Network.hpp>
15 #include <anna/comm/Host.hpp>
16 #include <anna/comm/ClientSocket.hpp>
17
18 #include <anna/diameter.comm/Transport.hpp>
19 #include <anna/diameter.comm/Engine.hpp>
20 #include <anna/diameter.comm/Entity.hpp>
21 #include <anna/diameter.comm/Server.hpp>
22 #include <anna/diameter.comm/ClientSession.hpp>
23 #include <anna/diameter.comm/LocalServer.hpp>
24 #include <anna/core/functions.hpp>
25 #include <anna/diameter/internal/sccs.hpp>
26 #include <anna/diameter.comm/OamModule.hpp>
27 #include <anna/diameter/codec/functions.hpp>
28 #include <anna/diameter/helpers/base/functions.hpp>
29 #include <anna/diameter/helpers/helpers.hpp>
30 #include <anna/diameter/codec/Message.hpp>
31 #include <anna/diameter/codec/Avp.hpp>
32
33 // STD
34 #include <map>
35
36 using namespace std;
37 using namespace anna::diameter::comm;
38
39
40 Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
41   anna::app::Component(className),
42   a_baseProtocolCodecEngine(baseProtocolCodecEngine),
43   a_autoBind(true),
44   a_availableForEntities(false),
45   a_availableForLocalServers(false),
46   a_cer(true),
47   a_dwr(true),
48 //      a_cea(true),
49 //      a_dwa(true),
50   a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
51   a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
52   a_numberOfClientSessionsPerServer(1) {
53   anna::diameter::sccs::activate();
54   a_realm = anna::functions::getDomainname();
55   a_host = anna::functions::getHostname();
56 }
57
58 Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); }
59 void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
60 ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
61 void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
62
63
64 void Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
65   if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
66     throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
67   }
68
69   if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
70     throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
71   }
72
73   a_cer = cer;
74   a_dwr = dwr;
75 }
76
77 void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
78
79   // Check for base protocol codec engine:
80   if (!getBaseProtocolCodecEngine())
81     throw anna::RuntimeException("Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow base protocol messages encoding, or use setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) which expect externally encoded messages", ANNA_FILE_LOCATION);
82
83   // Build CER
84   //   <CER> ::= < Diameter Header: 257, REQ >
85   //             { Origin-Host } 264 diameterIdentity
86   //             { Origin-Realm } 296 idem
87   //          1* { Host-IP-Address } 257, address
88   //             { Vendor-Id } 266 Unsigned32
89   //             { Product-Name } 269 UTF8String
90   //             [Origin-State-Id] 278 Unsigned32
91   //           * [ Supported-Vendor-Id ]  265 Unsigned32
92   //           * [ Auth-Application-Id ] 258 Unsigned32
93   //           * [Acct-Application-Id]  259 Unsigned32
94   anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
95   int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32
96   std::string OH = getHost();
97   std::string OR = getRealm();
98   std::string hostIP = anna::functions::getHostnameIP(); // Address
99   int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
100   std::string productName = "ANNA Diameter Client"; // UTF8String
101   bool encodeDefault = false;
102
103   if (cer != "") {
104     try {
105       diameterCER.loadXML(cer);
106     } catch(anna::RuntimeException &ex) {
107       //ex.trace();
108       encodeDefault = true;
109       LOGWARNING(anna::Logger::warning("CER file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
110     }
111   }
112   else {
113     encodeDefault = true;
114   }
115
116   if(encodeDefault) {
117     diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request);
118     diameterCER.setApplicationId(applicationId);
119     diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
120     diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
121     diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str()); // supported by Address class, anyway is better to provide "1|<ip address>"
122     diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
123     diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
124     diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId);
125   }
126
127   // Build DWR
128   //   <DWR>  ::= < Diameter Header: 280, REQ >
129   //              { Origin-Host }
130   //              { Origin-Realm }
131   anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine());
132   encodeDefault = false;
133
134   if (dwr != "") {
135     try {
136       diameterDWR.loadXML(dwr);
137     } catch(anna::RuntimeException &ex) {
138       //ex.trace();
139       encodeDefault = true;
140       LOGWARNING(anna::Logger::warning("DWR file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
141     }
142   }
143   else {
144     encodeDefault = true;
145   }
146
147   if(encodeDefault) {
148     diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request);
149     diameterDWR.setApplicationId(applicationId);
150     diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
151     diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
152   }
153
154   // Assignment for internal encoded versions:
155   setClientCERandDWR(diameterCER.code(), diameterDWR.code());
156 }
157
158 void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
159   if(wp < ClientSession::DefaultWatchdogPeriod) {
160     throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
161   }
162
163   a_watchdogPeriod = wp;
164 }
165
166 void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
167   socket_v::const_iterator it;
168   socket_v::const_iterator it_min(v.begin());
169   socket_v::const_iterator it_max(v.end());
170
171   for(it = it_min; it != it_max; it++) {
172     server_iterator ii = server_find(*it);
173
174     if(ii != server_end())
175       throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
176   }
177
178   // Check repetitions:
179   std::map < socket_t, int/*dummy*/ > auxMap;
180
181   for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
182
183   if(auxMap.size() != v.size())
184     throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
185 }
186
187 Entity* Engine::createEntity(const socket_v & socketList, const std::string &description)
188 throw(anna::RuntimeException) {
189   Entity* result(NULL);
190   anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
191
192   if(socketList.size() == 0)
193     throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
194
195   // Proteccion antes de reservar memoria para una entidad (allocateEntity):
196   checkEntityCollision(socketList);
197
198   if((result = allocateEntity()) == NULL)
199     throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
200
201   // Initialize:
202   result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
203   // Assignments (it could be done at allocate):
204   result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
205   result->setMaxServers(socketList.size());
206   result->setDescription(description);
207   entity_key key(getEntityKey(socketList));
208   result->a_socketListLiteral = key;
209   // Create associated servers:
210   socket_v::const_iterator it;
211   socket_v::const_iterator it_min(socketList.begin());
212   socket_v::const_iterator it_max(socketList.end());
213   int count = 1;
214
215   for(it = it_min; it != it_max; it++) {
216     result->addServer(*it);
217
218     if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
219
220     if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
221
222     count++;
223   }
224
225   a_entities.insert(entity_value_type(key, result));
226   LOGDEBUG(
227     string msg("diameter::comm::Engine::createEntity | ");
228     msg += result->asString();
229     msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
230     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
231   );
232   return result;
233 }
234
235
236 LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
237 throw(anna::RuntimeException) {
238   LocalServer* result(NULL);
239   anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
240   // Proteccion antes de reservar memoria para un LocalServer
241   socket_t key(addr, port);
242
243   if(a_localServers.find(key) != a_localServers.end())
244     throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
245
246   if((result = allocateLocalServer()) == NULL)
247     throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
248
249   result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa)
250   result->setKey(key);
251   result->setCategory(category);
252   result->setDescription(description);
253   result->setAllowedInactivityTime(allowedInactivityTime);
254   result->initializeStatisticConcepts();
255 // Los saco con metodos virtuales readXXX del motor:
256 //   if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
257 //      throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
258   a_localServers.insert(localServer_value_type(key, result));
259   LOGDEBUG(
260     string msg("diameter::comm::Engine::createLocalServer | ");
261     msg += result->asString();
262     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
263   );
264 //   // Listen: (*)
265 //   /*if (a_autoListen) */result->enable(); // creates server socket
266   result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
267   return result;
268 }
269
270
271 Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
272 throw(anna::RuntimeException) {
273   socket_v dualList;
274   dualList.push_back(socket_t(addr1, port1));
275   dualList.push_back(socket_t(addr2, port2));
276   return (createEntity(dualList, description));
277 }
278
279
280 Server* Engine::createServer(Entity *entity, const socket_t & socket)
281 throw(anna::RuntimeException) {
282   Server* result(NULL);
283   anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
284
285   if((result = allocateServer()) == NULL)
286     throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
287
288   // Initialize:
289   result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
290   // Assignments (it could be done at allocate):
291   result->a_parent = entity;
292   result->a_socket = socket;
293   result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
294   result->a_engine = this;
295   result->initializeStatisticConcepts();
296
297   for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
298     result->addClientSession(k);
299
300   a_servers.insert(server_value_type(socket, result));
301 //      LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
302 //         string msg("diameter::comm::Engine::resolveServer | ");
303 //         msg += result->asString();
304 //         msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
305 //         anna::Logger::debug(msg, ANNA_FILE_LOCATION);
306 //      );
307   return result;
308 }
309
310
311 // Lohacemos privado
312 ClientSession* Engine::createClientSession(Server *server, int socketId)
313 throw(anna::RuntimeException) {
314   ClientSession* result(NULL);
315   anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
316
317   if((result = allocateClientSession()) == NULL)
318     throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
319
320   // Initialize:
321   result->initialize(); // warning: recycler does not initialize its objects and at least...
322   // Assignments (it could be done at allocate):
323
324   if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
325     throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
326
327   result->a_cer.setBody(a_cer);
328   result->a_dwr.setBody(a_dwr);
329   result->setWatchdogPeriod(a_watchdogPeriod);
330   result->a_parent = server;
331   result->a_socketId = socketId;
332   result->initializeSequences(); // despu�s de asignar el server y el socketId (*)
333   // (*) Las secuencias se basan en la semilla:    srand(::time(NULL) + anna::functions::exclusiveHash(anna::functions::asString("%s:%d|%d", getAddress().c_str(), getPort(), a_socketId)));
334   result->a_engine = this;
335   clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
336   a_clientSessions.insert(clientSession_value_type(key, result));
337 //      LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
338 //         string msg("diameter::comm::Engine::createClientSession | ");
339 //         msg += result->asString();
340 //         msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
341 //         anna::Logger::debug(msg, ANNA_FILE_LOCATION);
342 //      );
343   // Creation:
344   anna::comm::Network& network = anna::comm::Network::instantiate();
345   result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
346                      result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
347                      anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
348   // Delay time on tcp connect:
349   result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
350
351   // Bind:
352   if(a_autoBind) result->bind();
353
354   return result;
355 }
356
357
358 bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
359   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
360   bool allok = true;
361   bool ok;
362
363   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
364     try {
365       ok = entity(it)->broadcast(message);
366
367       if(!ok) allok = false;
368     } catch(anna::RuntimeException &ex) {
369       ex.trace();
370       allok = false;
371     }
372   }
373
374   return allok;
375 }
376
377 bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
378   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
379   bool allok = true;
380   bool ok;
381
382   for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
383     try {
384       ok = localServer(it)->broadcast(message);
385
386       if(!ok) allok = false;
387     } catch(anna::RuntimeException &ex) {
388       ex.trace();
389       allok = false;
390     }
391   }
392
393   return allok;
394 }
395
396 bool Engine::bind() throw(anna::RuntimeException) {
397   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
398   bool result = true; // all OK return
399
400   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
401     try {
402       entity(it)->bind();
403     } catch(anna::RuntimeException &ex) {
404       ex.trace();
405       result = false;
406     }
407   }
408
409   return result;
410 }
411
412 ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
413 throw(anna::RuntimeException) {
414   return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
415 }
416
417 ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
418 throw(anna::RuntimeException) {
419   anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
420   clientSession_iterator ii = clientSession_find(key);
421
422   if(ii != clientSession_end())
423     return clientSession(ii);
424
425   if(emode != anna::Exception::Mode::Ignore) {
426     string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
427     msg += key;
428     msg += " | ClientSession not found";
429     anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
430
431     if(emode == anna::Exception::Mode::Throw)
432       throw ex;
433
434     ex.trace();
435   }
436
437   return NULL;
438 }
439
440
441 Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
442 throw(anna::RuntimeException) {
443   anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
444   server_iterator ii = server_find(server_key(addr, port));
445
446   if(ii != server_end())
447     return server(ii);
448
449   if(emode != anna::Exception::Mode::Ignore) {
450     string msg("diameter::comm::Engine::findServer | addr: ");
451     msg += addr;
452     msg += anna::functions::asText(" | port: ", port);
453     msg += " | Server not found";
454     anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
455
456     if(emode == anna::Exception::Mode::Throw)
457       throw ex;
458
459     ex.trace();
460   }
461
462   return NULL;
463 }
464
465 Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
466 throw(anna::RuntimeException) {
467   anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
468   entity_key key(getEntityKey(socketList));
469   entity_iterator ii = entity_find(key);
470
471   if(ii != entity_end())
472     return entity(ii);
473
474   if(emode != anna::Exception::Mode::Ignore) {
475     string msg("diameter::comm::Engine::findEntity | socket list: ");
476     msg += key;
477     msg += " | Entity not found";
478     anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
479
480     if(emode == anna::Exception::Mode::Throw)
481       throw ex;
482
483     ex.trace();
484   }
485
486   return NULL;
487 }
488
489 Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
490 throw(anna::RuntimeException) {
491   socket_v dualList;
492   dualList.push_back(socket_t(addr1, port1));
493   dualList.push_back(socket_t(addr2, port2));
494   return (findEntity(dualList, emode));
495 }
496
497
498 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
499 //throw(anna::RuntimeException) {
500 //
501 //   Entity *entity;
502 //
503 //   for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
504 //      entity = entity(it);
505 //      if (entity->getCategory() == category) return entity;
506 //   }
507 //
508 //   return NULL;
509 //}
510
511
512 LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
513 throw(anna::RuntimeException) {
514   anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
515   socket_t key(addr, port);
516   localServer_iterator ii = localServer_find(key);
517
518   if(ii != localServer_end())
519     return localServer(ii);
520
521   if(emode != anna::Exception::Mode::Ignore) {
522     string msg("diameter::comm::Engine::findLocalServer | addr: ");
523     msg += addr;
524     msg += anna::functions::asText(" | port: ", port);
525     msg += " | LocalServer not found";
526     anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
527
528     if(emode == anna::Exception::Mode::Throw)
529       throw ex;
530
531     ex.trace();
532   }
533
534   return NULL;
535 }
536
537
538 ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
539   anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
540   ServerSession *result;
541
542   // Search at each local server:
543   for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
544     result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
545
546     if(result) return result;
547   }
548
549   if(emode != anna::Exception::Mode::Ignore) {
550     string msg("diameter::comm::Engine::findServerSession | socketId: ");
551     msg += anna::functions::asString(socketId);
552     msg += " | ServerSession not found";
553     anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
554
555     if(emode == anna::Exception::Mode::Throw)
556       throw ex;
557
558     ex.trace();
559   }
560
561   return NULL;
562 }
563
564
565 void Engine::closeClientSession(ClientSession* clientSession, bool destroy)
566 throw(anna::RuntimeException) {
567   if(clientSession == NULL)
568     return;
569
570   LOGDEBUG(
571     string msg("diameter::comm::Engine::closeClientSession | ");
572     msg += clientSession->asString();
573     msg += " | Destroy: ";
574     msg += (destroy ? "yes" : "no");
575     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
576   );
577   anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
578   clientSession_iterator ii = clientSession_find(clientSession->getKey());
579
580   if(ii == clientSession_end())
581     return;
582
583   try {
584     clientSession->setState(ClientSession::State::Closing);
585
586     if(destroy) clientSession->setAutoRecovery(false);
587
588     clientSession->unbind(destroy /* destroy needs to perform immediate close */);
589
590     if(!destroy) return;
591
592     releaseClientSession(clientSession);
593   } catch(anna::RuntimeException& ex) {
594     ex.trace();
595   }
596
597   a_clientSessions.erase(ii);
598 }
599
600
601
602
603 void Engine::closeServer(Server* server, bool destroy)
604 throw(anna::RuntimeException) {
605   if(server == NULL)
606     return;
607
608   LOGDEBUG(
609     string msg("diameter::comm::Engine::closeServer | ");
610     msg += server->asString();
611     msg += " | Destroy: ";
612     msg += (destroy ? "yes" : "no");
613     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
614   );
615   anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
616   server_iterator ii = server_find(server->a_socket);
617
618   if(ii == server_end())
619     return;
620
621   try {
622     server->close(destroy);
623
624     if(!destroy) return;
625
626     releaseServer(server);
627   } catch(anna::RuntimeException& ex) {
628     ex.trace();
629   }
630
631   a_servers.erase(ii);
632 }
633
634
635 void Engine::closeEntity(Entity* entity, bool destroy)
636 throw(anna::RuntimeException) {
637   if(entity == NULL)
638     return;
639
640   LOGDEBUG(
641     string msg("diameter::comm::Engine::closeEntity | ");
642     msg += entity->asString();
643     msg += " | Destroy: ";
644     msg += (destroy ? "yes" : "no");
645     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
646   );
647   anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
648   entity_iterator ii = entity_find(entity->a_socketListLiteral);
649
650   if(ii == entity_end())
651     return;
652
653   try {
654     entity->close(destroy);
655
656     if(!destroy) return;
657
658     if(!entity->idle()) { entity->setDeprecated(true); return; }
659
660     releaseEntity(entity);
661   } catch(anna::RuntimeException& ex) {
662     ex.trace();
663   }
664
665   a_entities.erase(ii);
666 }
667
668
669
670 void Engine::closeLocalServer(LocalServer* localServer, bool destroy)
671 throw(anna::RuntimeException) {
672   if(localServer == NULL)
673     return;
674
675   LOGDEBUG(
676     string msg("diameter::comm::Engine::closeLocalServer | ");
677     msg += localServer->asString();
678     msg += " | Destroy: ";
679     msg += (destroy ? "yes" : "no");
680     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
681   );
682   anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
683   localServer_iterator ii = localServer_find(localServer->getKey());
684
685   if(ii == localServer_end())
686     return;
687
688   try {
689     localServer->close();
690
691     if(!destroy) return;
692
693     releaseLocalServer(localServer);
694   } catch(anna::RuntimeException& ex) {
695     ex.trace();
696   }
697
698   a_localServers.erase(ii);
699 }
700
701
702
703 void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
704   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
705   anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
706
707   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
708     closeEntity(entity(it), destroy);
709 }
710
711 void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
712   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
713   anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
714
715   for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
716     closeLocalServer(localServer(it), destroy);
717 }
718
719 void Engine::eraseDeprecatedIdleEntities() throw() {
720   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
721   Entity *et;
722
723   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
724     et = entity(it);
725
726     if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
727   }
728 }
729
730 int Engine::getOTARequestsForEntities() const throw() {
731   int result = 0;
732
733   for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
734     result += entity(it)->getOTARequests();
735
736   return result;
737 }
738
739 int Engine::getOTARequestsForLocalServers() const throw() {
740   int result = 0;
741
742   for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
743     result += localServer(it)->getOTARequests();
744
745   return result;
746 }
747
748
749 void Engine::setRealm(const std::string & name) throw() {
750   a_realm = ((name != "") ? name : anna::functions::getDomainname());
751 }
752
753
754 void Engine::setHost(const std::string & name) throw() {
755   a_host = ((name != "") ? name : anna::functions::getHostname());
756 }
757
758
759
760 void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
761   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
762
763   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
764     entity(it)->raiseAutoRecovery(autoRecovery);
765 }
766
767 void Engine::do_stop()
768 throw() {
769   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
770   close(true /* destroy */);
771 }
772
773 std::string Engine::asString(void) const throw() {
774   std::string trace;
775   trace =  "\n================================";
776   trace += "\nDiameter comm Engine information";
777   trace += "\n================================";
778   trace += "\nAutoBind: ";
779   trace += a_autoBind ? "yes" : "no";
780   trace += "\nMaxConnectionDelay: ";
781   trace += a_maxConnectionDelay.asString();
782   trace += "\nAvailable for entities: ";
783   trace += a_availableForEntities ? "yes" : "no";
784   trace += "\nAvailable for local servers: ";
785   trace += a_availableForLocalServers ? "yes" : "no";
786   trace += "\nOTA requests: ";
787   trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
788   trace += "\nOTA requests for entities: ";
789   trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
790   trace += "\nOTA requests for local servers: ";
791   trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
792   // Entities
793   trace += "\nNumber of entities: ";
794   trace += anna::functions::asString(a_entities.size());
795
796   for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
797     trace += "\n";
798     trace += entity(it)->asString();
799   }
800
801   // Server sockets
802   trace += "\nNumber of LocalServers: ";
803   trace += anna::functions::asString(a_localServers.size());
804
805   for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
806     trace += "\n";
807     trace += localServer(it)->asString();
808   }
809
810   return trace;
811 }
812
813
814 anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const
815 throw() {
816   parent = anna::app::Component::asXML(parent);
817   anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
818   result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
819   result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
820   result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
821   result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
822   result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
823   result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
824   result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
825   result->createAttribute("NumberOfEntities", a_entities.size());
826   anna::xml::Node* entities = result->createChild("Engine.Entities");
827
828   for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
829     entity(it)->asXML(entities);
830
831   result->createAttribute("NumberOfLocalServers", a_localServers.size());
832   anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
833
834   for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
835     localServer(it)->asXML(localServers);
836
837   return result;
838 }
839
840 Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() {
841   return a_clientSessions.find(key);
842 }
843
844 Engine::server_iterator Engine::server_find(const server_key &key) throw() {
845   return a_servers.find(key);
846 }
847
848 Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() {
849   return a_entities.find(key);
850 }
851
852 Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() {
853   return a_localServers.find(key);
854 }
855
856 Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
857   socket_v dualList;
858   dualList.push_back(socket_t(addr1, port1));
859   dualList.push_back(socket_t(addr2, port2));
860   return (getEntityKey(dualList));
861 }
862
863 Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
864   std::string result;
865   socket_v::const_iterator it;
866   socket_v::const_iterator it_min(v.begin());
867   socket_v::const_iterator it_max(v.end());
868
869   for(it = it_min; it != it_max; it++) {
870     result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
871     result += " ";
872   }
873
874   result.erase(result.size() - 1, 1);  // remove last space
875   //return anna::functions::exclusiveHash(result);
876   return result;
877 }
878
879
880 void Engine::availabilityLostForEntities() throw() {
881   a_availableForEntities = false;
882   LOGDEBUG(
883     std::string msg = "diameter::comm::Engine { Realm: ";
884     msg += getRealm();
885     msg += " } has lost its availability for entities";
886     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
887   );
888   // OAM
889   OamModule &oamModule = OamModule::instantiate();
890   oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
891   oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities);
892   // Virtual
893   availabilityLostForEntities(this);
894 }
895
896
897 void Engine::availabilityRecoveredForEntities() throw() {
898   a_availableForEntities = true;
899   LOGDEBUG(
900     std::string msg = "diameter::comm::Engine { Realm: ";
901     msg += getRealm();
902     msg += " } has recovered its availability for entities";
903     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
904   );
905   // OAM
906   OamModule &oamModule = OamModule::instantiate();
907   oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
908   oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
909   // Virtual
910   availabilityRecoveredForEntities(this);
911 }
912
913
914 void Engine::availabilityLostForLocalServers() throw() {
915   a_availableForLocalServers = false;
916   LOGDEBUG(
917     std::string msg = "diameter::comm::Engine { Realm: ";
918     msg += getRealm();
919     msg += " } has lost its availability for local servers";
920     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
921   );
922   // OAM
923   OamModule &oamModule = OamModule::instantiate();
924   oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
925   oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
926   // Virtual
927   availabilityLostForLocalServers(this);
928 }
929
930
931 void Engine::availabilityRecoveredForLocalServers() throw() {
932   a_availableForLocalServers = true;
933   LOGDEBUG(
934     std::string msg = "diameter::comm::Engine { Realm: ";
935     msg += getRealm();
936     msg += " } has recovered its availability for local servers";
937     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
938   );
939   // OAM
940   OamModule &oamModule = OamModule::instantiate();
941   oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
942   oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
943   // Virtual
944   availabilityRecoveredForLocalServers(this);
945 }
946
947
948 bool Engine::refreshAvailabilityForEntities() throw() {
949   // Here available
950   if(a_availableForEntities) {  // check not-bound state for all client-sessions:
951     bool isolate = true;
952
953     for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
954       if(entity(it)->isAvailable()) { isolate = false; break; }
955
956     if(isolate) {
957       availabilityLostForEntities();
958       return true;
959     }
960
961     return false;
962   }
963
964   // Here not available
965   for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
966     if(entity(it)->isAvailable()) {
967       availabilityRecoveredForEntities();
968       return true;
969     }
970
971   return false;
972 }
973
974 bool Engine::refreshAvailabilityForLocalServers() throw() {
975   // Here available
976   if(a_availableForLocalServers) {  // check not-bound state for all client-sessions:
977     bool isolate = true;
978
979     for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
980       if(localServer(it)->isAvailable()) { isolate = false; break; }
981
982     if(isolate) {
983       availabilityLostForLocalServers();
984       return true;
985     }
986
987     return false;
988   }
989
990   // Here not available
991   for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
992     if(localServer(it)->isAvailable()) {
993       availabilityRecoveredForLocalServers();
994       return true;
995     }
996
997   return false;
998 }
999
1000
1001 void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
1002   // Default DPA implementation:
1003   //
1004   //   'Disconnect-Peer-Answer' (282,answer)
1005   //        {Result-Code}...................................(268,0)
1006   //        {Origin-Host}...................................(264,0)
1007   //        {Origin-Realm}..................................(296,0)
1008   //        [Error-Message].................................(281,0)
1009   //       *[Failed-AVP]....................................(279,0)
1010   try {
1011     anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine());
1012     anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1013     anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1014     anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1015     // Message header
1016     diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
1017     diameterDPA.setVersion(1);
1018     diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
1019     diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
1020     diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
1021     // Result-Code
1022     avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1023     avpRC.setMandatoryBit();
1024     avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1025     // Origin-Host
1026     avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1027     avpOH.setMandatoryBit();
1028     avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1029     // Origin-Realm
1030     avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1031     avpOR.setMandatoryBit();
1032     avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1033     diameterDPA.addAvp(&avpRC);
1034     diameterDPA.addAvp(&avpOH);
1035     diameterDPA.addAvp(&avpOR);
1036     // Encode
1037     dpa = diameterDPA.code();
1038   } catch(anna::RuntimeException &ex) {
1039     std::string msg = ex.getText();
1040     msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)";
1041     anna::Logger::error(msg, ANNA_FILE_LOCATION);
1042     //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1043   }
1044 }
1045
1046
1047 void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
1048   // Default CEA implementation:
1049   //
1050   //   'Capabilities-Exchange-Answer' (257,answer)
1051   //        {Result-Code}...................................(268,0)
1052   //        {Origin-Host}...................................(264,0)
1053   //        {Origin-Realm}..................................(296,0)
1054   //      1*{Host-IP-Address}...............................(257,0)
1055   //        {Vendor-Id}.....................................(266,0)
1056   //        {Product-Name}..................................(269,0)
1057   //        [Origin-State-Id]...............................(278,0)
1058   //        [Error-Message].................................(281,0)
1059   //       *[Failed-AVP]....................................(279,0)
1060   //       *[Supported-Vendor-Id]...........................(265,0)
1061   //       *[Auth-Application-Id]...........................(258,0)
1062   //       *[Inband-Security-Id]............................(299,0)
1063   //       *[Acct-Application-Id]...........................(259,0)
1064   //        [Vendor-Specific-Application-Id]................(260,0)
1065   //        [Firmware-Revision].............................(267,0)
1066   //       *[AVP]...........................................(0,0)
1067   try {
1068     anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
1069     anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1070     anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1071     anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1072     // Message header
1073     diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1074     diameterCEA.setVersion(1);
1075     diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1076     diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1077     diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1078     // Result-Code
1079     avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1080     avpRC.setMandatoryBit();
1081     avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1082     // Origin-Host
1083     avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1084     avpOH.setMandatoryBit();
1085     avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1086     // Origin-Realm
1087     avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1088     avpOR.setMandatoryBit();
1089     avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1090     diameterCEA.addAvp(&avpRC);
1091     diameterCEA.addAvp(&avpOH);
1092     diameterCEA.addAvp(&avpOR);
1093     // Host-IP-Address
1094     std::string hostIP = anna::functions::getHostnameIP(); // Address
1095     diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1096     // Vendor-Id
1097     int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1098     diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1099     // Product-Name
1100     std::string productName = "OCS Diameter Server"; // UTF8String
1101     diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1102     // Encode
1103     cea = diameterCEA.code();
1104   } catch(anna::RuntimeException &ex) {
1105     std::string msg = ex.getText();
1106     msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)";
1107     anna::Logger::error(msg, ANNA_FILE_LOCATION);
1108     //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1109   }
1110 }
1111
1112
1113 void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
1114   // Default DWA implementation:
1115   //
1116   //   'Device-Watchdog-Answer' (280,answer)
1117   //        {Result-Code}...................................(268,0)
1118   //        {Origin-Host}...................................(264,0)
1119   //        {Origin-Realm}..................................(296,0)
1120   //        [Error-Message].................................(281,0)
1121   //       *[Failed-AVP]....................................(279,0)
1122   //        [Origin-State-Id]...............................(278,0)
1123   try {
1124     anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine());
1125     anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1126     anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1127     anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1128     // Message header
1129     diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1130     diameterDWA.setVersion(1);
1131     diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr));
1132     diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr));
1133     diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr));
1134     // Result-Code
1135     avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1136     avpRC.setMandatoryBit();
1137     avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1138     // Origin-Host
1139     avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1140     avpOH.setMandatoryBit();
1141     avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1142     // Origin-Realm
1143     avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1144     avpOR.setMandatoryBit();
1145     avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1146     diameterDWA.addAvp(&avpRC);
1147     diameterDWA.addAvp(&avpOH);
1148     diameterDWA.addAvp(&avpOR);
1149     // Encode
1150     dwa = diameterDWA.code();
1151   } catch(anna::RuntimeException &ex) {
1152     std::string msg = ex.getText();
1153     msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)";
1154     anna::Logger::error(msg, ANNA_FILE_LOCATION);
1155     //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1156   }
1157 }
1158
1159 void Engine::resetStatistics() throw() {
1160   for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1161     server(it)->resetStatistics();
1162
1163   for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1164     localServer(it)->resetStatistics();
1165 }
1166
1167 void Engine::do_initialize() throw(RuntimeException) {
1168   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
1169   LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
1170 }
1171
1172 void Engine::lazyInitialize() throw(RuntimeException) {
1173   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
1174   anna::app::Component::initialize(); // this will invoke do_initialize
1175 }