1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #include <anna/diameter.comm/Engine.hpp>
39 #include <anna/core/tracing/Logger.hpp>
40 #include <anna/core/tracing/TraceMethod.hpp>
41 #include <anna/xml/Node.hpp>
42 #include <anna/comm/Network.hpp>
43 #include <anna/comm/Host.hpp>
44 #include <anna/comm/ClientSocket.hpp>
46 #include <anna/diameter.comm/Transport.hpp>
47 #include <anna/diameter.comm/Engine.hpp>
48 #include <anna/diameter.comm/Entity.hpp>
49 #include <anna/diameter.comm/Server.hpp>
50 #include <anna/diameter.comm/ClientSession.hpp>
51 #include <anna/diameter.comm/LocalServer.hpp>
52 #include <anna/core/functions.hpp>
53 #include <anna/diameter/internal/sccs.hpp>
54 #include <anna/diameter.comm/OamModule.hpp>
55 #include <anna/diameter/codec/functions.hpp>
56 #include <anna/diameter/helpers/base/functions.hpp>
57 #include <anna/diameter/helpers/helpers.hpp>
58 #include <anna/diameter/codec/Message.hpp>
59 #include <anna/diameter/codec/Avp.hpp>
65 using namespace anna::diameter::comm;
69 anna::app::Component(getClassName()),
71 a_availableForEntities(false),
72 a_availableForLocalServers(false),
77 a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
78 a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
79 a_numberOfClientSessionsPerServer(1),
80 a_freezeEndToEndOnSending(false) {
81 anna::diameter::sccs::activate();
82 a_realm = anna::functions::getDomainname();
83 a_host = anna::functions::getHostname();
86 Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); }
87 void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
88 ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
89 void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
92 void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
93 if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
94 throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
97 if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
98 throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
105 //void Engine::setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException) {
106 // if (codec::functions::getCommandId(cea) != helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
107 // throw anna::RuntimeException("The message provided as 'CEA' is not a Capabilities-Exchange-Answer", ANNA_FILE_LOCATION);
110 // if (codec::functions::getCommandId(dwa) != helpers::base::COMMANDID__Device_Watchdog_Answer) {
111 // throw anna::RuntimeException("The message provided as 'DWA' is not a Device-Watchdog-Answer", ANNA_FILE_LOCATION);
118 void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
119 if(wp < ClientSession::DefaultWatchdogPeriod) {
120 throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
123 a_watchdogPeriod = wp;
126 void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
127 socket_v::const_iterator it;
128 socket_v::const_iterator it_min(v.begin());
129 socket_v::const_iterator it_max(v.end());
131 for(it = it_min; it != it_max; it++) {
132 server_iterator ii = server_find(*it);
134 if(ii != server_end())
135 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
138 // Check repetitions:
139 std::map < socket_t, int/*dummy*/ > auxMap;
141 for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
143 if(auxMap.size() != v.size())
144 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
147 Entity* Engine::createEntity(const socket_v & socketList, const std::string &description)
148 throw(anna::RuntimeException) {
149 Entity* result(NULL);
150 anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
152 if(socketList.size() == 0)
153 throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
155 // Proteccion antes de reservar memoria para una entidad (allocateEntity):
156 checkEntityCollision(socketList);
158 if((result = allocateEntity()) == NULL)
159 throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
162 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
163 // Assignments (it could be done at allocate):
164 result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
165 result->setMaxServers(socketList.size());
166 result->setDescription(description);
167 entity_key key(getEntityKey(socketList));
168 result->a_socketListLiteral = key;
169 // Create associated servers:
170 socket_v::const_iterator it;
171 socket_v::const_iterator it_min(socketList.begin());
172 socket_v::const_iterator it_max(socketList.end());
175 for(it = it_min; it != it_max; it++) {
176 result->addServer(*it);
178 if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
180 if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
185 a_entities.insert(entity_value_type(key, result));
187 string msg("diameter::comm::Engine::createEntity | ");
188 msg += result->asString();
189 msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
190 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
196 LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
197 throw(anna::RuntimeException) {
198 LocalServer* result(NULL);
199 anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
200 // Proteccion antes de reservar memoria para un LocalServer
201 socket_t key(addr, port);
203 if(a_localServers.find(key) != a_localServers.end())
204 throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
206 if((result = allocateLocalServer()) == NULL)
207 throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
209 result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa)
211 result->setCategory(category);
212 result->setDescription(description);
213 result->setAllowedInactivityTime(allowedInactivityTime);
214 result->initializeStatisticConcepts();
215 // Los saco con metodos virtuales readXXX del motor:
216 // if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
217 // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
218 a_localServers.insert(localServer_value_type(key, result));
220 string msg("diameter::comm::Engine::createLocalServer | ");
221 msg += result->asString();
222 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
225 // /*if (a_autoListen) */result->enable(); // creates server socket
226 result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
231 Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
232 throw(anna::RuntimeException) {
234 dualList.push_back(socket_t(addr1, port1));
235 dualList.push_back(socket_t(addr2, port2));
236 return (createEntity(dualList, description));
240 Server* Engine::createServer(Entity *entity, const socket_t & socket)
241 throw(anna::RuntimeException) {
242 Server* result(NULL);
243 anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
245 if((result = allocateServer()) == NULL)
246 throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
249 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
250 // Assignments (it could be done at allocate):
251 result->a_parent = entity;
252 result->a_socket = socket;
253 result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
254 result->a_engine = this;
255 result->initializeStatisticConcepts();
257 for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
258 result->addClientSession(k);
260 a_servers.insert(server_value_type(socket, result));
261 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
262 // string msg("diameter::comm::Engine::resolveServer | ");
263 // msg += result->asString();
264 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
265 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
272 ClientSession* Engine::createClientSession(Server *server, int socketId)
273 throw(anna::RuntimeException) {
274 ClientSession* result(NULL);
275 anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
277 if((result = allocateClientSession()) == NULL)
278 throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
281 result->initialize(); // warning: recycler does not initialize its objects and at least...
282 // Assignments (it could be done at allocate):
284 if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
285 throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
287 result->a_cer.setBody(a_cer);
288 result->a_dwr.setBody(a_dwr);
289 result->setWatchdogPeriod(a_watchdogPeriod);
290 result->a_parent = server;
291 result->a_socketId = socketId;
292 result->initializeSequences(); // después de asignar el server y el socketId (*)
293 // (*) 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)));
294 result->a_engine = this;
295 clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
296 a_clientSessions.insert(clientSession_value_type(key, result));
297 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
298 // string msg("diameter::comm::Engine::createClientSession | ");
299 // msg += result->asString();
300 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
301 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
304 anna::comm::Network& network = anna::comm::Network::instantiate();
305 result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
306 result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
307 anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
308 // Delay time on tcp connect:
309 result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
312 if(a_autoBind) result->bind();
318 bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
319 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
323 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
325 ok = entity(it)->broadcast(message);
327 if(!ok) allok = false;
328 } catch(anna::RuntimeException &ex) {
337 bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
338 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
342 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
344 ok = localServer(it)->broadcast(message);
346 if(!ok) allok = false;
347 } catch(anna::RuntimeException &ex) {
356 bool Engine::bind() throw(anna::RuntimeException) {
357 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
358 bool result = true; // all OK return
360 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
363 } catch(anna::RuntimeException &ex) {
372 ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
373 throw(anna::RuntimeException) {
374 return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
377 ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
378 throw(anna::RuntimeException) {
379 anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
380 clientSession_iterator ii = clientSession_find(key);
382 if(ii != clientSession_end())
383 return clientSession(ii);
385 if(emode != anna::Exception::Mode::Ignore) {
386 string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
388 msg += " | ClientSession not found";
389 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
391 if(emode == anna::Exception::Mode::Throw)
401 Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
402 throw(anna::RuntimeException) {
403 anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
404 server_iterator ii = server_find(server_key(addr, port));
406 if(ii != server_end())
409 if(emode != anna::Exception::Mode::Ignore) {
410 string msg("diameter::comm::Engine::findServer | addr: ");
412 msg += anna::functions::asText(" | port: ", port);
413 msg += " | Server not found";
414 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
416 if(emode == anna::Exception::Mode::Throw)
425 Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
426 throw(anna::RuntimeException) {
427 anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
428 entity_key key(getEntityKey(socketList));
429 entity_iterator ii = entity_find(key);
431 if(ii != entity_end())
434 if(emode != anna::Exception::Mode::Ignore) {
435 string msg("diameter::comm::Engine::findEntity | socket list: ");
437 msg += " | Entity not found";
438 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
440 if(emode == anna::Exception::Mode::Throw)
449 Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
450 throw(anna::RuntimeException) {
452 dualList.push_back(socket_t(addr1, port1));
453 dualList.push_back(socket_t(addr2, port2));
454 return (findEntity(dualList, emode));
458 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
459 //throw(anna::RuntimeException) {
463 // for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
464 // entity = entity(it);
465 // if (entity->getCategory() == category) return entity;
472 LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
473 throw(anna::RuntimeException) {
474 anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
475 socket_t key(addr, port);
476 localServer_iterator ii = localServer_find(key);
478 if(ii != localServer_end())
479 return localServer(ii);
481 if(emode != anna::Exception::Mode::Ignore) {
482 string msg("diameter::comm::Engine::findLocalServer | addr: ");
484 msg += anna::functions::asText(" | port: ", port);
485 msg += " | LocalServer not found";
486 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
488 if(emode == anna::Exception::Mode::Throw)
498 ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
499 anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
500 ServerSession *result;
502 // Search at each local server:
503 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
504 result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
506 if(result) return result;
509 if(emode != anna::Exception::Mode::Ignore) {
510 string msg("diameter::comm::Engine::findServerSession | socketId: ");
511 msg += anna::functions::asString(socketId);
512 msg += " | ServerSession not found";
513 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
515 if(emode == anna::Exception::Mode::Throw)
525 void Engine::closeClientSession(ClientSession* clientSession, bool destroy)
526 throw(anna::RuntimeException) {
527 if(clientSession == NULL)
531 string msg("diameter::comm::Engine::closeClientSession | ");
532 msg += clientSession->asString();
533 msg += " | Destroy: ";
534 msg += (destroy ? "yes" : "no");
535 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
537 anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
538 clientSession_iterator ii = clientSession_find(clientSession->getKey());
540 if(ii == clientSession_end())
544 clientSession->setState(ClientSession::State::Closing);
546 if(destroy) clientSession->setAutoRecovery(false);
548 clientSession->unbind(destroy /* destroy needs to perform immediate close */);
552 releaseClientSession(clientSession);
553 } catch(anna::RuntimeException& ex) {
557 a_clientSessions.erase(ii);
563 void Engine::closeServer(Server* server, bool destroy)
564 throw(anna::RuntimeException) {
569 string msg("diameter::comm::Engine::closeServer | ");
570 msg += server->asString();
571 msg += " | Destroy: ";
572 msg += (destroy ? "yes" : "no");
573 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
575 anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
576 server_iterator ii = server_find(server->a_socket);
578 if(ii == server_end())
582 server->close(destroy);
586 releaseServer(server);
587 } catch(anna::RuntimeException& ex) {
595 void Engine::closeEntity(Entity* entity, bool destroy)
596 throw(anna::RuntimeException) {
601 string msg("diameter::comm::Engine::closeEntity | ");
602 msg += entity->asString();
603 msg += " | Destroy: ";
604 msg += (destroy ? "yes" : "no");
605 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
607 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
608 entity_iterator ii = entity_find(entity->a_socketListLiteral);
610 if(ii == entity_end())
614 entity->close(destroy);
618 if(!entity->idle()) { entity->setDeprecated(true); return; }
620 releaseEntity(entity);
621 } catch(anna::RuntimeException& ex) {
625 a_entities.erase(ii);
630 void Engine::closeLocalServer(LocalServer* localServer, bool destroy)
631 throw(anna::RuntimeException) {
632 if(localServer == NULL)
636 string msg("diameter::comm::Engine::closeLocalServer | ");
637 msg += localServer->asString();
638 msg += " | Destroy: ";
639 msg += (destroy ? "yes" : "no");
640 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
642 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
643 localServer_iterator ii = localServer_find(localServer->getKey());
645 if(ii == localServer_end())
649 localServer->close();
653 releaseLocalServer(localServer);
654 } catch(anna::RuntimeException& ex) {
658 a_localServers.erase(ii);
663 void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
664 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
665 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
667 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
668 closeEntity(entity(it), destroy);
671 void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
672 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
673 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
675 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
676 closeLocalServer(localServer(it), destroy);
679 void Engine::eraseDeprecatedIdleEntities() throw() {
680 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
683 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
686 if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
690 int Engine::getOTARequestsForEntities() const throw() {
693 for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
694 result += entity(it)->getOTARequests();
699 int Engine::getOTARequestsForLocalServers() const throw() {
702 for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
703 result += localServer(it)->getOTARequests();
709 void Engine::setRealm(const std::string & name) throw() {
710 a_realm = ((name != "") ? name : anna::functions::getDomainname());
714 void Engine::setHost(const std::string & name) throw() {
715 a_host = ((name != "") ? name : anna::functions::getHostname());
720 void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
721 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
723 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
724 entity(it)->raiseAutoRecovery(autoRecovery);
727 void Engine::do_stop()
729 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
730 close(true /* destroy */);
733 std::string Engine::asString(void) const throw() {
735 trace = "\n================================";
736 trace += "\nDiameter comm Engine information";
737 trace += "\n================================";
738 trace += "\nAutoBind: ";
739 trace += a_autoBind ? "yes" : "no";
740 trace += "\nMaxConnectionDelay: ";
741 trace += a_maxConnectionDelay.asString();
742 trace += "\nAvailable for entities: ";
743 trace += a_availableForEntities ? "yes" : "no";
744 trace += "\nAvailable for local servers: ";
745 trace += a_availableForLocalServers ? "yes" : "no";
746 trace += "\nOTA requests: ";
747 trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
748 trace += "\nOTA requests for entities: ";
749 trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
750 trace += "\nOTA requests for local servers: ";
751 trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
753 trace += "\nNumber of entities: ";
754 trace += anna::functions::asString(a_entities.size());
756 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
758 trace += entity(it)->asString();
762 trace += "\nNumber of LocalServers: ";
763 trace += anna::functions::asString(a_localServers.size());
765 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
767 trace += localServer(it)->asString();
774 anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const
776 parent = anna::app::Component::asXML(parent);
777 anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
778 result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
779 result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
780 result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
781 result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
782 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
783 result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
784 result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
785 result->createAttribute("NumberOfEntities", a_entities.size());
786 anna::xml::Node* entities = result->createChild("Engine.Entities");
788 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
789 entity(it)->asXML(entities);
791 result->createAttribute("NumberOfLocalServers", a_localServers.size());
792 anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
794 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
795 localServer(it)->asXML(localServers);
800 Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() {
801 return a_clientSessions.find(key);
804 Engine::server_iterator Engine::server_find(const server_key &key) throw() {
805 return a_servers.find(key);
808 Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() {
809 return a_entities.find(key);
812 Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() {
813 return a_localServers.find(key);
816 Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
818 dualList.push_back(socket_t(addr1, port1));
819 dualList.push_back(socket_t(addr2, port2));
820 return (getEntityKey(dualList));
823 Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() {
825 socket_v::const_iterator it;
826 socket_v::const_iterator it_min(v.begin());
827 socket_v::const_iterator it_max(v.end());
829 for(it = it_min; it != it_max; it++) {
830 result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
834 result.erase(result.size() - 1, 1); // remove last space
835 //return anna::functions::exclusiveHash(result);
840 void Engine::availabilityLostForEntities() throw() {
841 a_availableForEntities = false;
843 std::string msg = "diameter::comm::Engine { Realm: ";
845 msg += " } has lost its availability for entities";
846 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
849 OamModule &oamModule = OamModule::instantiate();
850 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
851 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities);
853 availabilityLostForEntities(this);
857 void Engine::availabilityRecoveredForEntities() throw() {
858 a_availableForEntities = true;
860 std::string msg = "diameter::comm::Engine { Realm: ";
862 msg += " } has recovered its availability for entities";
863 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
866 OamModule &oamModule = OamModule::instantiate();
867 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
868 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
870 availabilityRecoveredForEntities(this);
874 void Engine::availabilityLostForLocalServers() throw() {
875 a_availableForLocalServers = false;
877 std::string msg = "diameter::comm::Engine { Realm: ";
879 msg += " } has lost its availability for local servers";
880 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
883 OamModule &oamModule = OamModule::instantiate();
884 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
885 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
887 availabilityLostForLocalServers(this);
891 void Engine::availabilityRecoveredForLocalServers() throw() {
892 a_availableForLocalServers = true;
894 std::string msg = "diameter::comm::Engine { Realm: ";
896 msg += " } has recovered its availability for local servers";
897 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
900 OamModule &oamModule = OamModule::instantiate();
901 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
902 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
904 availabilityRecoveredForLocalServers(this);
908 bool Engine::refreshAvailabilityForEntities() throw() {
910 if(a_availableForEntities) { // check not-bound state for all client-sessions:
913 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
914 if(entity(it)->isAvailable()) { isolate = false; break; }
917 availabilityLostForEntities();
924 // Here not available
925 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
926 if(entity(it)->isAvailable()) {
927 availabilityRecoveredForEntities();
934 bool Engine::refreshAvailabilityForLocalServers() throw() {
936 if(a_availableForLocalServers) { // check not-bound state for all client-sessions:
939 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
940 if(localServer(it)->isAvailable()) { isolate = false; break; }
943 availabilityLostForLocalServers();
950 // Here not available
951 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
952 if(localServer(it)->isAvailable()) {
953 availabilityRecoveredForLocalServers();
961 void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
962 // Default DPA implementation:
964 // 'Disconnect-Peer-Answer' (282,answer)
965 // {Result-Code}...................................(268,0)
966 // {Origin-Host}...................................(264,0)
967 // {Origin-Realm}..................................(296,0)
968 // [Error-Message].................................(281,0)
969 // *[Failed-AVP]....................................(279,0)
971 anna::diameter::codec::Message diameterDPA;
972 anna::diameter::codec::Avp avpRC;
973 anna::diameter::codec::Avp avpOH;
974 anna::diameter::codec::Avp avpOR;
976 diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
977 diameterDPA.setVersion(1);
978 diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
979 diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
980 diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
982 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
983 avpRC.setMandatoryBit();
984 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
986 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
987 avpOH.setMandatoryBit();
988 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
990 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
991 avpOR.setMandatoryBit();
992 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
993 diameterDPA.addAvp(&avpRC);
994 diameterDPA.addAvp(&avpOH);
995 diameterDPA.addAvp(&avpOR);
997 dpa = diameterDPA.code();
998 } catch(anna::RuntimeException &ex) {
1004 void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
1005 // Default CEA implementation:
1007 // 'Capabilities-Exchange-Answer' (257,answer)
1008 // {Result-Code}...................................(268,0)
1009 // {Origin-Host}...................................(264,0)
1010 // {Origin-Realm}..................................(296,0)
1011 // 1*{Host-IP-Address}...............................(257,0)
1012 // {Vendor-Id}.....................................(266,0)
1013 // {Product-Name}..................................(269,0)
1014 // [Origin-State-Id]...............................(278,0)
1015 // [Error-Message].................................(281,0)
1016 // *[Failed-AVP]....................................(279,0)
1017 // *[Supported-Vendor-Id]...........................(265,0)
1018 // *[Auth-Application-Id]...........................(258,0)
1019 // *[Inband-Security-Id]............................(299,0)
1020 // *[Acct-Application-Id]...........................(259,0)
1021 // [Vendor-Specific-Application-Id]................(260,0)
1022 // [Firmware-Revision].............................(267,0)
1023 // *[AVP]...........................................(0,0)
1025 anna::diameter::codec::Message diameterCEA;
1026 anna::diameter::codec::Avp avpRC;
1027 anna::diameter::codec::Avp avpOH;
1028 anna::diameter::codec::Avp avpOR;
1030 diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1031 diameterCEA.setVersion(1);
1032 diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1033 diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1034 diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1036 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1037 avpRC.setMandatoryBit();
1038 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1040 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1041 avpOH.setMandatoryBit();
1042 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1044 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1045 avpOR.setMandatoryBit();
1046 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1047 diameterCEA.addAvp(&avpRC);
1048 diameterCEA.addAvp(&avpOH);
1049 diameterCEA.addAvp(&avpOR);
1051 std::string hostIP = anna::functions::getHostnameIP(); // Address
1052 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1054 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1055 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1057 std::string productName = "OCS Diameter Server"; // UTF8String
1058 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1060 cea = diameterCEA.code();
1061 } catch(anna::RuntimeException &ex) {
1067 void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
1068 // Default DWA implementation:
1070 // 'Device-Watchdog-Answer' (280,answer)
1071 // {Result-Code}...................................(268,0)
1072 // {Origin-Host}...................................(264,0)
1073 // {Origin-Realm}..................................(296,0)
1074 // [Error-Message].................................(281,0)
1075 // *[Failed-AVP]....................................(279,0)
1076 // [Origin-State-Id]...............................(278,0)
1078 anna::diameter::codec::Message diameterDWA;
1079 anna::diameter::codec::Avp avpRC;
1080 anna::diameter::codec::Avp avpOH;
1081 anna::diameter::codec::Avp avpOR;
1083 diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1084 diameterDWA.setVersion(1);
1085 diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr));
1086 diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr));
1087 diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr));
1089 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1090 avpRC.setMandatoryBit();
1091 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1093 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1094 avpOH.setMandatoryBit();
1095 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1097 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1098 avpOR.setMandatoryBit();
1099 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1100 diameterDWA.addAvp(&avpRC);
1101 diameterDWA.addAvp(&avpOH);
1102 diameterDWA.addAvp(&avpOR);
1104 dwa = diameterDWA.code();
1105 } catch(anna::RuntimeException &ex) {
1110 void Engine::resetStatistics() throw() {
1111 for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1112 server(it)->resetStatistics();
1114 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1115 localServer(it)->resetStatistics();