1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
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 //
9 #include <stdlib.h> // rand()
12 #include <anna/diameter.comm/Engine.hpp>
13 #include <anna/core/tracing/Logger.hpp>
14 #include <anna/core/tracing/TraceMethod.hpp>
15 #include <anna/xml/Node.hpp>
16 #include <anna/comm/Network.hpp>
17 #include <anna/comm/Host.hpp>
18 #include <anna/comm/ClientSocket.hpp>
19 #include <anna/diameter.comm/Transport.hpp>
20 #include <anna/diameter.comm/Engine.hpp>
21 #include <anna/diameter.comm/Entity.hpp>
22 #include <anna/diameter.comm/Server.hpp>
23 #include <anna/diameter.comm/ClientSession.hpp>
24 #include <anna/diameter.comm/LocalServer.hpp>
25 #include <anna/core/functions.hpp>
26 #include <anna/diameter/internal/sccs.hpp>
27 #include <anna/diameter.comm/OamModule.hpp>
28 #include <anna/diameter/codec/functions.hpp>
29 #include <anna/diameter/helpers/base/functions.hpp>
30 #include <anna/diameter/helpers/helpers.hpp>
31 #include <anna/diameter/codec/Message.hpp>
32 #include <anna/diameter/codec/Avp.hpp>
33 #include <anna/diameter.comm/Response.hpp>
39 using namespace anna::diameter;
50 comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtocolDictionary) :
51 anna::app::Component(className),
53 a_availableForEntities(false),
54 a_availableForLocalServers(false),
59 a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
60 a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
61 a_numberOfClientSessionsPerServer(1),
62 a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str(), baseProtocolDictionary)
64 anna::diameter::sccs::activate();
65 a_originRealm = anna::functions::getDomainname();
66 a_originHost = anna::functions::getHostname();
69 // Internal base protocol codec engine:
70 a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding
74 void comm::Engine::assertBaseProtocolHealth() const noexcept(false) {
75 if (!getBaseProtocolCodecEngine()->getDictionary())
76 throw anna::RuntimeException("Invalid diameter::comm::Engine object: base protocol dictionary provided on constructor was NULL", ANNA_FILE_LOCATION);
77 // it would be interesting to check and identify certain base protocol elements in the dictionary ...
78 // but these things will be checked in runtime and will fail if they should.
82 comm::Server* comm::Engine::allocateServer() { return a_serversRecycler.create(); }
83 void comm::Engine::releaseServer(Server *server) { a_serversRecycler.release(server); }
84 comm::ClientSession* comm::Engine::allocateClientSession() { return a_clientSessionsRecycler.create(); }
85 void comm::Engine::releaseClientSession(ClientSession *clientSession) { a_clientSessionsRecycler.release(clientSession); }
87 void comm::Engine::setClientCER(const anna::DataBlock & cer) noexcept(false) {
88 if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
89 throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
95 void comm::Engine::setClientDWR(const anna::DataBlock & dwr) noexcept(false) {
96 if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
97 throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
103 void comm::Engine::setClientCER(const std::string & cerPathfile) noexcept(false) {
105 // Check for base protocol codec engine health:
106 assertBaseProtocolHealth();
108 anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
110 diameterCER.loadXMLFile(cerPathfile);
111 } catch(anna::RuntimeException &ex) {
112 anna::Logger::error("CER file not found or unable to parse. Nothing done !", ANNA_FILE_LOCATION);
116 // Assignment for internal encoded version:
117 setClientCER(diameterCER.code());
120 void comm::Engine::setClientDWR(const std::string & dwrPathfile) noexcept(false) {
122 // Check for base protocol codec engine health:
123 assertBaseProtocolHealth();
125 anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine());
126 std::string OH = getOriginHostName();
127 std::string OR = getOriginRealmName();
129 if (!dwrPathfile.empty()) {
131 diameterDWR.loadXMLFile(dwrPathfile);
132 } catch(anna::RuntimeException &ex) {
133 anna::Logger::error("DWR file not found or unable to parse. Nothing done !", ANNA_FILE_LOCATION);
140 // <DWR> ::= < Diameter Header: 280, REQ >
143 diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request);
144 diameterDWR.setApplicationId(0); // base protocol
145 diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
146 diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
148 // Assignment for internal encoded version:
149 setClientDWR(diameterDWR.code());
152 void comm::Engine::setClientCER(const anna::U32 &applicationId) noexcept(false) {
154 // Check for base protocol codec engine health:
155 assertBaseProtocolHealth();
158 // <CER> ::= < Diameter Header: 257, REQ >
159 // { Origin-Host } 264 diameterIdentity
160 // { Origin-Realm } 296 idem
161 // 1* { Host-IP-Address } 257, address
162 // { Vendor-Id } 266 Unsigned32
163 // { Product-Name } 269 UTF8String
164 // [Origin-State-Id] 278 Unsigned32
165 // * [ Supported-Vendor-Id ] 265 Unsigned32
166 // * [ Auth-Application-Id ] 258 Unsigned32
167 // * [Acct-Application-Id] 259 Unsigned32
168 anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
169 std::string OH = getOriginHostName();
170 std::string OR = getOriginRealmName();
171 std::string hostIP = anna::functions::getHostnameIP(); // Address
172 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
173 std::string productName = "ANNA Diameter Client"; // UTF8String
175 diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request);
176 diameterCER.setApplicationId(0); // base protocol
177 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
178 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
179 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>"
180 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
181 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
182 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId);
184 // Assignment for internal encoded versions:
185 setClientCER(diameterCER.code());
188 void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) noexcept(false) {
189 if(wp < ClientSession::DefaultWatchdogPeriod) {
190 throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
193 a_watchdogPeriod = wp;
196 void comm::Engine::checkEntityCollision(const socket_v &v) noexcept(false) {
197 socket_v::const_iterator it;
198 socket_v::const_iterator it_min(v.begin());
199 socket_v::const_iterator it_max(v.end());
201 for(it = it_min; it != it_max; it++) {
202 server_iterator ii = server_find(*it);
204 if(ii != server_end())
205 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
208 // Check repetitions:
209 std::map < socket_t, int/*dummy*/ > auxMap;
211 for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
213 if(auxMap.size() != v.size())
214 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
217 comm::Entity* comm::Engine::createEntity(const socket_v & socketList, const std::string &description)
219 Entity* result(NULL);
220 anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
222 if(socketList.size() == 0)
223 throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
225 // Proteccion antes de reservar memoria para una entidad (allocateEntity):
226 checkEntityCollision(socketList);
228 if((result = allocateEntity()) == NULL)
229 throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
232 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
233 // Assignments (it could be done at allocate):
234 result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
235 result->setMaxServers(socketList.size());
236 result->setDescription(description);
237 entity_key key(getEntityKey(socketList));
238 result->a_socketListLiteral = key;
239 // Create associated servers:
240 socket_v::const_iterator it;
241 socket_v::const_iterator it_min(socketList.begin());
242 socket_v::const_iterator it_max(socketList.end());
245 for(it = it_min; it != it_max; it++) {
246 result->addServer(*it);
248 if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
250 if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
255 a_entities.insert(entity_value_type(key, result));
257 string msg("diameter::comm::Engine::createEntity | ");
258 msg += result->asString();
259 msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
260 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
266 comm::LocalServer *comm::Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
268 LocalServer* result(NULL);
269 anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
270 // Proteccion antes de reservar memoria para un LocalServer
271 socket_t key(addr, port);
273 if(a_localServers.find(key) != a_localServers.end()) {
274 throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
277 if((result = allocateLocalServer()) == NULL)
278 throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
280 result->setEngine(this); // only to refresh availability
282 result->setCategory(category);
283 result->setDescription(description);
284 result->setAllowedInactivityTime(allowedInactivityTime);
285 result->initializeStatisticResources();
286 // Los saco con metodos virtuales readXXX del motor:
287 // if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
288 // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
289 a_localServers.insert(localServer_value_type(key, result));
291 string msg("diameter::comm::Engine::createLocalServer | ");
292 msg += result->asString();
293 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
296 // /*if (a_autoListen) */result->enable(); // creates server socket
297 // ENABLE THE SERVER: if already open (other comm engine for another origin host in the same address), nothing done. But the reference to the server is doubled along 2 comm engines ...
298 result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
303 comm::Entity* comm::Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
306 dualList.push_back(socket_t(addr1, port1));
307 dualList.push_back(socket_t(addr2, port2));
308 return (createEntity(dualList, description));
312 comm::Server* comm::Engine::createServer(Entity *entity, const socket_t & socket)
314 Server* result(NULL);
315 anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
317 if((result = allocateServer()) == NULL)
318 throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
321 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
322 // Assignments (it could be done at allocate):
323 result->a_parent = entity;
324 result->a_socket = socket;
325 result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
326 result->initializeStatisticResources();
328 result->a_engine = this;
329 for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
330 result->addClientSession(k);
332 a_servers.insert(server_value_type(socket, result));
333 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
334 // string msg("diameter::comm::Engine::resolveServer | ");
335 // msg += result->asString();
336 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
337 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
344 comm::ClientSession* comm::Engine::createClientSession(Server *server, int socketId)
346 ClientSession* result(NULL);
347 anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
349 if((result = allocateClientSession()) == NULL)
350 throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
353 result->initialize(); // warning: recycler does not initialize its objects and at least...
354 // Assignments (it could be done at allocate):
356 if((a_client_cer.isEmpty()) || (a_client_dwr.isEmpty()))
357 throw anna::RuntimeException("Must define valid CER and DWR messages by mean setClientCER and setClientDWR()", ANNA_FILE_LOCATION);
359 result->a_cer.setBody(a_client_cer);
360 result->a_dwr.setBody(a_client_dwr);
361 result->setWatchdogPeriod(a_watchdogPeriod);
362 result->a_parent = server;
363 result->a_socketId = socketId;
364 result->initializeSequences(); // despues de asignar el server y el socketId (sequences are seed-based by mean exclusive hash)
365 result->a_engine = this;
366 clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
367 a_clientSessions.insert(clientSession_value_type(key, result));
368 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
369 // string msg("diameter::comm::Engine::createClientSession | ");
370 // msg += result->asString();
371 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
372 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
375 anna::comm::Network& network = anna::comm::Network::instantiate();
376 result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
377 result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
378 anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
379 // Delay time on tcp connect:
380 result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
383 if(a_autoBind) result->bind();
389 bool comm::Engine::broadcastEntities(const Message* message) noexcept(false) {
390 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
394 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
396 ok = entity(it)->broadcast(message);
398 if(!ok) allok = false;
399 } catch(anna::RuntimeException &ex) {
408 bool comm::Engine::broadcastLocalServers(const Message* message) noexcept(false) {
409 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
413 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
415 ok = localServer(it)->broadcast(message);
417 if(!ok) allok = false;
418 } catch(anna::RuntimeException &ex) {
427 bool comm::Engine::bind() noexcept(false) {
428 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
429 bool result = true; // all OK return
431 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
434 } catch(anna::RuntimeException &ex) {
443 comm::ClientSession* comm::Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
445 return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
448 comm::ClientSession* comm::Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
450 anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
451 clientSession_iterator ii = clientSession_find(key);
453 if(ii != clientSession_end())
454 return clientSession(ii);
456 if(emode != anna::Exception::Mode::Ignore) {
457 string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
459 msg += " | ClientSession not found";
460 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
462 if(emode == anna::Exception::Mode::Throw)
472 comm::Server* comm::Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
474 anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
475 server_iterator ii = server_find(server_key(addr, port));
477 if(ii != server_end())
480 if(emode != anna::Exception::Mode::Ignore) {
481 string msg("diameter::comm::Engine::findServer | addr: ");
483 msg += anna::functions::asText(" | port: ", port);
484 msg += " | Server not found";
485 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
487 if(emode == anna::Exception::Mode::Throw)
496 comm::Entity* comm::Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
498 anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
499 entity_key key(getEntityKey(socketList));
500 entity_iterator ii = entity_find(key);
502 if(ii != entity_end())
505 if(emode != anna::Exception::Mode::Ignore) {
506 string msg("diameter::comm::Engine::findEntity | socket list: ");
508 msg += " | Entity not found";
509 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
511 if(emode == anna::Exception::Mode::Throw)
520 comm::Entity* comm::Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
523 dualList.push_back(socket_t(addr1, port1));
524 dualList.push_back(socket_t(addr2, port2));
525 return (findEntity(dualList, emode));
529 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
534 // for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
535 // entity = entity(it);
536 // if (entity->getCategory() == category) return entity;
543 comm::LocalServer* comm::Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
545 anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
546 socket_t key(addr, port);
547 localServer_iterator ii = localServer_find(key);
549 if(ii != localServer_end())
550 return localServer(ii);
552 if(emode != anna::Exception::Mode::Ignore) {
553 string msg("diameter::comm::Engine::findLocalServer | addr: ");
555 msg += anna::functions::asText(" | port: ", port);
556 msg += " | LocalServer not found";
557 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
559 if(emode == anna::Exception::Mode::Throw)
569 comm::ServerSession* comm::Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) noexcept(false) {
570 anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
571 ServerSession *result;
573 // Search at each local server:
574 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
575 result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
577 if(result) return result;
580 if(emode != anna::Exception::Mode::Ignore) {
581 string msg("diameter::comm::Engine::findServerSession | socketId: ");
582 msg += anna::functions::asString(socketId);
583 msg += " | ServerSession not found";
584 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
586 if(emode == anna::Exception::Mode::Throw)
596 void comm::Engine::closeClientSession(comm::ClientSession* clientSession, bool destroy)
598 if(clientSession == NULL)
602 string msg("diameter::comm::Engine::closeClientSession | ");
603 msg += clientSession->asString();
604 msg += " | Destroy: ";
605 msg += (destroy ? "yes" : "no");
606 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
608 anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
609 clientSession_iterator ii = clientSession_find(clientSession->getKey());
611 if(ii == clientSession_end())
615 clientSession->setState(ClientSession::State::Closing);
617 if(destroy) clientSession->setAutoRecovery(false);
619 clientSession->unbind(destroy /* destroy needs to perform immediate close */);
623 releaseClientSession(clientSession);
624 } catch(anna::RuntimeException& ex) {
628 a_clientSessions.erase(ii);
634 void comm::Engine::closeServer(comm::Server* server, bool destroy)
640 string msg("diameter::comm::Engine::closeServer | ");
641 msg += server->asString();
642 msg += " | Destroy: ";
643 msg += (destroy ? "yes" : "no");
644 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
646 anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
647 server_iterator ii = server_find(server->a_socket);
649 if(ii == server_end())
653 server->close(destroy);
657 releaseServer(server);
658 } catch(anna::RuntimeException& ex) {
666 void comm::Engine::closeEntity(comm::Entity* entity, bool destroy)
672 string msg("diameter::comm::Engine::closeEntity | ");
673 msg += entity->asString();
674 msg += " | Destroy: ";
675 msg += (destroy ? "yes" : "no");
676 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
678 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
679 entity_iterator ii = entity_find(entity->a_socketListLiteral);
681 if(ii == entity_end())
685 entity->close(destroy);
689 if(!entity->idle()) { entity->setDeprecated(true); return; }
691 releaseEntity(entity);
692 } catch(anna::RuntimeException& ex) {
696 a_entities.erase(ii);
701 void comm::Engine::closeLocalServer(comm::LocalServer* localServer, bool destroy)
703 if(localServer == NULL)
707 string msg("diameter::comm::Engine::closeLocalServer | ");
708 msg += localServer->asString();
709 msg += " | Destroy: ";
710 msg += (destroy ? "yes" : "no");
711 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
713 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
714 localServer_iterator ii = localServer_find(localServer->getKey());
716 if(ii == localServer_end())
720 localServer->close();
724 releaseLocalServer(localServer);
725 } catch(anna::RuntimeException& ex) {
729 a_localServers.erase(ii);
734 void comm::Engine::closeEntities(bool destroy) noexcept(false) {
735 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
736 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
738 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
739 closeEntity(entity(it), destroy);
742 void comm::Engine::closeLocalServers(bool destroy) noexcept(false) {
743 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
744 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
746 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
747 closeLocalServer(localServer(it), destroy);
750 void comm::Engine::eraseDeprecatedIdleEntities() {
751 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
754 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
757 if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
761 int comm::Engine::getOTARequestsForEntities() const {
764 for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
765 result += entity(it)->getOTARequests();
770 int comm::Engine::getOTARequestsForLocalServers() const {
773 for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
774 result += localServer(it)->getOTARequests();
780 void comm::Engine::setOriginRealmName(const std::string & originRealmName) {
781 a_originRealm = ((originRealmName != "") ? originRealmName : anna::functions::getDomainname());
785 void comm::Engine::setOriginHostName(const std::string & originHostName) {
786 a_originHost = ((originHostName != "") ? originHostName : anna::functions::getHostname());
791 void comm::Engine::raiseAutoRecovery(bool autoRecovery) noexcept(false) {
792 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
794 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
795 entity(it)->raiseAutoRecovery(autoRecovery);
798 void comm::Engine::do_stop()
800 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
801 close(true /* destroy */);
804 std::string comm::Engine::asString(void) const {
806 trace = "\n================================";
807 trace += "\nDiameter comm Engine information";
808 trace += "\n================================";
809 trace += "\nAutoBind: ";
810 trace += a_autoBind ? "yes" : "no";
811 trace += "\nMaxConnectionDelay: ";
812 trace += a_maxConnectionDelay.asString();
813 trace += "\nAvailable for entities: ";
814 trace += a_availableForEntities ? "yes" : "no";
815 trace += "\nAvailable for local servers: ";
816 trace += a_availableForLocalServers ? "yes" : "no";
817 trace += "\nOTA requests: ";
818 trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
819 trace += "\nOTA requests for entities: ";
820 trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
821 trace += "\nOTA requests for local servers: ";
822 trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
824 trace += "\nNumber of entities: ";
825 trace += anna::functions::asString(a_entities.size());
827 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
829 trace += entity(it)->asString();
833 trace += "\nNumber of LocalServers: ";
834 trace += anna::functions::asString(a_localServers.size());
836 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
838 trace += localServer(it)->asString();
845 anna::xml::Node* comm::Engine::asXML(anna::xml::Node* parent) const
847 parent = anna::app::Component::asXML(parent);
848 anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
849 result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
850 result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
851 result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
852 result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
853 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
854 result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
855 result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
856 result->createAttribute("NumberOfEntities", a_entities.size());
857 anna::xml::Node* entities = result->createChild("Engine.Entities");
859 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
860 entity(it)->asXML(entities);
862 result->createAttribute("NumberOfLocalServers", a_localServers.size());
863 anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
865 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
866 localServer(it)->asXML(localServers);
870 // <Engine.RemoteRealm Name="afNodeHostRealm.com">
871 // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:4"/>
872 // </Engine.RemoteRealm>
873 // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
874 // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:6"/>
875 // </Engine.RemoteRealm>
876 for (dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.begin(); drit != a_dr_dh_server_sessions.end(); drit++) {
877 anna::xml::Node* remoteRealm = result->createChild("Engine.RemoteRealm");
878 remoteRealm->createAttribute("Name", drit->first);
879 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
880 for (dh_server_sessions_it_t dhit = dhServerSessions->begin(); dhit != dhServerSessions->end(); dhit++) {
881 anna::xml::Node* remoteRealmHost = remoteRealm->createChild("Engine.RemoteRealmHost");
882 remoteRealmHost->createAttribute("Name", dhit->first);
883 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
884 for (server_sessions_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
885 std::string socket = anna::functions::socketLiteralAsString((*ssit)->getAddress(), (*ssit)->getPort());
886 std::string ss_desc = socket + anna::functions::asString("|ServerSessionId:%d", (*ssit)->getSocketId());
887 remoteRealmHost->createAttribute("ServerSession", ss_desc);
895 comm::Engine::clientSession_iterator comm::Engine::clientSession_find(const clientSession_key &key) {
896 return a_clientSessions.find(key);
899 comm::Engine::server_iterator comm::Engine::server_find(const server_key &key) {
900 return a_servers.find(key);
903 comm::Engine::entity_iterator comm::Engine::entity_find(const entity_key &key) {
904 return a_entities.find(key);
907 comm::Engine::localServer_iterator comm::Engine::localServer_find(const socket_t &key) {
908 return a_localServers.find(key);
911 comm::Engine::entity_key comm::Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const {
913 dualList.push_back(socket_t(addr1, port1));
914 dualList.push_back(socket_t(addr2, port2));
915 return (getEntityKey(dualList));
918 comm::Engine::entity_key comm::Engine::getEntityKey(const socket_v &v) const {
920 socket_v::const_iterator it;
921 socket_v::const_iterator it_min(v.begin());
922 socket_v::const_iterator it_max(v.end());
924 for(it = it_min; it != it_max; it++) {
925 result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
929 result.erase(result.size() - 1, 1); // remove last space
934 void comm::Engine::availabilityLostForEntities() {
935 a_availableForEntities = false;
937 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
938 msg += getOriginRealmName();
939 msg += " | Origin-Host: ";
940 msg += getOriginHostName();
941 msg += " } has lost its availability for entities";
942 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
945 OamModule &oamModule = OamModule::instantiate();
946 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
947 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities);
951 void comm::Engine::availabilityRecoveredForEntities() {
952 a_availableForEntities = true;
954 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
955 msg += getOriginRealmName();
956 msg += " | Origin-Host: ";
957 msg += getOriginHostName();
958 msg += " } has recovered its availability for entities";
959 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
962 OamModule &oamModule = OamModule::instantiate();
963 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
964 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
968 void comm::Engine::availabilityLostForLocalServers() {
969 a_availableForLocalServers = false;
971 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
972 msg += getOriginRealmName();
973 msg += " | Origin-Host: ";
974 msg += getOriginHostName();
975 msg += " } has lost its availability for local servers";
976 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
979 OamModule &oamModule = OamModule::instantiate();
980 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
981 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
985 void comm::Engine::availabilityRecoveredForLocalServers() {
986 a_availableForLocalServers = true;
988 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
989 msg += getOriginRealmName();
990 msg += " | Origin-Host: ";
991 msg += getOriginHostName();
992 msg += " } has recovered its availability for local servers";
993 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
996 OamModule &oamModule = OamModule::instantiate();
997 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
998 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
1002 bool comm::Engine::refreshAvailabilityForEntities() {
1004 if(a_availableForEntities) { // check not-bound state for all client-sessions:
1005 bool isolate = true;
1007 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
1008 if(entity(it)->isAvailable()) { isolate = false; break; }
1011 availabilityLostForEntities();
1018 // Here not available
1019 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
1020 if(entity(it)->isAvailable()) {
1021 availabilityRecoveredForEntities();
1028 bool comm::Engine::refreshAvailabilityForLocalServers() {
1030 if(a_availableForLocalServers) { // check not-bound state for all client-sessions:
1031 bool isolate = true;
1033 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
1034 if(localServer(it)->isAvailable()) { isolate = false; break; }
1037 availabilityLostForLocalServers();
1044 // Here not available
1045 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
1046 if(localServer(it)->isAvailable()) {
1047 availabilityRecoveredForLocalServers();
1055 void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) const {
1057 // Check for base protocol codec engine health:
1059 assertBaseProtocolHealth();
1061 catch(anna::RuntimeException &ex) {
1066 // Default DPA implementation:
1068 // 'Disconnect-Peer-Answer' (282,answer)
1069 // {Result-Code}...................................(268,0)
1070 // {Origin-Host}...................................(264,0)
1071 // {Origin-Realm}..................................(296,0)
1072 // [Error-Message].................................(281,0)
1073 // *[Failed-AVP]....................................(279,0)
1075 anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine());
1076 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1077 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1078 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1080 diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
1081 diameterDPA.setVersion(1);
1082 diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
1083 diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
1084 diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
1086 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1087 avpRC.setMandatoryBit();
1088 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1090 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1091 avpOH.setMandatoryBit();
1092 avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
1094 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1095 avpOR.setMandatoryBit();
1096 avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
1097 diameterDPA.addAvp(&avpRC);
1098 diameterDPA.addAvp(&avpOH);
1099 diameterDPA.addAvp(&avpOR);
1101 dpa = diameterDPA.code();
1102 } catch(anna::RuntimeException &ex) {
1103 std::string msg = ex.getText();
1104 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)";
1105 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1106 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1111 void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock &cer) const {
1113 // Check for base protocol codec engine health:
1114 assertBaseProtocolHealth();
1116 if (getCEA() != "") {
1117 anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
1120 diameterCEA.loadXMLFile(getCEA());
1121 diameterCEA.setHopByHop(anna::diameter::codec::functions::getHopByHop(cer));
1122 diameterCEA.setEndToEnd(anna::diameter::codec::functions::getEndToEnd(cer));
1123 cea = diameterCEA.code();
1125 } catch(anna::RuntimeException &ex) {
1127 LOGWARNING(anna::Logger::warning("CEA file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
1128 //return anna::diameter::comm::Engine::readCEA(cea, cer);
1129 // will fail with empty cea
1135 // Default CEA implementation:
1137 // 'Capabilities-Exchange-Answer' (257,answer)
1138 // {Result-Code}...................................(268,0)
1139 // {Origin-Host}...................................(264,0)
1140 // {Origin-Realm}..................................(296,0)
1141 // 1*{Host-IP-Address}...............................(257,0)
1142 // {Vendor-Id}.....................................(266,0)
1143 // {Product-Name}..................................(269,0)
1144 // [Origin-State-Id]...............................(278,0)
1145 // [Error-Message].................................(281,0)
1146 // *[Failed-AVP]....................................(279,0)
1147 // *[Supported-Vendor-Id]...........................(265,0)
1148 // *[Auth-Application-Id]...........................(258,0)
1149 // *[Inband-Security-Id]............................(299,0)
1150 // *[Acct-Application-Id]...........................(259,0)
1151 // [Vendor-Specific-Application-Id]................(260,0)
1152 // [Firmware-Revision].............................(267,0)
1153 // *[AVP]...........................................(0,0)
1155 anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
1156 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1157 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1158 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1160 diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1161 diameterCEA.setVersion(1);
1162 diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1163 diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1164 diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1166 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1167 avpRC.setMandatoryBit();
1168 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1170 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1171 avpOH.setMandatoryBit();
1172 avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
1174 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1175 avpOR.setMandatoryBit();
1176 avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
1177 diameterCEA.addAvp(&avpRC);
1178 diameterCEA.addAvp(&avpOH);
1179 diameterCEA.addAvp(&avpOR);
1181 std::string hostIP = anna::functions::getHostnameIP(); // Address
1182 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1184 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1185 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1187 std::string productName = "Diameter Server"; // UTF8String
1188 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1190 cea = diameterCEA.code();
1191 } catch(anna::RuntimeException &ex) {
1192 std::string msg = ex.getText();
1193 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)";
1194 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1195 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1199 void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) {
1201 // Decode CER (TODO: use raw buffer helpers)
1202 std::string destinationRealm, destinationHost;
1203 codec::Message codecMsg(getBaseProtocolCodecEngine());
1205 codecMsg.decode(a_client_cer);
1206 destinationRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
1207 destinationHost = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->getValue();
1209 catch(anna::RuntimeException &ex) {
1214 dr_dh_server_sessions_nc_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
1215 if (drit != a_dr_dh_server_sessions.end()) { // found
1216 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
1217 dh_server_sessions_nc_it_t dhit = dhServerSessions->find(destinationHost);
1218 if (dhit != dhServerSessions->end()) { // found
1219 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
1220 if (register_or_desregister) { // REGISTER
1221 serverSessions->push_back(ss);
1223 else { // DESREGISTER
1224 // Sequential search the specific server session:
1225 for (server_sessions_nc_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
1226 if ((*ssit)->getAddress() != ss->getAddress()) continue;
1227 if ((*ssit)->getPort() != ss->getPort()) continue;
1228 if ((*ssit)->getSocketId() != ss->getSocketId()) continue;
1229 serverSessions->erase(ssit); // if it is the last server session removed in DR-DH path, the XML will show this tree empty
1230 // (it could be a hint for past registerings):
1231 // <Engine.RemoteRealm Name="afNodeHostRealm.com">
1232 // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com"/>
1233 // </Engine.RemoteRealm>
1234 // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
1235 // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com"/>
1236 // </Engine.RemoteRealm>
1243 if (!register_or_desregister) return; // strange (host not found)
1244 server_sessions_vector_t ssVector;
1245 ssVector.push_back(ss);
1246 (*dhServerSessions)[destinationHost] = ssVector;
1250 if (!register_or_desregister) return; // strange (realm not found)
1251 server_sessions_vector_t ssVector;
1252 ssVector.push_back(ss);
1253 dh_server_sessions_map_t dhServerSessions;
1254 dhServerSessions[destinationHost] = ssVector;
1255 a_dr_dh_server_sessions[destinationRealm] = dhServerSessions;
1259 void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) const {
1261 // Check for base protocol codec engine health:
1262 assertBaseProtocolHealth();
1264 // Default DWA implementation:
1266 // 'Device-Watchdog-Answer' (280,answer)
1267 // {Result-Code}...................................(268,0)
1268 // {Origin-Host}...................................(264,0)
1269 // {Origin-Realm}..................................(296,0)
1270 // [Error-Message].................................(281,0)
1271 // *[Failed-AVP]....................................(279,0)
1272 // [Origin-State-Id]...............................(278,0)
1274 anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine());
1275 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1276 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1277 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1279 diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1280 diameterDWA.setVersion(1);
1281 diameterDWA.setApplicationId(anna::diameter::codec::functions::getApplicationId(dwr));
1282 diameterDWA.setHopByHop(anna::diameter::codec::functions::getHopByHop(dwr));
1283 diameterDWA.setEndToEnd(anna::diameter::codec::functions::getEndToEnd(dwr));
1285 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1286 avpRC.setMandatoryBit();
1287 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1289 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1290 avpOH.setMandatoryBit();
1291 avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
1293 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1294 avpOR.setMandatoryBit();
1295 avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
1296 diameterDWA.addAvp(&avpRC);
1297 diameterDWA.addAvp(&avpOH);
1298 diameterDWA.addAvp(&avpOR);
1300 dwa = diameterDWA.code();
1301 } catch(anna::RuntimeException &ex) {
1302 std::string msg = ex.getText();
1303 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)";
1304 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1305 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1309 void comm::Engine::resetStatistics() {
1310 for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1311 server(it)->resetStatistics();
1313 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1314 localServer(it)->resetStatistics();
1317 void comm::Engine::do_initialize() noexcept(false) {
1318 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
1319 LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
1322 void comm::Engine::lazyInitialize() noexcept(false) {
1323 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
1324 anna::app::Component::initialize(); // this will invoke do_initialize
1328 const comm::Response* comm::Engine::sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost) noexcept(false) {
1330 if (destinationRealm == "")
1331 throw anna::RuntimeException("Unable to resolve the destination: empty provided Destination-Realm name", ANNA_FILE_LOCATION);
1333 // Get the server sessions which fulfill the restrictions:
1334 dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
1335 if (drit == a_dr_dh_server_sessions.end())
1336 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);
1338 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
1339 // randomize between all server sessions for all hosts:
1340 dh_server_sessions_nc_it_t dhit;
1341 int hostsN = dhServerSessions->size();
1342 if (hostsN == 0) // avoids next division by cero (rand() % 0)
1343 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);
1345 if (destinationHost == "") {
1346 // in this case, randomize the host:
1347 dhit = dhServerSessions->begin();
1348 int randomHostIndx = rand() % hostsN; // number between 0 and the number of hosts - 1
1349 std::advance (dhit, randomHostIndx);
1352 dhit = dhServerSessions->find(destinationHost);
1353 if (dhit == dhServerSessions->end())
1354 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);
1357 // Now, randomize the available server sessions:
1358 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
1359 int serverSessionN = serverSessions->size();
1360 if (serverSessionN == 0) { // avoids next division by cero (rand() % 0)
1361 std::string aux = "";
1362 if (destinationHost != "") { aux = "to Destination-Host '"; aux += destinationHost; aux += "'"; }
1363 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());
1364 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1367 server_sessions_nc_it_t ssit = serverSessions->begin();
1368 int randomServerSessionIndx = rand() % serverSessionN; // number between 0 and the number of server sessions - 1
1369 std::advance (ssit, randomServerSessionIndx);
1370 return (*ssit)->send(message);