Add nlohmann/json parser
[anna.git] / source / diameter.comm / Engine.cpp
index 3a7f843..867b6cc 100644 (file)
@@ -5,16 +5,17 @@
 // 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 <stdlib.h> // rand()
 
-#include <anna/diameter.comm/Engine.hpp>
 
+#include <anna/diameter.comm/Engine.hpp>
 #include <anna/core/tracing/Logger.hpp>
 #include <anna/core/tracing/TraceMethod.hpp>
 #include <anna/xml/Node.hpp>
 #include <anna/comm/Network.hpp>
 #include <anna/comm/Host.hpp>
 #include <anna/comm/ClientSocket.hpp>
-
 #include <anna/diameter.comm/Transport.hpp>
 #include <anna/diameter.comm/Engine.hpp>
 #include <anna/diameter.comm/Entity.hpp>
 #include <anna/diameter/helpers/helpers.hpp>
 #include <anna/diameter/codec/Message.hpp>
 #include <anna/diameter/codec/Avp.hpp>
+#include <anna/diameter.comm/Response.hpp>
 
 // STD
 #include <map>
 
 using namespace std;
-using namespace anna::diameter::comm;
+using namespace anna::diameter;
+
 
+namespace anna {
+  namespace diameter {
+    namespace stack {
+      class Dictionary;
+    }
+  }
+}
 
-Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
+comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtocolDictionary) :
   anna::app::Component(className),
-  a_baseProtocolCodecEngine(baseProtocolCodecEngine),
   a_autoBind(true),
   a_availableForEntities(false),
   a_availableForLocalServers(false),
@@ -49,19 +58,34 @@ Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
 //      a_dwa(true),
   a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
   a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
-  a_numberOfClientSessionsPerServer(1) {
+  a_numberOfClientSessionsPerServer(1),
+  a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str(), baseProtocolDictionary)
+{
   anna::diameter::sccs::activate();
-  a_realm = anna::functions::getDomainname();
-  a_host = anna::functions::getHostname();
+  a_originRealm = anna::functions::getDomainname();
+  a_originHost = anna::functions::getHostname();
+  a_ceaPathfile = "";
+
+  // Internal base protocol codec engine:
+  a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding
 }
 
-Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); }
-void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
-ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
-void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
+
+void comm::Engine::assertBaseProtocolHealth() throw(anna::RuntimeException) {
+  if (!getBaseProtocolCodecEngine()->getDictionary())
+    throw anna::RuntimeException("Invalid diameter::comm::Engine object: base protocol dictionary provided on constructor was NULL", ANNA_FILE_LOCATION);
+  // it would be interesting to check and identify certain base protocol elements in the dictionary ...
+  //  but these things will be checked in runtime and will fail if they should.
+}
+
+
+comm::Server* comm::Engine::allocateServer() throw() { return a_serversRecycler.create(); }
+void comm::Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
+comm::ClientSession* comm::Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
+void comm::Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
 
 
-void Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
+void comm::Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
   if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
     throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
   }
@@ -74,11 +98,10 @@ void Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlo
   a_dwr = dwr;
 }
 
-void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
+void comm::Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
 
-  // Check for base protocol codec engine:
-  if (!getBaseProtocolCodecEngine())
-    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);
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
 
   // Build CER
   //   <CER> ::= < Diameter Header: 257, REQ >
@@ -93,8 +116,8 @@ void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr
   //           * [Acct-Application-Id]  259 Unsigned32
   anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
   int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32
-  std::string OH = getHost();
-  std::string OR = getRealm();
+  std::string OH = getOriginHostName();
+  std::string OR = getOriginRealmName();
   std::string hostIP = anna::functions::getHostnameIP(); // Address
   int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
   std::string productName = "ANNA Diameter Client"; // UTF8String
@@ -102,7 +125,7 @@ void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr
 
   if (cer != "") {
     try {
-      diameterCER.loadXML(cer);
+      diameterCER.loadXMLFile(cer);
     } catch(anna::RuntimeException &ex) {
       //ex.trace();
       encodeDefault = true;
@@ -133,7 +156,7 @@ void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr
 
   if (dwr != "") {
     try {
-      diameterDWR.loadXML(dwr);
+      diameterDWR.loadXMLFile(dwr);
     } catch(anna::RuntimeException &ex) {
       //ex.trace();
       encodeDefault = true;
@@ -155,7 +178,7 @@ void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr
   setClientCERandDWR(diameterCER.code(), diameterDWR.code());
 }
 
-void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
+void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
   if(wp < ClientSession::DefaultWatchdogPeriod) {
     throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
   }
@@ -163,7 +186,7 @@ void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::Runtime
   a_watchdogPeriod = wp;
 }
 
-void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
+void comm::Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
   socket_v::const_iterator it;
   socket_v::const_iterator it_min(v.begin());
   socket_v::const_iterator it_max(v.end());
@@ -184,7 +207,7 @@ void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeExceptio
     throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
 }
 
-Entity* Engine::createEntity(const socket_v & socketList, const std::string &description)
+comm::Entity* comm::Engine::createEntity(const socket_v & socketList, const std::string &description)
 throw(anna::RuntimeException) {
   Entity* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
@@ -233,7 +256,7 @@ throw(anna::RuntimeException) {
 }
 
 
-LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
+comm::LocalServer *comm::Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
 throw(anna::RuntimeException) {
   LocalServer* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
@@ -251,7 +274,7 @@ throw(anna::RuntimeException) {
   result->setCategory(category);
   result->setDescription(description);
   result->setAllowedInactivityTime(allowedInactivityTime);
-  result->initializeStatisticConcepts();
+  result->initializeStatisticResources();
 // Los saco con metodos virtuales readXXX del motor:
 //   if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
 //      throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
@@ -268,7 +291,7 @@ throw(anna::RuntimeException) {
 }
 
 
-Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
+comm::Entity* comm::Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
 throw(anna::RuntimeException) {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
@@ -277,7 +300,7 @@ throw(anna::RuntimeException) {
 }
 
 
-Server* Engine::createServer(Entity *entity, const socket_t & socket)
+comm::Server* comm::Engine::createServer(Entity *entity, const socket_t & socket)
 throw(anna::RuntimeException) {
   Server* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
@@ -292,7 +315,7 @@ throw(anna::RuntimeException) {
   result->a_socket = socket;
   result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
   result->a_engine = this;
-  result->initializeStatisticConcepts();
+  result->initializeStatisticResources();
 
   for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
     result->addClientSession(k);
@@ -309,7 +332,7 @@ throw(anna::RuntimeException) {
 
 
 // Lohacemos privado
-ClientSession* Engine::createClientSession(Server *server, int socketId)
+comm::ClientSession* comm::Engine::createClientSession(Server *server, int socketId)
 throw(anna::RuntimeException) {
   ClientSession* result(NULL);
   anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
@@ -322,15 +345,14 @@ throw(anna::RuntimeException) {
   // Assignments (it could be done at allocate):
 
   if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
-    throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
+    throw anna::RuntimeException("Must define valid CER and DWR messages by mean setClientCERandDWR()", ANNA_FILE_LOCATION);
 
   result->a_cer.setBody(a_cer);
   result->a_dwr.setBody(a_dwr);
   result->setWatchdogPeriod(a_watchdogPeriod);
   result->a_parent = server;
   result->a_socketId = socketId;
-  result->initializeSequences(); // despu�s de asignar el server y el socketId (*)
-  // (*) 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)));
+  result->initializeSequences(); // despues de asignar el server y el socketId (sequences are seed-based by mean exclusive hash)
   result->a_engine = this;
   clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
   a_clientSessions.insert(clientSession_value_type(key, result));
@@ -355,7 +377,7 @@ throw(anna::RuntimeException) {
 }
 
 
-bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
+bool comm::Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
   bool allok = true;
   bool ok;
@@ -374,7 +396,7 @@ bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeExcept
   return allok;
 }
 
-bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
+bool comm::Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
   bool allok = true;
   bool ok;
@@ -393,7 +415,7 @@ bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeEx
   return allok;
 }
 
-bool Engine::bind() throw(anna::RuntimeException) {
+bool comm::Engine::bind() throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
   bool result = true; // all OK return
 
@@ -409,12 +431,12 @@ bool Engine::bind() throw(anna::RuntimeException) {
   return result;
 }
 
-ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
+comm::ClientSession* comm::Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
 }
 
-ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
+comm::ClientSession* comm::Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
   clientSession_iterator ii = clientSession_find(key);
@@ -438,7 +460,7 @@ throw(anna::RuntimeException) {
 }
 
 
-Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
+comm::Server* comm::Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
   server_iterator ii = server_find(server_key(addr, port));
@@ -462,7 +484,7 @@ throw(anna::RuntimeException) {
   return NULL;
 }
 
-Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
+comm::Entity* comm::Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
   entity_key key(getEntityKey(socketList));
@@ -486,7 +508,7 @@ throw(anna::RuntimeException) {
   return NULL;
 }
 
-Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
+comm::Entity* comm::Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
@@ -509,7 +531,7 @@ throw(anna::RuntimeException) {
 //}
 
 
-LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
+comm::LocalServer* comm::Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
 throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
   socket_t key(addr, port);
@@ -535,7 +557,7 @@ throw(anna::RuntimeException) {
 }
 
 
-ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
+comm::ServerSession* comm::Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
   anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
   ServerSession *result;
 
@@ -562,7 +584,7 @@ ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v
 }
 
 
-void Engine::closeClientSession(ClientSession* clientSession, bool destroy)
+void comm::Engine::closeClientSession(comm::ClientSession* clientSession, bool destroy)
 throw(anna::RuntimeException) {
   if(clientSession == NULL)
     return;
@@ -600,7 +622,7 @@ throw(anna::RuntimeException) {
 
 
 
-void Engine::closeServer(Server* server, bool destroy)
+void comm::Engine::closeServer(comm::Server* server, bool destroy)
 throw(anna::RuntimeException) {
   if(server == NULL)
     return;
@@ -632,7 +654,7 @@ throw(anna::RuntimeException) {
 }
 
 
-void Engine::closeEntity(Entity* entity, bool destroy)
+void comm::Engine::closeEntity(comm::Entity* entity, bool destroy)
 throw(anna::RuntimeException) {
   if(entity == NULL)
     return;
@@ -667,7 +689,7 @@ throw(anna::RuntimeException) {
 
 
 
-void Engine::closeLocalServer(LocalServer* localServer, bool destroy)
+void comm::Engine::closeLocalServer(comm::LocalServer* localServer, bool destroy)
 throw(anna::RuntimeException) {
   if(localServer == NULL)
     return;
@@ -700,7 +722,7 @@ throw(anna::RuntimeException) {
 
 
 
-void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
+void comm::Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
   anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
 
@@ -708,7 +730,7 @@ void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
     closeEntity(entity(it), destroy);
 }
 
-void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
+void comm::Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
   anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
 
@@ -716,7 +738,7 @@ void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
     closeLocalServer(localServer(it), destroy);
 }
 
-void Engine::eraseDeprecatedIdleEntities() throw() {
+void comm::Engine::eraseDeprecatedIdleEntities() throw() {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
   Entity *et;
 
@@ -727,7 +749,7 @@ void Engine::eraseDeprecatedIdleEntities() throw() {
   }
 }
 
-int Engine::getOTARequestsForEntities() const throw() {
+int comm::Engine::getOTARequestsForEntities() const throw() {
   int result = 0;
 
   for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
@@ -736,7 +758,7 @@ int Engine::getOTARequestsForEntities() const throw() {
   return result;
 }
 
-int Engine::getOTARequestsForLocalServers() const throw() {
+int comm::Engine::getOTARequestsForLocalServers() const throw() {
   int result = 0;
 
   for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
@@ -746,31 +768,31 @@ int Engine::getOTARequestsForLocalServers() const throw() {
 }
 
 
-void Engine::setRealm(const std::string & name) throw() {
-  a_realm = ((name != "") ? name : anna::functions::getDomainname());
+void comm::Engine::setOriginRealmName(const std::string & originRealmName) throw() {
+  a_originRealm = ((originRealmName != "") ? originRealmName : anna::functions::getDomainname());
 }
 
 
-void Engine::setHost(const std::string & name) throw() {
-  a_host = ((name != "") ? name : anna::functions::getHostname());
+void comm::Engine::setOriginHostName(const std::string & originHostName) throw() {
+  a_originHost = ((originHostName != "") ? originHostName : anna::functions::getHostname());
 }
 
 
 
-void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
+void comm::Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
 
   for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
     entity(it)->raiseAutoRecovery(autoRecovery);
 }
 
-void Engine::do_stop()
+void comm::Engine::do_stop()
 throw() {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
   close(true /* destroy */);
 }
 
-std::string Engine::asString(void) const throw() {
+std::string comm::Engine::asString(void) const throw() {
   std::string trace;
   trace =  "\n================================";
   trace += "\nDiameter comm Engine information";
@@ -811,7 +833,7 @@ std::string Engine::asString(void) const throw() {
 }
 
 
-anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const
+anna::xml::Node* comm::Engine::asXML(anna::xml::Node* parent) const
 throw() {
   parent = anna::app::Component::asXML(parent);
   anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
@@ -834,33 +856,57 @@ throw() {
   for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
     localServer(it)->asXML(localServers);
 
+  // DRA Basics
+  // Aspect:
+  //  <Engine.RemoteRealm Name="afNodeHostRealm.com">
+  //     <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:4"/>
+  //  </Engine.RemoteRealm>
+  //  <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
+  //     <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:6"/>
+  //  </Engine.RemoteRealm>
+  for (dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.begin(); drit != a_dr_dh_server_sessions.end(); drit++) {
+    anna::xml::Node* remoteRealm = result->createChild("Engine.RemoteRealm");
+    remoteRealm->createAttribute("Name", drit->first);
+    dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
+    for (dh_server_sessions_it_t dhit = dhServerSessions->begin(); dhit != dhServerSessions->end(); dhit++) {
+      anna::xml::Node* remoteRealmHost = remoteRealm->createChild("Engine.RemoteRealmHost");
+      remoteRealmHost->createAttribute("Name", dhit->first);
+      server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
+      for (server_sessions_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
+        std::string socket = anna::functions::socketLiteralAsString((*ssit)->getAddress(), (*ssit)->getPort());
+        std::string ss_desc = socket + anna::functions::asString("|ServerSessionId:%d", (*ssit)->getSocketId());
+        remoteRealmHost->createAttribute("ServerSession", ss_desc);
+      }
+    }
+  }
+
   return result;
 }
 
-Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() {
+comm::Engine::clientSession_iterator comm::Engine::clientSession_find(const clientSession_key &key) throw() {
   return a_clientSessions.find(key);
 }
 
-Engine::server_iterator Engine::server_find(const server_key &key) throw() {
+comm::Engine::server_iterator comm::Engine::server_find(const server_key &key) throw() {
   return a_servers.find(key);
 }
 
-Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() {
+comm::Engine::entity_iterator comm::Engine::entity_find(const entity_key &key) throw() {
   return a_entities.find(key);
 }
 
-Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() {
+comm::Engine::localServer_iterator comm::Engine::localServer_find(const socket_t &key) throw() {
   return a_localServers.find(key);
 }
 
-Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
+comm::Engine::entity_key comm::Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
   socket_v dualList;
   dualList.push_back(socket_t(addr1, port1));
   dualList.push_back(socket_t(addr2, port2));
   return (getEntityKey(dualList));
 }
 
-Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
+comm::Engine::entity_key comm::Engine::getEntityKey(const socket_v &v) const throw() {
   std::string result;
   socket_v::const_iterator it;
   socket_v::const_iterator it_min(v.begin());
@@ -872,16 +918,17 @@ Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
   }
 
   result.erase(result.size() - 1, 1);  // remove last space
-  //return anna::functions::exclusiveHash(result);
   return result;
 }
 
 
-void Engine::availabilityLostForEntities() throw() {
+void comm::Engine::availabilityLostForEntities() throw() {
   a_availableForEntities = false;
   LOGDEBUG(
-    std::string msg = "diameter::comm::Engine { Realm: ";
-    msg += getRealm();
+    std::string msg = "diameter::comm::Engine { Origin-Realm: ";
+    msg += getOriginRealmName();
+    msg += " | Origin-Host: ";
+    msg += getOriginHostName();
     msg += " } has lost its availability for entities";
     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
@@ -894,11 +941,13 @@ void Engine::availabilityLostForEntities() throw() {
 }
 
 
-void Engine::availabilityRecoveredForEntities() throw() {
+void comm::Engine::availabilityRecoveredForEntities() throw() {
   a_availableForEntities = true;
   LOGDEBUG(
-    std::string msg = "diameter::comm::Engine { Realm: ";
-    msg += getRealm();
+    std::string msg = "diameter::comm::Engine { Origin-Realm: ";
+    msg += getOriginRealmName();
+    msg += " | Origin-Host: ";
+    msg += getOriginHostName();
     msg += " } has recovered its availability for entities";
     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
@@ -911,11 +960,13 @@ void Engine::availabilityRecoveredForEntities() throw() {
 }
 
 
-void Engine::availabilityLostForLocalServers() throw() {
+void comm::Engine::availabilityLostForLocalServers() throw() {
   a_availableForLocalServers = false;
   LOGDEBUG(
-    std::string msg = "diameter::comm::Engine { Realm: ";
-    msg += getRealm();
+    std::string msg = "diameter::comm::Engine { Origin-Realm: ";
+    msg += getOriginRealmName();
+    msg += " | Origin-Host: ";
+    msg += getOriginHostName();
     msg += " } has lost its availability for local servers";
     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
@@ -928,11 +979,13 @@ void Engine::availabilityLostForLocalServers() throw() {
 }
 
 
-void Engine::availabilityRecoveredForLocalServers() throw() {
+void comm::Engine::availabilityRecoveredForLocalServers() throw() {
   a_availableForLocalServers = true;
   LOGDEBUG(
-    std::string msg = "diameter::comm::Engine { Realm: ";
-    msg += getRealm();
+    std::string msg = "diameter::comm::Engine { Origin-Realm: ";
+    msg += getOriginRealmName();
+    msg += " | Origin-Host: ";
+    msg += getOriginHostName();
     msg += " } has recovered its availability for local servers";
     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
   );
@@ -945,7 +998,7 @@ void Engine::availabilityRecoveredForLocalServers() throw() {
 }
 
 
-bool Engine::refreshAvailabilityForEntities() throw() {
+bool comm::Engine::refreshAvailabilityForEntities() throw() {
   // Here available
   if(a_availableForEntities) {  // check not-bound state for all client-sessions:
     bool isolate = true;
@@ -971,7 +1024,7 @@ bool Engine::refreshAvailabilityForEntities() throw() {
   return false;
 }
 
-bool Engine::refreshAvailabilityForLocalServers() throw() {
+bool comm::Engine::refreshAvailabilityForLocalServers() throw() {
   // Here available
   if(a_availableForLocalServers) {  // check not-bound state for all client-sessions:
     bool isolate = true;
@@ -998,7 +1051,17 @@ bool Engine::refreshAvailabilityForLocalServers() throw() {
 }
 
 
-void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
+void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
+
+  // Check for base protocol codec engine health:
+  try {
+    assertBaseProtocolHealth();
+  }
+  catch(anna::RuntimeException &ex) {
+    ex.trace();
+    return;
+  }
+
   // Default DPA implementation:
   //
   //   'Disconnect-Peer-Answer' (282,answer)
@@ -1025,11 +1088,11 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw()
     // Origin-Host
     avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
     avpOH.setMandatoryBit();
-    avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
+    avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
     // Origin-Realm
     avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
     avpOR.setMandatoryBit();
-    avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
+    avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
     diameterDPA.addAvp(&avpRC);
     diameterDPA.addAvp(&avpOH);
     diameterDPA.addAvp(&avpOR);
@@ -1044,7 +1107,30 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw()
 }
 
 
-void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
+void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock &cer) throw() {
+
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
+
+  if (a_ceaPathfile != "") {
+    anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
+
+    try {
+      diameterCEA.loadXMLFile(a_ceaPathfile);
+      diameterCEA.setHopByHop(anna::diameter::codec::functions::getHopByHop(cer));
+      diameterCEA.setEndToEnd(anna::diameter::codec::functions::getEndToEnd(cer));
+      cea = diameterCEA.code();
+
+    } catch(anna::RuntimeException &ex) {
+      ex.trace();
+      LOGWARNING(anna::Logger::warning("CEA file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
+      //return anna::diameter::comm::Engine::readCEA(cea, cer);
+      // will fail with empty cea
+      }
+
+    return;
+  }
+
   // Default CEA implementation:
   //
   //   'Capabilities-Exchange-Answer' (257,answer)
@@ -1082,11 +1168,11 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw()
     // Origin-Host
     avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
     avpOH.setMandatoryBit();
-    avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
+    avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
     // Origin-Realm
     avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
     avpOR.setMandatoryBit();
-    avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
+    avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
     diameterCEA.addAvp(&avpRC);
     diameterCEA.addAvp(&avpOH);
     diameterCEA.addAvp(&avpOR);
@@ -1097,7 +1183,7 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw()
     int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
     diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
     // Product-Name
-    std::string productName = "OCS Diameter Server"; // UTF8String
+    std::string productName = "Diameter Server"; // UTF8String
     diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
     // Encode
     cea = diameterCEA.code();
@@ -1109,8 +1195,71 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw()
   }
 }
 
+void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw() {
+
+  // Decode CER (TODO: use raw buffer helpers)
+  std::string destinationRealm, destinationHost;
+  codec::Message codecMsg(getBaseProtocolCodecEngine());
+  try {
+    codecMsg.decode(ss->a_cer);
+    destinationRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
+    destinationHost = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->getValue();
+  }
+  catch(anna::RuntimeException &ex) {
+    ex.trace();
+    return;
+  }
+
+  dr_dh_server_sessions_nc_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
+  if (drit != a_dr_dh_server_sessions.end()) { // found
+    dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
+    dh_server_sessions_nc_it_t dhit = dhServerSessions->find(destinationHost);
+    if (dhit != dhServerSessions->end()) { // found
+      server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
+      if (register_or_desregister) { // REGISTER
+        serverSessions->push_back(ss);
+      }
+      else { // DESREGISTER
+        // Sequential search the specific server session:
+        for (server_sessions_nc_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
+          if ((*ssit)->getAddress() != ss->getAddress()) continue;
+          if ((*ssit)->getPort() != ss->getPort()) continue;
+          if ((*ssit)->getSocketId() != ss->getSocketId()) continue;
+          serverSessions->erase(ssit);  // if it is the last server session removed in DR-DH path, the XML will show this tree empty
+                                        // (it could be a hint for past registerings):
+                                        //          <Engine.RemoteRealm Name="afNodeHostRealm.com">
+                                        //             <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com"/>
+                                        //          </Engine.RemoteRealm>
+                                        //          <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
+                                        //             <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com"/>
+                                        //          </Engine.RemoteRealm>
+
+          break;
+        }
+      }
+    }
+    else {
+      if (!register_or_desregister) return; // strange (host not found)
+      server_sessions_vector_t ssVector;
+      ssVector.push_back(ss);
+      (*dhServerSessions)[destinationHost] = ssVector;
+    }
+  }
+  else {
+    if (!register_or_desregister) return; // strange (realm not found)
+    server_sessions_vector_t ssVector;
+    ssVector.push_back(ss);
+    dh_server_sessions_map_t dhServerSessions;
+    dhServerSessions[destinationHost] = ssVector;
+    a_dr_dh_server_sessions[destinationRealm] = dhServerSessions;
+  }
+}
+
+void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
+
+  // Check for base protocol codec engine health:
+  assertBaseProtocolHealth();
 
-void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
   // Default DWA implementation:
   //
   //   'Device-Watchdog-Answer' (280,answer)
@@ -1138,11 +1287,11 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw()
     // Origin-Host
     avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
     avpOH.setMandatoryBit();
-    avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
+    avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
     // Origin-Realm
     avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
     avpOR.setMandatoryBit();
-    avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
+    avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
     diameterDWA.addAvp(&avpRC);
     diameterDWA.addAvp(&avpOH);
     diameterDWA.addAvp(&avpOR);
@@ -1156,7 +1305,7 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw()
   }
 }
 
-void Engine::resetStatistics() throw() {
+void comm::Engine::resetStatistics() throw() {
   for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
     server(it)->resetStatistics();
 
@@ -1164,12 +1313,58 @@ void Engine::resetStatistics() throw() {
     localServer(it)->resetStatistics();
 }
 
-void Engine::do_initialize() throw(RuntimeException) {
+void comm::Engine::do_initialize() throw(RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
   LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
 }
 
-void Engine::lazyInitialize() throw(RuntimeException) {
+void comm::Engine::lazyInitialize() throw(RuntimeException) {
   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
   anna::app::Component::initialize(); // this will invoke do_initialize
 }
+
+// Not tested yet
+const comm::Response* comm::Engine::sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost) throw(anna::RuntimeException) {
+
+  if (destinationRealm == "")
+    throw anna::RuntimeException("Unable to resolve the destination: empty provided Destination-Realm name", ANNA_FILE_LOCATION);
+
+  // Get the server sessions which fulfill the restrictions:
+  dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
+  if (drit == a_dr_dh_server_sessions.end())
+    throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: Destination-Realm name is not registered (no remote clients have been connected to '%s')", destinationRealm.c_str()), ANNA_FILE_LOCATION);
+
+  dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
+  // randomize between all server sessions for all hosts:
+  dh_server_sessions_nc_it_t dhit;
+  int hostsN = dhServerSessions->size();
+  if (hostsN == 0) // avoids next division by cero (rand() % 0)
+    throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: neither Destination-Host currently connected to Destination-Realm '%s'", destinationRealm.c_str()), ANNA_FILE_LOCATION);
+
+  if (destinationHost == "") {
+    // in this case, randomize the host:
+    dhit = dhServerSessions->begin();
+    int randomHostIndx = rand() % hostsN; // number between 0 and the number of hosts - 1
+    std::advance (dhit, randomHostIndx);
+  }
+  else {
+    dhit = dhServerSessions->find(destinationHost);
+    if (dhit == dhServerSessions->end())
+      throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: Destination-Host '%s' is not registered for Destination-Realm '%s'", destinationHost.c_str(), destinationRealm.c_str()), ANNA_FILE_LOCATION);
+  }
+
+  // Now, randomize the available server sessions:
+  server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
+  int serverSessionN = serverSessions->size();
+  if (serverSessionN == 0) { // avoids next division by cero (rand() % 0)
+    std::string aux = "";
+    if (destinationHost != "") { aux = "to Destination-Host '"; aux += destinationHost; aux += "'"; }
+    std::string msg = anna::functions::asString("Unable to resolve the destination: neither server session currently connected%s within Destination-Realm '%s'", aux.c_str(), destinationRealm.c_str());
+    throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+  }
+
+  server_sessions_nc_it_t ssit = serverSessions->begin();
+  int randomServerSessionIndx = rand() % serverSessionN; // number between 0 and the number of server sessions - 1
+  std::advance (ssit, randomServerSessionIndx);
+  return (*ssit)->send(message);
+}