1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
9 #include <stdlib.h> // rand()
12 #include <anna/diameter.comm/Engine.hpp>
13 #include <anna/core/tracing/Logger.hpp>
14 #include <anna/core/tracing/TraceMethod.hpp>
15 #include <anna/xml/Node.hpp>
16 #include <anna/comm/Network.hpp>
17 #include <anna/comm/Host.hpp>
18 #include <anna/comm/ClientSocket.hpp>
20 #include <anna/diameter.comm/Transport.hpp>
21 #include <anna/diameter.comm/Engine.hpp>
22 #include <anna/diameter.comm/Entity.hpp>
23 #include <anna/diameter.comm/Server.hpp>
24 #include <anna/diameter.comm/ClientSession.hpp>
25 #include <anna/diameter.comm/LocalServer.hpp>
26 #include <anna/core/functions.hpp>
27 #include <anna/diameter/internal/sccs.hpp>
28 #include <anna/diameter.comm/OamModule.hpp>
29 #include <anna/diameter/codec/functions.hpp>
30 #include <anna/diameter/helpers/base/functions.hpp>
31 #include <anna/diameter/helpers/helpers.hpp>
32 #include <anna/diameter/codec/Message.hpp>
33 #include <anna/diameter/codec/Avp.hpp>
34 #include <anna/diameter.comm/Response.hpp>
40 using namespace anna::diameter;
51 comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtocolDictionary) :
52 anna::app::Component(className),
54 a_availableForEntities(false),
55 a_availableForLocalServers(false),
60 a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
61 a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
62 a_numberOfClientSessionsPerServer(1),
63 a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str())
65 anna::diameter::sccs::activate();
66 a_realm = anna::functions::getDomainname();
67 a_host = anna::functions::getHostname();
69 // Internal base protocol codec engine:
70 a_baseProtocolCodecEngine.setDictionary(baseProtocolDictionary);
71 a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding
75 void comm::Engine::assertBaseProtocolHealth() throw(anna::RuntimeException) {
76 if (!getBaseProtocolCodecEngine()->getDictionary())
77 throw anna::RuntimeException("Invalid diameter::comm::Engine object: base protocol dictionary provided on constructor was NULL", ANNA_FILE_LOCATION);
78 // it would be interesting to check and identify certain base protocol elements in the dictionary ...
79 // but these things will be checked in runtime and will fail if they should.
83 comm::Server* comm::Engine::allocateServer() throw() { return a_serversRecycler.create(); }
84 void comm::Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
85 comm::ClientSession* comm::Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
86 void comm::Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
89 void comm::Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
90 if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
91 throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
94 if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
95 throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
102 void comm::Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
104 // Check for base protocol codec engine health:
105 assertBaseProtocolHealth();
108 // <CER> ::= < Diameter Header: 257, REQ >
109 // { Origin-Host } 264 diameterIdentity
110 // { Origin-Realm } 296 idem
111 // 1* { Host-IP-Address } 257, address
112 // { Vendor-Id } 266 Unsigned32
113 // { Product-Name } 269 UTF8String
114 // [Origin-State-Id] 278 Unsigned32
115 // * [ Supported-Vendor-Id ] 265 Unsigned32
116 // * [ Auth-Application-Id ] 258 Unsigned32
117 // * [Acct-Application-Id] 259 Unsigned32
118 anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
119 int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32
120 std::string OH = getHost();
121 std::string OR = getRealm();
122 std::string hostIP = anna::functions::getHostnameIP(); // Address
123 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
124 std::string productName = "ANNA Diameter Client"; // UTF8String
125 bool encodeDefault = false;
129 diameterCER.loadXML(cer);
130 } catch(anna::RuntimeException &ex) {
132 encodeDefault = true;
133 LOGWARNING(anna::Logger::warning("CER file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
137 encodeDefault = true;
141 diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request);
142 diameterCER.setApplicationId(applicationId);
143 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
144 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
145 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str()); // supported by Address class, anyway is better to provide "1|<ip address>"
146 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
147 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
148 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId);
152 // <DWR> ::= < Diameter Header: 280, REQ >
155 anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine());
156 encodeDefault = false;
160 diameterDWR.loadXML(dwr);
161 } catch(anna::RuntimeException &ex) {
163 encodeDefault = true;
164 LOGWARNING(anna::Logger::warning("DWR file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
168 encodeDefault = true;
172 diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request);
173 diameterDWR.setApplicationId(applicationId);
174 diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
175 diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
178 // Assignment for internal encoded versions:
179 setClientCERandDWR(diameterCER.code(), diameterDWR.code());
182 void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
183 if(wp < ClientSession::DefaultWatchdogPeriod) {
184 throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
187 a_watchdogPeriod = wp;
190 void comm::Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
191 socket_v::const_iterator it;
192 socket_v::const_iterator it_min(v.begin());
193 socket_v::const_iterator it_max(v.end());
195 for(it = it_min; it != it_max; it++) {
196 server_iterator ii = server_find(*it);
198 if(ii != server_end())
199 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
202 // Check repetitions:
203 std::map < socket_t, int/*dummy*/ > auxMap;
205 for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
207 if(auxMap.size() != v.size())
208 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
211 comm::Entity* comm::Engine::createEntity(const socket_v & socketList, const std::string &description)
212 throw(anna::RuntimeException) {
213 Entity* result(NULL);
214 anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
216 if(socketList.size() == 0)
217 throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
219 // Proteccion antes de reservar memoria para una entidad (allocateEntity):
220 checkEntityCollision(socketList);
222 if((result = allocateEntity()) == NULL)
223 throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
226 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
227 // Assignments (it could be done at allocate):
228 result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
229 result->setMaxServers(socketList.size());
230 result->setDescription(description);
231 entity_key key(getEntityKey(socketList));
232 result->a_socketListLiteral = key;
233 // Create associated servers:
234 socket_v::const_iterator it;
235 socket_v::const_iterator it_min(socketList.begin());
236 socket_v::const_iterator it_max(socketList.end());
239 for(it = it_min; it != it_max; it++) {
240 result->addServer(*it);
242 if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
244 if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
249 a_entities.insert(entity_value_type(key, result));
251 string msg("diameter::comm::Engine::createEntity | ");
252 msg += result->asString();
253 msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
254 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
260 comm::LocalServer *comm::Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
261 throw(anna::RuntimeException) {
262 LocalServer* result(NULL);
263 anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
264 // Proteccion antes de reservar memoria para un LocalServer
265 socket_t key(addr, port);
267 if(a_localServers.find(key) != a_localServers.end())
268 throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
270 if((result = allocateLocalServer()) == NULL)
271 throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
273 result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa)
275 result->setCategory(category);
276 result->setDescription(description);
277 result->setAllowedInactivityTime(allowedInactivityTime);
278 result->initializeStatisticConcepts();
279 // Los saco con metodos virtuales readXXX del motor:
280 // if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
281 // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
282 a_localServers.insert(localServer_value_type(key, result));
284 string msg("diameter::comm::Engine::createLocalServer | ");
285 msg += result->asString();
286 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
289 // /*if (a_autoListen) */result->enable(); // creates server socket
290 result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
295 comm::Entity* comm::Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
296 throw(anna::RuntimeException) {
298 dualList.push_back(socket_t(addr1, port1));
299 dualList.push_back(socket_t(addr2, port2));
300 return (createEntity(dualList, description));
304 comm::Server* comm::Engine::createServer(Entity *entity, const socket_t & socket)
305 throw(anna::RuntimeException) {
306 Server* result(NULL);
307 anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
309 if((result = allocateServer()) == NULL)
310 throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
313 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
314 // Assignments (it could be done at allocate):
315 result->a_parent = entity;
316 result->a_socket = socket;
317 result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
318 result->a_engine = this;
319 result->initializeStatisticConcepts();
321 for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
322 result->addClientSession(k);
324 a_servers.insert(server_value_type(socket, result));
325 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
326 // string msg("diameter::comm::Engine::resolveServer | ");
327 // msg += result->asString();
328 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
329 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
336 comm::ClientSession* comm::Engine::createClientSession(Server *server, int socketId)
337 throw(anna::RuntimeException) {
338 ClientSession* result(NULL);
339 anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
341 if((result = allocateClientSession()) == NULL)
342 throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
345 result->initialize(); // warning: recycler does not initialize its objects and at least...
346 // Assignments (it could be done at allocate):
348 if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
349 throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
351 result->a_cer.setBody(a_cer);
352 result->a_dwr.setBody(a_dwr);
353 result->setWatchdogPeriod(a_watchdogPeriod);
354 result->a_parent = server;
355 result->a_socketId = socketId;
356 result->initializeSequences(); // despu�s de asignar el server y el socketId (*)
357 // (*) 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)));
358 result->a_engine = this;
359 clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
360 a_clientSessions.insert(clientSession_value_type(key, result));
361 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
362 // string msg("diameter::comm::Engine::createClientSession | ");
363 // msg += result->asString();
364 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
365 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
368 anna::comm::Network& network = anna::comm::Network::instantiate();
369 result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
370 result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
371 anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
372 // Delay time on tcp connect:
373 result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
376 if(a_autoBind) result->bind();
382 bool comm::Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
383 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
387 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
389 ok = entity(it)->broadcast(message);
391 if(!ok) allok = false;
392 } catch(anna::RuntimeException &ex) {
401 bool comm::Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
402 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
406 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
408 ok = localServer(it)->broadcast(message);
410 if(!ok) allok = false;
411 } catch(anna::RuntimeException &ex) {
420 bool comm::Engine::bind() throw(anna::RuntimeException) {
421 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
422 bool result = true; // all OK return
424 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
427 } catch(anna::RuntimeException &ex) {
436 comm::ClientSession* comm::Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
437 throw(anna::RuntimeException) {
438 return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
441 comm::ClientSession* comm::Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
442 throw(anna::RuntimeException) {
443 anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
444 clientSession_iterator ii = clientSession_find(key);
446 if(ii != clientSession_end())
447 return clientSession(ii);
449 if(emode != anna::Exception::Mode::Ignore) {
450 string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
452 msg += " | ClientSession not found";
453 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
455 if(emode == anna::Exception::Mode::Throw)
465 comm::Server* comm::Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
466 throw(anna::RuntimeException) {
467 anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
468 server_iterator ii = server_find(server_key(addr, port));
470 if(ii != server_end())
473 if(emode != anna::Exception::Mode::Ignore) {
474 string msg("diameter::comm::Engine::findServer | addr: ");
476 msg += anna::functions::asText(" | port: ", port);
477 msg += " | Server not found";
478 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
480 if(emode == anna::Exception::Mode::Throw)
489 comm::Entity* comm::Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
490 throw(anna::RuntimeException) {
491 anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
492 entity_key key(getEntityKey(socketList));
493 entity_iterator ii = entity_find(key);
495 if(ii != entity_end())
498 if(emode != anna::Exception::Mode::Ignore) {
499 string msg("diameter::comm::Engine::findEntity | socket list: ");
501 msg += " | Entity not found";
502 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
504 if(emode == anna::Exception::Mode::Throw)
513 comm::Entity* comm::Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
514 throw(anna::RuntimeException) {
516 dualList.push_back(socket_t(addr1, port1));
517 dualList.push_back(socket_t(addr2, port2));
518 return (findEntity(dualList, emode));
522 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
523 //throw(anna::RuntimeException) {
527 // for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
528 // entity = entity(it);
529 // if (entity->getCategory() == category) return entity;
536 comm::LocalServer* comm::Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
537 throw(anna::RuntimeException) {
538 anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
539 socket_t key(addr, port);
540 localServer_iterator ii = localServer_find(key);
542 if(ii != localServer_end())
543 return localServer(ii);
545 if(emode != anna::Exception::Mode::Ignore) {
546 string msg("diameter::comm::Engine::findLocalServer | addr: ");
548 msg += anna::functions::asText(" | port: ", port);
549 msg += " | LocalServer not found";
550 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
552 if(emode == anna::Exception::Mode::Throw)
562 comm::ServerSession* comm::Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
563 anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
564 ServerSession *result;
566 // Search at each local server:
567 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
568 result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
570 if(result) return result;
573 if(emode != anna::Exception::Mode::Ignore) {
574 string msg("diameter::comm::Engine::findServerSession | socketId: ");
575 msg += anna::functions::asString(socketId);
576 msg += " | ServerSession not found";
577 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
579 if(emode == anna::Exception::Mode::Throw)
589 void comm::Engine::closeClientSession(comm::ClientSession* clientSession, bool destroy)
590 throw(anna::RuntimeException) {
591 if(clientSession == NULL)
595 string msg("diameter::comm::Engine::closeClientSession | ");
596 msg += clientSession->asString();
597 msg += " | Destroy: ";
598 msg += (destroy ? "yes" : "no");
599 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
601 anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
602 clientSession_iterator ii = clientSession_find(clientSession->getKey());
604 if(ii == clientSession_end())
608 clientSession->setState(ClientSession::State::Closing);
610 if(destroy) clientSession->setAutoRecovery(false);
612 clientSession->unbind(destroy /* destroy needs to perform immediate close */);
616 releaseClientSession(clientSession);
617 } catch(anna::RuntimeException& ex) {
621 a_clientSessions.erase(ii);
627 void comm::Engine::closeServer(comm::Server* server, bool destroy)
628 throw(anna::RuntimeException) {
633 string msg("diameter::comm::Engine::closeServer | ");
634 msg += server->asString();
635 msg += " | Destroy: ";
636 msg += (destroy ? "yes" : "no");
637 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
639 anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
640 server_iterator ii = server_find(server->a_socket);
642 if(ii == server_end())
646 server->close(destroy);
650 releaseServer(server);
651 } catch(anna::RuntimeException& ex) {
659 void comm::Engine::closeEntity(comm::Entity* entity, bool destroy)
660 throw(anna::RuntimeException) {
665 string msg("diameter::comm::Engine::closeEntity | ");
666 msg += entity->asString();
667 msg += " | Destroy: ";
668 msg += (destroy ? "yes" : "no");
669 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
671 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
672 entity_iterator ii = entity_find(entity->a_socketListLiteral);
674 if(ii == entity_end())
678 entity->close(destroy);
682 if(!entity->idle()) { entity->setDeprecated(true); return; }
684 releaseEntity(entity);
685 } catch(anna::RuntimeException& ex) {
689 a_entities.erase(ii);
694 void comm::Engine::closeLocalServer(comm::LocalServer* localServer, bool destroy)
695 throw(anna::RuntimeException) {
696 if(localServer == NULL)
700 string msg("diameter::comm::Engine::closeLocalServer | ");
701 msg += localServer->asString();
702 msg += " | Destroy: ";
703 msg += (destroy ? "yes" : "no");
704 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
706 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
707 localServer_iterator ii = localServer_find(localServer->getKey());
709 if(ii == localServer_end())
713 localServer->close();
717 releaseLocalServer(localServer);
718 } catch(anna::RuntimeException& ex) {
722 a_localServers.erase(ii);
727 void comm::Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
728 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
729 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
731 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
732 closeEntity(entity(it), destroy);
735 void comm::Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
736 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
737 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
739 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
740 closeLocalServer(localServer(it), destroy);
743 void comm::Engine::eraseDeprecatedIdleEntities() throw() {
744 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
747 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
750 if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
754 int comm::Engine::getOTARequestsForEntities() const throw() {
757 for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
758 result += entity(it)->getOTARequests();
763 int comm::Engine::getOTARequestsForLocalServers() const throw() {
766 for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
767 result += localServer(it)->getOTARequests();
773 void comm::Engine::setRealm(const std::string & name) throw() {
774 a_realm = ((name != "") ? name : anna::functions::getDomainname());
778 void comm::Engine::setHost(const std::string & name) throw() {
779 a_host = ((name != "") ? name : anna::functions::getHostname());
784 void comm::Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
785 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
787 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
788 entity(it)->raiseAutoRecovery(autoRecovery);
791 void comm::Engine::do_stop()
793 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
794 close(true /* destroy */);
797 std::string comm::Engine::asString(void) const throw() {
799 trace = "\n================================";
800 trace += "\nDiameter comm Engine information";
801 trace += "\n================================";
802 trace += "\nAutoBind: ";
803 trace += a_autoBind ? "yes" : "no";
804 trace += "\nMaxConnectionDelay: ";
805 trace += a_maxConnectionDelay.asString();
806 trace += "\nAvailable for entities: ";
807 trace += a_availableForEntities ? "yes" : "no";
808 trace += "\nAvailable for local servers: ";
809 trace += a_availableForLocalServers ? "yes" : "no";
810 trace += "\nOTA requests: ";
811 trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
812 trace += "\nOTA requests for entities: ";
813 trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
814 trace += "\nOTA requests for local servers: ";
815 trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
817 trace += "\nNumber of entities: ";
818 trace += anna::functions::asString(a_entities.size());
820 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
822 trace += entity(it)->asString();
826 trace += "\nNumber of LocalServers: ";
827 trace += anna::functions::asString(a_localServers.size());
829 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
831 trace += localServer(it)->asString();
838 anna::xml::Node* comm::Engine::asXML(anna::xml::Node* parent) const
840 parent = anna::app::Component::asXML(parent);
841 anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
842 result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
843 result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
844 result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
845 result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
846 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
847 result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
848 result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
849 result->createAttribute("NumberOfEntities", a_entities.size());
850 anna::xml::Node* entities = result->createChild("Engine.Entities");
852 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
853 entity(it)->asXML(entities);
855 result->createAttribute("NumberOfLocalServers", a_localServers.size());
856 anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
858 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
859 localServer(it)->asXML(localServers);
863 // <Engine.RemoteRealm Name="afNodeHostRealm.com">
864 // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:4"/>
865 // </Engine.RemoteRealm>
866 // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
867 // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:6"/>
868 // </Engine.RemoteRealm>
869 for (dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.begin(); drit != a_dr_dh_server_sessions.end(); drit++) {
870 anna::xml::Node* remoteRealm = result->createChild("Engine.RemoteRealm");
871 remoteRealm->createAttribute("Name", drit->first);
872 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
873 for (dh_server_sessions_it_t dhit = dhServerSessions->begin(); dhit != dhServerSessions->end(); dhit++) {
874 anna::xml::Node* remoteRealmHost = remoteRealm->createChild("Engine.RemoteRealmHost");
875 remoteRealmHost->createAttribute("Name", dhit->first);
876 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
877 for (server_sessions_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
878 std::string socket = anna::functions::socketLiteralAsString((*ssit)->getAddress(), (*ssit)->getPort());
879 std::string ss_desc = socket + anna::functions::asString("|ServerSessionId:%d", (*ssit)->getSocketId());
880 remoteRealmHost->createAttribute("ServerSession", ss_desc);
888 comm::Engine::clientSession_iterator comm::Engine::clientSession_find(const clientSession_key &key) throw() {
889 return a_clientSessions.find(key);
892 comm::Engine::server_iterator comm::Engine::server_find(const server_key &key) throw() {
893 return a_servers.find(key);
896 comm::Engine::entity_iterator comm::Engine::entity_find(const entity_key &key) throw() {
897 return a_entities.find(key);
900 comm::Engine::localServer_iterator comm::Engine::localServer_find(const socket_t &key) throw() {
901 return a_localServers.find(key);
904 comm::Engine::entity_key comm::Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
906 dualList.push_back(socket_t(addr1, port1));
907 dualList.push_back(socket_t(addr2, port2));
908 return (getEntityKey(dualList));
911 comm::Engine::entity_key comm::Engine::getEntityKey(const socket_v &v) const throw() {
913 socket_v::const_iterator it;
914 socket_v::const_iterator it_min(v.begin());
915 socket_v::const_iterator it_max(v.end());
917 for(it = it_min; it != it_max; it++) {
918 result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
922 result.erase(result.size() - 1, 1); // remove last space
923 //return anna::functions::exclusiveHash(result);
928 void comm::Engine::availabilityLostForEntities() throw() {
929 a_availableForEntities = false;
931 std::string msg = "diameter::comm::Engine { Realm: ";
933 msg += " } has lost its availability for entities";
934 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
937 OamModule &oamModule = OamModule::instantiate();
938 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
939 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities);
941 availabilityLostForEntities(this);
945 void comm::Engine::availabilityRecoveredForEntities() throw() {
946 a_availableForEntities = true;
948 std::string msg = "diameter::comm::Engine { Realm: ";
950 msg += " } has recovered its availability for entities";
951 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
954 OamModule &oamModule = OamModule::instantiate();
955 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
956 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
958 availabilityRecoveredForEntities(this);
962 void comm::Engine::availabilityLostForLocalServers() throw() {
963 a_availableForLocalServers = false;
965 std::string msg = "diameter::comm::Engine { Realm: ";
967 msg += " } has lost its availability for local servers";
968 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
971 OamModule &oamModule = OamModule::instantiate();
972 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
973 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
975 availabilityLostForLocalServers(this);
979 void comm::Engine::availabilityRecoveredForLocalServers() throw() {
980 a_availableForLocalServers = true;
982 std::string msg = "diameter::comm::Engine { Realm: ";
984 msg += " } has recovered its availability for local servers";
985 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
988 OamModule &oamModule = OamModule::instantiate();
989 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
990 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
992 availabilityRecoveredForLocalServers(this);
996 bool comm::Engine::refreshAvailabilityForEntities() throw() {
998 if(a_availableForEntities) { // check not-bound state for all client-sessions:
1001 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
1002 if(entity(it)->isAvailable()) { isolate = false; break; }
1005 availabilityLostForEntities();
1012 // Here not available
1013 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
1014 if(entity(it)->isAvailable()) {
1015 availabilityRecoveredForEntities();
1022 bool comm::Engine::refreshAvailabilityForLocalServers() throw() {
1024 if(a_availableForLocalServers) { // check not-bound state for all client-sessions:
1025 bool isolate = true;
1027 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
1028 if(localServer(it)->isAvailable()) { isolate = false; break; }
1031 availabilityLostForLocalServers();
1038 // Here not available
1039 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
1040 if(localServer(it)->isAvailable()) {
1041 availabilityRecoveredForLocalServers();
1049 void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
1051 // Check for base protocol codec engine health:
1052 assertBaseProtocolHealth();
1054 // Default DPA implementation:
1056 // 'Disconnect-Peer-Answer' (282,answer)
1057 // {Result-Code}...................................(268,0)
1058 // {Origin-Host}...................................(264,0)
1059 // {Origin-Realm}..................................(296,0)
1060 // [Error-Message].................................(281,0)
1061 // *[Failed-AVP]....................................(279,0)
1063 anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine());
1064 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1065 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1066 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1068 diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
1069 diameterDPA.setVersion(1);
1070 diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
1071 diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
1072 diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
1074 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1075 avpRC.setMandatoryBit();
1076 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1078 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1079 avpOH.setMandatoryBit();
1080 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1082 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1083 avpOR.setMandatoryBit();
1084 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1085 diameterDPA.addAvp(&avpRC);
1086 diameterDPA.addAvp(&avpOH);
1087 diameterDPA.addAvp(&avpOR);
1089 dpa = diameterDPA.code();
1090 } catch(anna::RuntimeException &ex) {
1091 std::string msg = ex.getText();
1092 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)";
1093 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1094 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1099 void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
1101 // Check for base protocol codec engine health:
1102 assertBaseProtocolHealth();
1104 // Default CEA implementation:
1106 // 'Capabilities-Exchange-Answer' (257,answer)
1107 // {Result-Code}...................................(268,0)
1108 // {Origin-Host}...................................(264,0)
1109 // {Origin-Realm}..................................(296,0)
1110 // 1*{Host-IP-Address}...............................(257,0)
1111 // {Vendor-Id}.....................................(266,0)
1112 // {Product-Name}..................................(269,0)
1113 // [Origin-State-Id]...............................(278,0)
1114 // [Error-Message].................................(281,0)
1115 // *[Failed-AVP]....................................(279,0)
1116 // *[Supported-Vendor-Id]...........................(265,0)
1117 // *[Auth-Application-Id]...........................(258,0)
1118 // *[Inband-Security-Id]............................(299,0)
1119 // *[Acct-Application-Id]...........................(259,0)
1120 // [Vendor-Specific-Application-Id]................(260,0)
1121 // [Firmware-Revision].............................(267,0)
1122 // *[AVP]...........................................(0,0)
1124 anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
1125 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1126 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1127 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1129 diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1130 diameterCEA.setVersion(1);
1131 diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1132 diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1133 diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1135 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1136 avpRC.setMandatoryBit();
1137 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1139 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1140 avpOH.setMandatoryBit();
1141 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1143 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1144 avpOR.setMandatoryBit();
1145 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1146 diameterCEA.addAvp(&avpRC);
1147 diameterCEA.addAvp(&avpOH);
1148 diameterCEA.addAvp(&avpOR);
1150 std::string hostIP = anna::functions::getHostnameIP(); // Address
1151 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1153 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1154 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1156 std::string productName = "OCS Diameter Server"; // UTF8String
1157 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1159 cea = diameterCEA.code();
1160 } catch(anna::RuntimeException &ex) {
1161 std::string msg = ex.getText();
1162 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)";
1163 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1164 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1168 void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw() {
1170 // Decode CER (TODO: use raw buffer helpers)
1171 std::string destinationRealm, destinationHost;
1172 codec::Message codecMsg(getBaseProtocolCodecEngine());
1174 codecMsg.decode(ss->a_cer);
1175 destinationRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
1176 destinationHost = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->getValue();
1178 catch(anna::RuntimeException &ex) {
1183 dr_dh_server_sessions_nc_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
1184 if (drit != a_dr_dh_server_sessions.end()) { // found
1185 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
1186 dh_server_sessions_nc_it_t dhit = dhServerSessions->find(destinationHost);
1187 if (dhit != dhServerSessions->end()) { // found
1188 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
1189 if (register_or_desregister) { // REGISTER
1190 serverSessions->push_back(ss);
1192 else { // DESREGISTER
1193 // Sequential search the specific server session:
1194 for (server_sessions_nc_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
1195 if ((*ssit)->getAddress() != ss->getAddress()) continue;
1196 if ((*ssit)->getPort() != ss->getPort()) continue;
1197 if ((*ssit)->getSocketId() != ss->getSocketId()) continue;
1198 serverSessions->erase(ssit); // if it is the last server session removed in DR-DH path, the XML will show this tree empty
1199 // (it could be a hint for past registerings):
1200 // <Engine.RemoteRealm Name="afNodeHostRealm.com">
1201 // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com"/>
1202 // </Engine.RemoteRealm>
1203 // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
1204 // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com"/>
1205 // </Engine.RemoteRealm>
1212 if (!register_or_desregister) return; // strange (host not found)
1213 server_sessions_vector_t ssVector;
1214 ssVector.push_back(ss);
1215 (*dhServerSessions)[destinationHost] = ssVector;
1219 if (!register_or_desregister) return; // strange (realm not found)
1220 server_sessions_vector_t ssVector;
1221 ssVector.push_back(ss);
1222 dh_server_sessions_map_t dhServerSessions;
1223 dhServerSessions[destinationHost] = ssVector;
1224 a_dr_dh_server_sessions[destinationRealm] = dhServerSessions;
1228 void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
1230 // Check for base protocol codec engine health:
1231 assertBaseProtocolHealth();
1233 // Default DWA implementation:
1235 // 'Device-Watchdog-Answer' (280,answer)
1236 // {Result-Code}...................................(268,0)
1237 // {Origin-Host}...................................(264,0)
1238 // {Origin-Realm}..................................(296,0)
1239 // [Error-Message].................................(281,0)
1240 // *[Failed-AVP]....................................(279,0)
1241 // [Origin-State-Id]...............................(278,0)
1243 anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine());
1244 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1245 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1246 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1248 diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1249 diameterDWA.setVersion(1);
1250 diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr));
1251 diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr));
1252 diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr));
1254 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1255 avpRC.setMandatoryBit();
1256 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1258 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1259 avpOH.setMandatoryBit();
1260 avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str());
1262 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1263 avpOR.setMandatoryBit();
1264 avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str());
1265 diameterDWA.addAvp(&avpRC);
1266 diameterDWA.addAvp(&avpOH);
1267 diameterDWA.addAvp(&avpOR);
1269 dwa = diameterDWA.code();
1270 } catch(anna::RuntimeException &ex) {
1271 std::string msg = ex.getText();
1272 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)";
1273 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1274 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1278 void comm::Engine::resetStatistics() throw() {
1279 for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1280 server(it)->resetStatistics();
1282 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1283 localServer(it)->resetStatistics();
1286 void comm::Engine::do_initialize() throw(RuntimeException) {
1287 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
1288 LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
1291 void comm::Engine::lazyInitialize() throw(RuntimeException) {
1292 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
1293 anna::app::Component::initialize(); // this will invoke do_initialize
1297 const comm::Response* comm::Engine::sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost) throw(anna::RuntimeException) {
1299 if (destinationRealm == "")
1300 throw anna::RuntimeException("Unable to resolve the destination: empty provided Destination-Realm name", ANNA_FILE_LOCATION);
1302 // Get the server sessions which fulfill the restrictions:
1303 dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
1304 if (drit == a_dr_dh_server_sessions.end())
1305 throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: Destination-Realm name is not registered (no remote clients have been connected to '%s')", destinationRealm.c_str()), ANNA_FILE_LOCATION);
1307 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
1308 // randomize between all server sessions for all hosts:
1309 dh_server_sessions_nc_it_t dhit;
1310 int hostsN = dhServerSessions->size();
1311 if (hostsN == 0) // avoids next division by cero (rand() % 0)
1312 throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: neither Destination-Host currently connected to Destination-Realm '%s'", destinationRealm.c_str()), ANNA_FILE_LOCATION);
1314 if (destinationHost == "") {
1315 // in this case, randomize the host:
1316 dhit = dhServerSessions->begin();
1317 int randomHostIndx = rand() % hostsN; // number between 0 and the number of hosts - 1
1318 std::advance (dhit, randomHostIndx);
1321 dhit = dhServerSessions->find(destinationHost);
1322 if (dhit == dhServerSessions->end())
1323 throw anna::RuntimeException(anna::functions::asString("Unable to resolve the destination: Destination-Host '%s' is not registered for Destination-Realm '%s'", destinationHost.c_str(), destinationRealm.c_str()), ANNA_FILE_LOCATION);
1326 // Now, randomize the available server sessions:
1327 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
1328 int serverSessionN = serverSessions->size();
1329 if (serverSessionN == 0) { // avoids next division by cero (rand() % 0)
1330 std::string aux = "";
1331 if (destinationHost != "") { aux = "to Destination-Host '"; aux += destinationHost; aux += "'"; }
1332 std::string msg = anna::functions::asString("Unable to resolve the destination: neither server session currently connected%s within Destination-Realm '%s'", aux.c_str(), destinationRealm.c_str());
1333 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1336 server_sessions_nc_it_t ssit = serverSessions->begin();
1337 int randomServerSessionIndx = rand() % serverSessionN; // number between 0 and the number of server sessions - 1
1338 std::advance (ssit, randomServerSessionIndx);
1339 return (*ssit)->send(message);