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 <anna/diameter.comm/Engine.hpp>
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>
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>
37 using namespace anna::diameter::comm;
41 anna::app::Component(getClassName()),
43 a_availableForEntities(false),
44 a_availableForLocalServers(false),
49 a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
50 a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
51 a_numberOfClientSessionsPerServer(1) {
52 anna::diameter::sccs::activate();
53 a_realm = anna::functions::getDomainname();
54 a_host = anna::functions::getHostname();
57 Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); }
58 void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
59 ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
60 void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
63 void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
64 if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
65 throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
68 if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
69 throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
76 //void Engine::setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException) {
77 // if (codec::functions::getCommandId(cea) != helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
78 // throw anna::RuntimeException("The message provided as 'CEA' is not a Capabilities-Exchange-Answer", ANNA_FILE_LOCATION);
81 // if (codec::functions::getCommandId(dwa) != helpers::base::COMMANDID__Device_Watchdog_Answer) {
82 // throw anna::RuntimeException("The message provided as 'DWA' is not a Device-Watchdog-Answer", ANNA_FILE_LOCATION);
89 void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
90 if(wp < ClientSession::DefaultWatchdogPeriod) {
91 throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
94 a_watchdogPeriod = wp;
97 void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
98 socket_v::const_iterator it;
99 socket_v::const_iterator it_min(v.begin());
100 socket_v::const_iterator it_max(v.end());
102 for(it = it_min; it != it_max; it++) {
103 server_iterator ii = server_find(*it);
105 if(ii != server_end())
106 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
109 // Check repetitions:
110 std::map < socket_t, int/*dummy*/ > auxMap;
112 for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
114 if(auxMap.size() != v.size())
115 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
118 Entity* Engine::createEntity(const socket_v & socketList, const std::string &description)
119 throw(anna::RuntimeException) {
120 Entity* result(NULL);
121 anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
123 if(socketList.size() == 0)
124 throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
126 // Proteccion antes de reservar memoria para una entidad (allocateEntity):
127 checkEntityCollision(socketList);
129 if((result = allocateEntity()) == NULL)
130 throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
133 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
134 // Assignments (it could be done at allocate):
135 result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
136 result->setMaxServers(socketList.size());
137 result->setDescription(description);
138 entity_key key(getEntityKey(socketList));
139 result->a_socketListLiteral = key;
140 // Create associated servers:
141 socket_v::const_iterator it;
142 socket_v::const_iterator it_min(socketList.begin());
143 socket_v::const_iterator it_max(socketList.end());
146 for(it = it_min; it != it_max; it++) {
147 result->addServer(*it);
149 if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
151 if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
156 a_entities.insert(entity_value_type(key, result));
158 string msg("diameter::comm::Engine::createEntity | ");
159 msg += result->asString();
160 msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
161 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
167 LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
168 throw(anna::RuntimeException) {
169 LocalServer* result(NULL);
170 anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
171 // Proteccion antes de reservar memoria para un LocalServer
172 socket_t key(addr, port);
174 if(a_localServers.find(key) != a_localServers.end())
175 throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
177 if((result = allocateLocalServer()) == NULL)
178 throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
180 result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa)
182 result->setCategory(category);
183 result->setDescription(description);
184 result->setAllowedInactivityTime(allowedInactivityTime);
185 result->initializeStatisticConcepts();
186 // Los saco con metodos virtuales readXXX del motor:
187 // if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
188 // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
189 a_localServers.insert(localServer_value_type(key, result));
191 string msg("diameter::comm::Engine::createLocalServer | ");
192 msg += result->asString();
193 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
196 // /*if (a_autoListen) */result->enable(); // creates server socket
197 result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
202 Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
203 throw(anna::RuntimeException) {
205 dualList.push_back(socket_t(addr1, port1));
206 dualList.push_back(socket_t(addr2, port2));
207 return (createEntity(dualList, description));
211 Server* Engine::createServer(Entity *entity, const socket_t & socket)
212 throw(anna::RuntimeException) {
213 Server* result(NULL);
214 anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
216 if((result = allocateServer()) == NULL)
217 throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
220 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
221 // Assignments (it could be done at allocate):
222 result->a_parent = entity;
223 result->a_socket = socket;
224 result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
225 result->a_engine = this;
226 result->initializeStatisticConcepts();
228 for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
229 result->addClientSession(k);
231 a_servers.insert(server_value_type(socket, result));
232 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
233 // string msg("diameter::comm::Engine::resolveServer | ");
234 // msg += result->asString();
235 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
236 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
243 ClientSession* Engine::createClientSession(Server *server, int socketId)
244 throw(anna::RuntimeException) {
245 ClientSession* result(NULL);
246 anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
248 if((result = allocateClientSession()) == NULL)
249 throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
252 result->initialize(); // warning: recycler does not initialize its objects and at least...
253 // Assignments (it could be done at allocate):
255 if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
256 throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
258 result->a_cer.setBody(a_cer);
259 result->a_dwr.setBody(a_dwr);
260 result->setWatchdogPeriod(a_watchdogPeriod);
261 result->a_parent = server;
262 result->a_socketId = socketId;
263 result->initializeSequences(); // despu�s de asignar el server y el socketId (*)
264 // (*) 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)));
265 result->a_engine = this;
266 clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
267 a_clientSessions.insert(clientSession_value_type(key, result));
268 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
269 // string msg("diameter::comm::Engine::createClientSession | ");
270 // msg += result->asString();
271 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
272 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
275 anna::comm::Network& network = anna::comm::Network::instantiate();
276 result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
277 result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
278 anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
279 // Delay time on tcp connect:
280 result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
283 if(a_autoBind) result->bind();
289 bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
290 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
294 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
296 ok = entity(it)->broadcast(message);
298 if(!ok) allok = false;
299 } catch(anna::RuntimeException &ex) {
308 bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
309 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
313 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
315 ok = localServer(it)->broadcast(message);
317 if(!ok) allok = false;
318 } catch(anna::RuntimeException &ex) {
327 bool Engine::bind() throw(anna::RuntimeException) {
328 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
329 bool result = true; // all OK return
331 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
334 } catch(anna::RuntimeException &ex) {
343 ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
344 throw(anna::RuntimeException) {
345 return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
348 ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
349 throw(anna::RuntimeException) {
350 anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
351 clientSession_iterator ii = clientSession_find(key);
353 if(ii != clientSession_end())
354 return clientSession(ii);
356 if(emode != anna::Exception::Mode::Ignore) {
357 string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
359 msg += " | ClientSession not found";
360 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
362 if(emode == anna::Exception::Mode::Throw)
372 Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
373 throw(anna::RuntimeException) {
374 anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
375 server_iterator ii = server_find(server_key(addr, port));
377 if(ii != server_end())
380 if(emode != anna::Exception::Mode::Ignore) {
381 string msg("diameter::comm::Engine::findServer | addr: ");
383 msg += anna::functions::asText(" | port: ", port);
384 msg += " | Server not found";
385 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
387 if(emode == anna::Exception::Mode::Throw)
396 Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
397 throw(anna::RuntimeException) {
398 anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
399 entity_key key(getEntityKey(socketList));
400 entity_iterator ii = entity_find(key);
402 if(ii != entity_end())
405 if(emode != anna::Exception::Mode::Ignore) {
406 string msg("diameter::comm::Engine::findEntity | socket list: ");
408 msg += " | Entity not found";
409 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
411 if(emode == anna::Exception::Mode::Throw)
420 Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
421 throw(anna::RuntimeException) {
423 dualList.push_back(socket_t(addr1, port1));
424 dualList.push_back(socket_t(addr2, port2));
425 return (findEntity(dualList, emode));
429 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
430 //throw(anna::RuntimeException) {
434 // for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
435 // entity = entity(it);
436 // if (entity->getCategory() == category) return entity;
443 LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
444 throw(anna::RuntimeException) {
445 anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
446 socket_t key(addr, port);
447 localServer_iterator ii = localServer_find(key);
449 if(ii != localServer_end())
450 return localServer(ii);
452 if(emode != anna::Exception::Mode::Ignore) {
453 string msg("diameter::comm::Engine::findLocalServer | addr: ");
455 msg += anna::functions::asText(" | port: ", port);
456 msg += " | LocalServer not found";
457 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
459 if(emode == anna::Exception::Mode::Throw)
469 ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
470 anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
471 ServerSession *result;
473 // Search at each local server:
474 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
475 result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
477 if(result) return result;
480 if(emode != anna::Exception::Mode::Ignore) {
481 string msg("diameter::comm::Engine::findServerSession | socketId: ");
482 msg += anna::functions::asString(socketId);
483 msg += " | ServerSession not found";
484 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
486 if(emode == anna::Exception::Mode::Throw)
496 void Engine::closeClientSession(ClientSession* clientSession, bool destroy)
497 throw(anna::RuntimeException) {
498 if(clientSession == NULL)
502 string msg("diameter::comm::Engine::closeClientSession | ");
503 msg += clientSession->asString();
504 msg += " | Destroy: ";
505 msg += (destroy ? "yes" : "no");
506 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
508 anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
509 clientSession_iterator ii = clientSession_find(clientSession->getKey());
511 if(ii == clientSession_end())
515 clientSession->setState(ClientSession::State::Closing);
517 if(destroy) clientSession->setAutoRecovery(false);
519 clientSession->unbind(destroy /* destroy needs to perform immediate close */);
523 releaseClientSession(clientSession);
524 } catch(anna::RuntimeException& ex) {
528 a_clientSessions.erase(ii);
534 void Engine::closeServer(Server* server, bool destroy)
535 throw(anna::RuntimeException) {
540 string msg("diameter::comm::Engine::closeServer | ");
541 msg += server->asString();
542 msg += " | Destroy: ";
543 msg += (destroy ? "yes" : "no");
544 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
546 anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
547 server_iterator ii = server_find(server->a_socket);
549 if(ii == server_end())
553 server->close(destroy);
557 releaseServer(server);
558 } catch(anna::RuntimeException& ex) {
566 void Engine::closeEntity(Entity* entity, bool destroy)
567 throw(anna::RuntimeException) {
572 string msg("diameter::comm::Engine::closeEntity | ");
573 msg += entity->asString();
574 msg += " | Destroy: ";
575 msg += (destroy ? "yes" : "no");
576 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
578 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
579 entity_iterator ii = entity_find(entity->a_socketListLiteral);
581 if(ii == entity_end())
585 entity->close(destroy);
589 if(!entity->idle()) { entity->setDeprecated(true); return; }
591 releaseEntity(entity);
592 } catch(anna::RuntimeException& ex) {
596 a_entities.erase(ii);
601 void Engine::closeLocalServer(LocalServer* localServer, bool destroy)
602 throw(anna::RuntimeException) {
603 if(localServer == NULL)
607 string msg("diameter::comm::Engine::closeLocalServer | ");
608 msg += localServer->asString();
609 msg += " | Destroy: ";
610 msg += (destroy ? "yes" : "no");
611 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
613 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
614 localServer_iterator ii = localServer_find(localServer->getKey());
616 if(ii == localServer_end())
620 localServer->close();
624 releaseLocalServer(localServer);
625 } catch(anna::RuntimeException& ex) {
629 a_localServers.erase(ii);
634 void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
635 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
636 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
638 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
639 closeEntity(entity(it), destroy);
642 void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
643 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
644 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
646 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
647 closeLocalServer(localServer(it), destroy);
650 void Engine::eraseDeprecatedIdleEntities() throw() {
651 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
654 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
657 if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
661 int Engine::getOTARequestsForEntities() const throw() {
664 for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
665 result += entity(it)->getOTARequests();
670 int Engine::getOTARequestsForLocalServers() const throw() {
673 for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
674 result += localServer(it)->getOTARequests();
680 void Engine::setRealm(const std::string & name) throw() {
681 a_realm = ((name != "") ? name : anna::functions::getDomainname());
685 void Engine::setHost(const std::string & name) throw() {
686 a_host = ((name != "") ? name : anna::functions::getHostname());
691 void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
692 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
694 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
695 entity(it)->raiseAutoRecovery(autoRecovery);
698 void Engine::do_stop()
700 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
701 close(true /* destroy */);
704 std::string Engine::asString(void) const throw() {
706 trace = "\n================================";
707 trace += "\nDiameter comm Engine information";
708 trace += "\n================================";
709 trace += "\nAutoBind: ";
710 trace += a_autoBind ? "yes" : "no";
711 trace += "\nMaxConnectionDelay: ";
712 trace += a_maxConnectionDelay.asString();
713 trace += "\nAvailable for entities: ";
714 trace += a_availableForEntities ? "yes" : "no";
715 trace += "\nAvailable for local servers: ";
716 trace += a_availableForLocalServers ? "yes" : "no";
717 trace += "\nOTA requests: ";
718 trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
719 trace += "\nOTA requests for entities: ";
720 trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
721 trace += "\nOTA requests for local servers: ";
722 trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
724 trace += "\nNumber of entities: ";
725 trace += anna::functions::asString(a_entities.size());
727 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
729 trace += entity(it)->asString();
733 trace += "\nNumber of LocalServers: ";
734 trace += anna::functions::asString(a_localServers.size());
736 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
738 trace += localServer(it)->asString();
745 anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const
747 parent = anna::app::Component::asXML(parent);
748 anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
749 result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
750 result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
751 result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
752 result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
753 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
754 result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
755 result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
756 result->createAttribute("NumberOfEntities", a_entities.size());
757 anna::xml::Node* entities = result->createChild("Engine.Entities");
759 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
760 entity(it)->asXML(entities);
762 result->createAttribute("NumberOfLocalServers", a_localServers.size());
763 anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
765 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
766 localServer(it)->asXML(localServers);
771 Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() {
772 return a_clientSessions.find(key);
775 Engine::server_iterator Engine::server_find(const server_key &key) throw() {
776 return a_servers.find(key);
779 Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() {
780 return a_entities.find(key);
783 Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() {
784 return a_localServers.find(key);
787 Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
789 dualList.push_back(socket_t(addr1, port1));
790 dualList.push_back(socket_t(addr2, port2));
791 return (getEntityKey(dualList));
794 Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
796 socket_v::const_iterator it;
797 socket_v::const_iterator it_min(v.begin());
798 socket_v::const_iterator it_max(v.end());
800 for(it = it_min; it != it_max; it++) {
801 result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
805 result.erase(result.size() - 1, 1); // remove last space
806 //return anna::functions::exclusiveHash(result);
811 void Engine::availabilityLostForEntities() throw() {
812 a_availableForEntities = false;
814 std::string msg = "diameter::comm::Engine { Realm: ";
816 msg += " } has lost its availability for entities";
817 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
820 OamModule &oamModule = OamModule::instantiate();
821 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
822 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities);
824 availabilityLostForEntities(this);
828 void Engine::availabilityRecoveredForEntities() throw() {
829 a_availableForEntities = true;
831 std::string msg = "diameter::comm::Engine { Realm: ";
833 msg += " } has recovered its availability for entities";
834 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
837 OamModule &oamModule = OamModule::instantiate();
838 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
839 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
841 availabilityRecoveredForEntities(this);
845 void Engine::availabilityLostForLocalServers() throw() {
846 a_availableForLocalServers = false;
848 std::string msg = "diameter::comm::Engine { Realm: ";
850 msg += " } has lost its availability for local servers";
851 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
854 OamModule &oamModule = OamModule::instantiate();
855 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
856 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
858 availabilityLostForLocalServers(this);
862 void Engine::availabilityRecoveredForLocalServers() throw() {
863 a_availableForLocalServers = true;
865 std::string msg = "diameter::comm::Engine { Realm: ";
867 msg += " } has recovered its availability for local servers";
868 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
871 OamModule &oamModule = OamModule::instantiate();
872 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
873 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
875 availabilityRecoveredForLocalServers(this);
879 bool Engine::refreshAvailabilityForEntities() throw() {
881 if(a_availableForEntities) { // check not-bound state for all client-sessions:
884 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
885 if(entity(it)->isAvailable()) { isolate = false; break; }
888 availabilityLostForEntities();
895 // Here not available
896 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
897 if(entity(it)->isAvailable()) {
898 availabilityRecoveredForEntities();
905 bool Engine::refreshAvailabilityForLocalServers() throw() {
907 if(a_availableForLocalServers) { // check not-bound state for all client-sessions:
910 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
911 if(localServer(it)->isAvailable()) { isolate = false; break; }
914 availabilityLostForLocalServers();
921 // Here not available
922 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
923 if(localServer(it)->isAvailable()) {
924 availabilityRecoveredForLocalServers();
932 void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
933 // Default DPA implementation:
935 // 'Disconnect-Peer-Answer' (282,answer)
936 // {Result-Code}...................................(268,0)
937 // {Origin-Host}...................................(264,0)
938 // {Origin-Realm}..................................(296,0)
939 // [Error-Message].................................(281,0)
940 // *[Failed-AVP]....................................(279,0)
942 anna::diameter::codec::Message diameterDPA;
943 anna::diameter::codec::Avp avpRC;
944 anna::diameter::codec::Avp avpOH;
945 anna::diameter::codec::Avp avpOR;
947 diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
948 diameterDPA.setVersion(1);
949 diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
950 diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
951 diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
953 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
954 avpRC.setMandatoryBit();
955 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
957 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
958 avpOH.setMandatoryBit();
959 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
961 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
962 avpOR.setMandatoryBit();
963 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
964 diameterDPA.addAvp(&avpRC);
965 diameterDPA.addAvp(&avpOH);
966 diameterDPA.addAvp(&avpOR);
968 dpa = diameterDPA.code();
969 } catch(anna::RuntimeException &ex) {
975 void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
976 // Default CEA implementation:
978 // 'Capabilities-Exchange-Answer' (257,answer)
979 // {Result-Code}...................................(268,0)
980 // {Origin-Host}...................................(264,0)
981 // {Origin-Realm}..................................(296,0)
982 // 1*{Host-IP-Address}...............................(257,0)
983 // {Vendor-Id}.....................................(266,0)
984 // {Product-Name}..................................(269,0)
985 // [Origin-State-Id]...............................(278,0)
986 // [Error-Message].................................(281,0)
987 // *[Failed-AVP]....................................(279,0)
988 // *[Supported-Vendor-Id]...........................(265,0)
989 // *[Auth-Application-Id]...........................(258,0)
990 // *[Inband-Security-Id]............................(299,0)
991 // *[Acct-Application-Id]...........................(259,0)
992 // [Vendor-Specific-Application-Id]................(260,0)
993 // [Firmware-Revision].............................(267,0)
994 // *[AVP]...........................................(0,0)
996 anna::diameter::codec::Message diameterCEA;
997 anna::diameter::codec::Avp avpRC;
998 anna::diameter::codec::Avp avpOH;
999 anna::diameter::codec::Avp avpOR;
1001 diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1002 diameterCEA.setVersion(1);
1003 diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1004 diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1005 diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1007 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1008 avpRC.setMandatoryBit();
1009 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1011 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1012 avpOH.setMandatoryBit();
1013 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1015 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1016 avpOR.setMandatoryBit();
1017 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1018 diameterCEA.addAvp(&avpRC);
1019 diameterCEA.addAvp(&avpOH);
1020 diameterCEA.addAvp(&avpOR);
1022 std::string hostIP = anna::functions::getHostnameIP(); // Address
1023 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1025 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1026 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1028 std::string productName = "OCS Diameter Server"; // UTF8String
1029 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1031 cea = diameterCEA.code();
1032 } catch(anna::RuntimeException &ex) {
1038 void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
1039 // Default DWA implementation:
1041 // 'Device-Watchdog-Answer' (280,answer)
1042 // {Result-Code}...................................(268,0)
1043 // {Origin-Host}...................................(264,0)
1044 // {Origin-Realm}..................................(296,0)
1045 // [Error-Message].................................(281,0)
1046 // *[Failed-AVP]....................................(279,0)
1047 // [Origin-State-Id]...............................(278,0)
1049 anna::diameter::codec::Message diameterDWA;
1050 anna::diameter::codec::Avp avpRC;
1051 anna::diameter::codec::Avp avpOH;
1052 anna::diameter::codec::Avp avpOR;
1054 diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1055 diameterDWA.setVersion(1);
1056 diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr));
1057 diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr));
1058 diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr));
1060 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1061 avpRC.setMandatoryBit();
1062 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1064 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1065 avpOH.setMandatoryBit();
1066 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1068 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1069 avpOR.setMandatoryBit();
1070 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1071 diameterDWA.addAvp(&avpRC);
1072 diameterDWA.addAvp(&avpOH);
1073 diameterDWA.addAvp(&avpOR);
1075 dwa = diameterDWA.code();
1076 } catch(anna::RuntimeException &ex) {
1081 void Engine::resetStatistics() throw() {
1082 for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1083 server(it)->resetStatistics();
1085 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1086 localServer(it)->resetStatistics();