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 a_freezeEndToEndOnSending(false) {
53 anna::diameter::sccs::activate();
54 a_realm = anna::functions::getDomainname();
55 a_host = anna::functions::getHostname();
58 Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); }
59 void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
60 ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
61 void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
64 void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
65 if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
66 throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
69 if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
70 throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
77 //void Engine::setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException) {
78 // if (codec::functions::getCommandId(cea) != helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
79 // throw anna::RuntimeException("The message provided as 'CEA' is not a Capabilities-Exchange-Answer", ANNA_FILE_LOCATION);
82 // if (codec::functions::getCommandId(dwa) != helpers::base::COMMANDID__Device_Watchdog_Answer) {
83 // throw anna::RuntimeException("The message provided as 'DWA' is not a Device-Watchdog-Answer", ANNA_FILE_LOCATION);
90 void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
91 if(wp < ClientSession::DefaultWatchdogPeriod) {
92 throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
95 a_watchdogPeriod = wp;
98 void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
99 socket_v::const_iterator it;
100 socket_v::const_iterator it_min(v.begin());
101 socket_v::const_iterator it_max(v.end());
103 for(it = it_min; it != it_max; it++) {
104 server_iterator ii = server_find(*it);
106 if(ii != server_end())
107 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
110 // Check repetitions:
111 std::map < socket_t, int/*dummy*/ > auxMap;
113 for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
115 if(auxMap.size() != v.size())
116 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
119 Entity* Engine::createEntity(const socket_v & socketList, const std::string &description)
120 throw(anna::RuntimeException) {
121 Entity* result(NULL);
122 anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
124 if(socketList.size() == 0)
125 throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
127 // Proteccion antes de reservar memoria para una entidad (allocateEntity):
128 checkEntityCollision(socketList);
130 if((result = allocateEntity()) == NULL)
131 throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
134 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
135 // Assignments (it could be done at allocate):
136 result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
137 result->setMaxServers(socketList.size());
138 result->setDescription(description);
139 entity_key key(getEntityKey(socketList));
140 result->a_socketListLiteral = key;
141 // Create associated servers:
142 socket_v::const_iterator it;
143 socket_v::const_iterator it_min(socketList.begin());
144 socket_v::const_iterator it_max(socketList.end());
147 for(it = it_min; it != it_max; it++) {
148 result->addServer(*it);
150 if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
152 if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
157 a_entities.insert(entity_value_type(key, result));
159 string msg("diameter::comm::Engine::createEntity | ");
160 msg += result->asString();
161 msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
162 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
168 LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
169 throw(anna::RuntimeException) {
170 LocalServer* result(NULL);
171 anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
172 // Proteccion antes de reservar memoria para un LocalServer
173 socket_t key(addr, port);
175 if(a_localServers.find(key) != a_localServers.end())
176 throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
178 if((result = allocateLocalServer()) == NULL)
179 throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
181 result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa)
183 result->setCategory(category);
184 result->setDescription(description);
185 result->setAllowedInactivityTime(allowedInactivityTime);
186 result->initializeStatisticConcepts();
187 // Los saco con metodos virtuales readXXX del motor:
188 // if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
189 // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
190 a_localServers.insert(localServer_value_type(key, result));
192 string msg("diameter::comm::Engine::createLocalServer | ");
193 msg += result->asString();
194 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
197 // /*if (a_autoListen) */result->enable(); // creates server socket
198 result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
203 Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
204 throw(anna::RuntimeException) {
206 dualList.push_back(socket_t(addr1, port1));
207 dualList.push_back(socket_t(addr2, port2));
208 return (createEntity(dualList, description));
212 Server* Engine::createServer(Entity *entity, const socket_t & socket)
213 throw(anna::RuntimeException) {
214 Server* result(NULL);
215 anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
217 if((result = allocateServer()) == NULL)
218 throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
221 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
222 // Assignments (it could be done at allocate):
223 result->a_parent = entity;
224 result->a_socket = socket;
225 result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
226 result->a_engine = this;
227 result->initializeStatisticConcepts();
229 for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
230 result->addClientSession(k);
232 a_servers.insert(server_value_type(socket, result));
233 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
234 // string msg("diameter::comm::Engine::resolveServer | ");
235 // msg += result->asString();
236 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
237 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
244 ClientSession* Engine::createClientSession(Server *server, int socketId)
245 throw(anna::RuntimeException) {
246 ClientSession* result(NULL);
247 anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
249 if((result = allocateClientSession()) == NULL)
250 throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
253 result->initialize(); // warning: recycler does not initialize its objects and at least...
254 // Assignments (it could be done at allocate):
256 if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
257 throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
259 result->a_cer.setBody(a_cer);
260 result->a_dwr.setBody(a_dwr);
261 result->setWatchdogPeriod(a_watchdogPeriod);
262 result->a_parent = server;
263 result->a_socketId = socketId;
264 result->initializeSequences(); // después de asignar el server y el socketId (*)
265 // (*) 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)));
266 result->a_engine = this;
267 clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
268 a_clientSessions.insert(clientSession_value_type(key, result));
269 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
270 // string msg("diameter::comm::Engine::createClientSession | ");
271 // msg += result->asString();
272 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
273 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
276 anna::comm::Network& network = anna::comm::Network::instantiate();
277 result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
278 result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
279 anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
280 // Delay time on tcp connect:
281 result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
284 if(a_autoBind) result->bind();
290 bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
291 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
295 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
297 ok = entity(it)->broadcast(message);
299 if(!ok) allok = false;
300 } catch(anna::RuntimeException &ex) {
309 bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
310 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
314 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
316 ok = localServer(it)->broadcast(message);
318 if(!ok) allok = false;
319 } catch(anna::RuntimeException &ex) {
328 bool Engine::bind() throw(anna::RuntimeException) {
329 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
330 bool result = true; // all OK return
332 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
335 } catch(anna::RuntimeException &ex) {
344 ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
345 throw(anna::RuntimeException) {
346 return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
349 ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
350 throw(anna::RuntimeException) {
351 anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
352 clientSession_iterator ii = clientSession_find(key);
354 if(ii != clientSession_end())
355 return clientSession(ii);
357 if(emode != anna::Exception::Mode::Ignore) {
358 string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
360 msg += " | ClientSession not found";
361 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
363 if(emode == anna::Exception::Mode::Throw)
373 Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
374 throw(anna::RuntimeException) {
375 anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
376 server_iterator ii = server_find(server_key(addr, port));
378 if(ii != server_end())
381 if(emode != anna::Exception::Mode::Ignore) {
382 string msg("diameter::comm::Engine::findServer | addr: ");
384 msg += anna::functions::asText(" | port: ", port);
385 msg += " | Server not found";
386 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
388 if(emode == anna::Exception::Mode::Throw)
397 Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
398 throw(anna::RuntimeException) {
399 anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
400 entity_key key(getEntityKey(socketList));
401 entity_iterator ii = entity_find(key);
403 if(ii != entity_end())
406 if(emode != anna::Exception::Mode::Ignore) {
407 string msg("diameter::comm::Engine::findEntity | socket list: ");
409 msg += " | Entity not found";
410 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
412 if(emode == anna::Exception::Mode::Throw)
421 Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
422 throw(anna::RuntimeException) {
424 dualList.push_back(socket_t(addr1, port1));
425 dualList.push_back(socket_t(addr2, port2));
426 return (findEntity(dualList, emode));
430 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
431 //throw(anna::RuntimeException) {
435 // for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
436 // entity = entity(it);
437 // if (entity->getCategory() == category) return entity;
444 LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
445 throw(anna::RuntimeException) {
446 anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
447 socket_t key(addr, port);
448 localServer_iterator ii = localServer_find(key);
450 if(ii != localServer_end())
451 return localServer(ii);
453 if(emode != anna::Exception::Mode::Ignore) {
454 string msg("diameter::comm::Engine::findLocalServer | addr: ");
456 msg += anna::functions::asText(" | port: ", port);
457 msg += " | LocalServer not found";
458 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
460 if(emode == anna::Exception::Mode::Throw)
470 ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
471 anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
472 ServerSession *result;
474 // Search at each local server:
475 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
476 result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
478 if(result) return result;
481 if(emode != anna::Exception::Mode::Ignore) {
482 string msg("diameter::comm::Engine::findServerSession | socketId: ");
483 msg += anna::functions::asString(socketId);
484 msg += " | ServerSession not found";
485 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
487 if(emode == anna::Exception::Mode::Throw)
497 void Engine::closeClientSession(ClientSession* clientSession, bool destroy)
498 throw(anna::RuntimeException) {
499 if(clientSession == NULL)
503 string msg("diameter::comm::Engine::closeClientSession | ");
504 msg += clientSession->asString();
505 msg += " | Destroy: ";
506 msg += (destroy ? "yes" : "no");
507 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
509 anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
510 clientSession_iterator ii = clientSession_find(clientSession->getKey());
512 if(ii == clientSession_end())
516 clientSession->setState(ClientSession::State::Closing);
518 if(destroy) clientSession->setAutoRecovery(false);
520 clientSession->unbind(destroy /* destroy needs to perform immediate close */);
524 releaseClientSession(clientSession);
525 } catch(anna::RuntimeException& ex) {
529 a_clientSessions.erase(ii);
535 void Engine::closeServer(Server* server, bool destroy)
536 throw(anna::RuntimeException) {
541 string msg("diameter::comm::Engine::closeServer | ");
542 msg += server->asString();
543 msg += " | Destroy: ";
544 msg += (destroy ? "yes" : "no");
545 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
547 anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
548 server_iterator ii = server_find(server->a_socket);
550 if(ii == server_end())
554 server->close(destroy);
558 releaseServer(server);
559 } catch(anna::RuntimeException& ex) {
567 void Engine::closeEntity(Entity* entity, bool destroy)
568 throw(anna::RuntimeException) {
573 string msg("diameter::comm::Engine::closeEntity | ");
574 msg += entity->asString();
575 msg += " | Destroy: ";
576 msg += (destroy ? "yes" : "no");
577 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
579 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
580 entity_iterator ii = entity_find(entity->a_socketListLiteral);
582 if(ii == entity_end())
586 entity->close(destroy);
590 if(!entity->idle()) { entity->setDeprecated(true); return; }
592 releaseEntity(entity);
593 } catch(anna::RuntimeException& ex) {
597 a_entities.erase(ii);
602 void Engine::closeLocalServer(LocalServer* localServer, bool destroy)
603 throw(anna::RuntimeException) {
604 if(localServer == NULL)
608 string msg("diameter::comm::Engine::closeLocalServer | ");
609 msg += localServer->asString();
610 msg += " | Destroy: ";
611 msg += (destroy ? "yes" : "no");
612 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
614 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
615 localServer_iterator ii = localServer_find(localServer->getKey());
617 if(ii == localServer_end())
621 localServer->close();
625 releaseLocalServer(localServer);
626 } catch(anna::RuntimeException& ex) {
630 a_localServers.erase(ii);
635 void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
636 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
637 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
639 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
640 closeEntity(entity(it), destroy);
643 void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
644 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
645 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
647 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
648 closeLocalServer(localServer(it), destroy);
651 void Engine::eraseDeprecatedIdleEntities() throw() {
652 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
655 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
658 if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
662 int Engine::getOTARequestsForEntities() const throw() {
665 for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
666 result += entity(it)->getOTARequests();
671 int Engine::getOTARequestsForLocalServers() const throw() {
674 for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
675 result += localServer(it)->getOTARequests();
681 void Engine::setRealm(const std::string & name) throw() {
682 a_realm = ((name != "") ? name : anna::functions::getDomainname());
686 void Engine::setHost(const std::string & name) throw() {
687 a_host = ((name != "") ? name : anna::functions::getHostname());
692 void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
693 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
695 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
696 entity(it)->raiseAutoRecovery(autoRecovery);
699 void Engine::do_stop()
701 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
702 close(true /* destroy */);
705 std::string Engine::asString(void) const throw() {
707 trace = "\n================================";
708 trace += "\nDiameter comm Engine information";
709 trace += "\n================================";
710 trace += "\nAutoBind: ";
711 trace += a_autoBind ? "yes" : "no";
712 trace += "\nMaxConnectionDelay: ";
713 trace += a_maxConnectionDelay.asString();
714 trace += "\nAvailable for entities: ";
715 trace += a_availableForEntities ? "yes" : "no";
716 trace += "\nAvailable for local servers: ";
717 trace += a_availableForLocalServers ? "yes" : "no";
718 trace += "\nOTA requests: ";
719 trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
720 trace += "\nOTA requests for entities: ";
721 trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
722 trace += "\nOTA requests for local servers: ";
723 trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
725 trace += "\nNumber of entities: ";
726 trace += anna::functions::asString(a_entities.size());
728 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
730 trace += entity(it)->asString();
734 trace += "\nNumber of LocalServers: ";
735 trace += anna::functions::asString(a_localServers.size());
737 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
739 trace += localServer(it)->asString();
746 anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const
748 parent = anna::app::Component::asXML(parent);
749 anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
750 result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
751 result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
752 result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
753 result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
754 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
755 result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
756 result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
757 result->createAttribute("NumberOfEntities", a_entities.size());
758 anna::xml::Node* entities = result->createChild("Engine.Entities");
760 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
761 entity(it)->asXML(entities);
763 result->createAttribute("NumberOfLocalServers", a_localServers.size());
764 anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
766 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
767 localServer(it)->asXML(localServers);
772 Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() {
773 return a_clientSessions.find(key);
776 Engine::server_iterator Engine::server_find(const server_key &key) throw() {
777 return a_servers.find(key);
780 Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() {
781 return a_entities.find(key);
784 Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() {
785 return a_localServers.find(key);
788 Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
790 dualList.push_back(socket_t(addr1, port1));
791 dualList.push_back(socket_t(addr2, port2));
792 return (getEntityKey(dualList));
795 Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
797 socket_v::const_iterator it;
798 socket_v::const_iterator it_min(v.begin());
799 socket_v::const_iterator it_max(v.end());
801 for(it = it_min; it != it_max; it++) {
802 result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
806 result.erase(result.size() - 1, 1); // remove last space
807 //return anna::functions::exclusiveHash(result);
812 void Engine::availabilityLostForEntities() throw() {
813 a_availableForEntities = false;
815 std::string msg = "diameter::comm::Engine { Realm: ";
817 msg += " } has lost its availability for entities";
818 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
821 OamModule &oamModule = OamModule::instantiate();
822 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
823 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities);
825 availabilityLostForEntities(this);
829 void Engine::availabilityRecoveredForEntities() throw() {
830 a_availableForEntities = true;
832 std::string msg = "diameter::comm::Engine { Realm: ";
834 msg += " } has recovered its availability for entities";
835 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
838 OamModule &oamModule = OamModule::instantiate();
839 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
840 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
842 availabilityRecoveredForEntities(this);
846 void Engine::availabilityLostForLocalServers() throw() {
847 a_availableForLocalServers = false;
849 std::string msg = "diameter::comm::Engine { Realm: ";
851 msg += " } has lost its availability for local servers";
852 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
855 OamModule &oamModule = OamModule::instantiate();
856 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
857 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
859 availabilityLostForLocalServers(this);
863 void Engine::availabilityRecoveredForLocalServers() throw() {
864 a_availableForLocalServers = true;
866 std::string msg = "diameter::comm::Engine { Realm: ";
868 msg += " } has recovered its availability for local servers";
869 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
872 OamModule &oamModule = OamModule::instantiate();
873 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
874 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
876 availabilityRecoveredForLocalServers(this);
880 bool Engine::refreshAvailabilityForEntities() throw() {
882 if(a_availableForEntities) { // check not-bound state for all client-sessions:
885 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
886 if(entity(it)->isAvailable()) { isolate = false; break; }
889 availabilityLostForEntities();
896 // Here not available
897 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
898 if(entity(it)->isAvailable()) {
899 availabilityRecoveredForEntities();
906 bool Engine::refreshAvailabilityForLocalServers() throw() {
908 if(a_availableForLocalServers) { // check not-bound state for all client-sessions:
911 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
912 if(localServer(it)->isAvailable()) { isolate = false; break; }
915 availabilityLostForLocalServers();
922 // Here not available
923 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
924 if(localServer(it)->isAvailable()) {
925 availabilityRecoveredForLocalServers();
933 void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
934 // Default DPA implementation:
936 // 'Disconnect-Peer-Answer' (282,answer)
937 // {Result-Code}...................................(268,0)
938 // {Origin-Host}...................................(264,0)
939 // {Origin-Realm}..................................(296,0)
940 // [Error-Message].................................(281,0)
941 // *[Failed-AVP]....................................(279,0)
943 anna::diameter::codec::Message diameterDPA;
944 anna::diameter::codec::Avp avpRC;
945 anna::diameter::codec::Avp avpOH;
946 anna::diameter::codec::Avp avpOR;
948 diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
949 diameterDPA.setVersion(1);
950 diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
951 diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
952 diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
954 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
955 avpRC.setMandatoryBit();
956 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
958 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
959 avpOH.setMandatoryBit();
960 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
962 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
963 avpOR.setMandatoryBit();
964 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
965 diameterDPA.addAvp(&avpRC);
966 diameterDPA.addAvp(&avpOH);
967 diameterDPA.addAvp(&avpOR);
969 dpa = diameterDPA.code();
970 } catch(anna::RuntimeException &ex) {
976 void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
977 // Default CEA implementation:
979 // 'Capabilities-Exchange-Answer' (257,answer)
980 // {Result-Code}...................................(268,0)
981 // {Origin-Host}...................................(264,0)
982 // {Origin-Realm}..................................(296,0)
983 // 1*{Host-IP-Address}...............................(257,0)
984 // {Vendor-Id}.....................................(266,0)
985 // {Product-Name}..................................(269,0)
986 // [Origin-State-Id]...............................(278,0)
987 // [Error-Message].................................(281,0)
988 // *[Failed-AVP]....................................(279,0)
989 // *[Supported-Vendor-Id]...........................(265,0)
990 // *[Auth-Application-Id]...........................(258,0)
991 // *[Inband-Security-Id]............................(299,0)
992 // *[Acct-Application-Id]...........................(259,0)
993 // [Vendor-Specific-Application-Id]................(260,0)
994 // [Firmware-Revision].............................(267,0)
995 // *[AVP]...........................................(0,0)
997 anna::diameter::codec::Message diameterCEA;
998 anna::diameter::codec::Avp avpRC;
999 anna::diameter::codec::Avp avpOH;
1000 anna::diameter::codec::Avp avpOR;
1002 diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1003 diameterCEA.setVersion(1);
1004 diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1005 diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1006 diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1008 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1009 avpRC.setMandatoryBit();
1010 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1012 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1013 avpOH.setMandatoryBit();
1014 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1016 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1017 avpOR.setMandatoryBit();
1018 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1019 diameterCEA.addAvp(&avpRC);
1020 diameterCEA.addAvp(&avpOH);
1021 diameterCEA.addAvp(&avpOR);
1023 std::string hostIP = anna::functions::getHostnameIP(); // Address
1024 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1026 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1027 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1029 std::string productName = "OCS Diameter Server"; // UTF8String
1030 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1032 cea = diameterCEA.code();
1033 } catch(anna::RuntimeException &ex) {
1039 void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
1040 // Default DWA implementation:
1042 // 'Device-Watchdog-Answer' (280,answer)
1043 // {Result-Code}...................................(268,0)
1044 // {Origin-Host}...................................(264,0)
1045 // {Origin-Realm}..................................(296,0)
1046 // [Error-Message].................................(281,0)
1047 // *[Failed-AVP]....................................(279,0)
1048 // [Origin-State-Id]...............................(278,0)
1050 anna::diameter::codec::Message diameterDWA;
1051 anna::diameter::codec::Avp avpRC;
1052 anna::diameter::codec::Avp avpOH;
1053 anna::diameter::codec::Avp avpOR;
1055 diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1056 diameterDWA.setVersion(1);
1057 diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr));
1058 diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr));
1059 diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr));
1061 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1062 avpRC.setMandatoryBit();
1063 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1065 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1066 avpOH.setMandatoryBit();
1067 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1069 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1070 avpOR.setMandatoryBit();
1071 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1072 diameterDWA.addAvp(&avpRC);
1073 diameterDWA.addAvp(&avpOH);
1074 diameterDWA.addAvp(&avpOR);
1076 dwa = diameterDWA.code();
1077 } catch(anna::RuntimeException &ex) {
1082 void Engine::resetStatistics() throw() {
1083 for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1084 server(it)->resetStatistics();
1086 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1087 localServer(it)->resetStatistics();