1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
9 #include <stdlib.h> // rand()
12 #include <anna/diameter.comm/Engine.hpp>
13 #include <anna/core/tracing/Logger.hpp>
14 #include <anna/core/tracing/TraceMethod.hpp>
15 #include <anna/xml/Node.hpp>
16 #include <anna/comm/Network.hpp>
17 #include <anna/comm/Host.hpp>
18 #include <anna/comm/ClientSocket.hpp>
19 #include <anna/diameter.comm/Transport.hpp>
20 #include <anna/diameter.comm/Engine.hpp>
21 #include <anna/diameter.comm/Entity.hpp>
22 #include <anna/diameter.comm/Server.hpp>
23 #include <anna/diameter.comm/ClientSession.hpp>
24 #include <anna/diameter.comm/LocalServer.hpp>
25 #include <anna/core/functions.hpp>
26 #include <anna/diameter/internal/sccs.hpp>
27 #include <anna/diameter.comm/OamModule.hpp>
28 #include <anna/diameter/codec/functions.hpp>
29 #include <anna/diameter/helpers/base/functions.hpp>
30 #include <anna/diameter/helpers/helpers.hpp>
31 #include <anna/diameter/codec/Message.hpp>
32 #include <anna/diameter/codec/Avp.hpp>
33 #include <anna/diameter.comm/Response.hpp>
39 using namespace anna::diameter;
50 comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtocolDictionary) :
51 anna::app::Component(className),
53 a_availableForEntities(false),
54 a_availableForLocalServers(false),
59 a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
60 a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
61 a_numberOfClientSessionsPerServer(1),
62 a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str(), baseProtocolDictionary)
64 anna::diameter::sccs::activate();
65 a_originRealm = anna::functions::getDomainname();
66 a_originHost = anna::functions::getHostname();
68 // Internal base protocol codec engine:
69 a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding
73 void comm::Engine::assertBaseProtocolHealth() throw(anna::RuntimeException) {
74 if (!getBaseProtocolCodecEngine()->getDictionary())
75 throw anna::RuntimeException("Invalid diameter::comm::Engine object: base protocol dictionary provided on constructor was NULL", ANNA_FILE_LOCATION);
76 // it would be interesting to check and identify certain base protocol elements in the dictionary ...
77 // but these things will be checked in runtime and will fail if they should.
81 comm::Server* comm::Engine::allocateServer() throw() { return a_serversRecycler.create(); }
82 void comm::Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); }
83 comm::ClientSession* comm::Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); }
84 void comm::Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
87 void comm::Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
88 if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
89 throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
92 if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) {
93 throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION);
100 void comm::Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
102 // Check for base protocol codec engine health:
103 assertBaseProtocolHealth();
106 // <CER> ::= < Diameter Header: 257, REQ >
107 // { Origin-Host } 264 diameterIdentity
108 // { Origin-Realm } 296 idem
109 // 1* { Host-IP-Address } 257, address
110 // { Vendor-Id } 266 Unsigned32
111 // { Product-Name } 269 UTF8String
112 // [Origin-State-Id] 278 Unsigned32
113 // * [ Supported-Vendor-Id ] 265 Unsigned32
114 // * [ Auth-Application-Id ] 258 Unsigned32
115 // * [Acct-Application-Id] 259 Unsigned32
116 anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
117 int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32
118 std::string OH = getOriginHost();
119 std::string OR = getOriginRealm();
120 std::string hostIP = anna::functions::getHostnameIP(); // Address
121 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
122 std::string productName = "ANNA Diameter Client"; // UTF8String
123 bool encodeDefault = false;
127 diameterCER.loadXML(cer);
128 } catch(anna::RuntimeException &ex) {
130 encodeDefault = true;
131 LOGWARNING(anna::Logger::warning("CER file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
135 encodeDefault = true;
139 diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request);
140 diameterCER.setApplicationId(applicationId);
141 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
142 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
143 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>"
144 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
145 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
146 diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId);
150 // <DWR> ::= < Diameter Header: 280, REQ >
153 anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine());
154 encodeDefault = false;
158 diameterDWR.loadXML(dwr);
159 } catch(anna::RuntimeException &ex) {
161 encodeDefault = true;
162 LOGWARNING(anna::Logger::warning("DWR file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
166 encodeDefault = true;
170 diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request);
171 diameterDWR.setApplicationId(applicationId);
172 diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
173 diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
176 // Assignment for internal encoded versions:
177 setClientCERandDWR(diameterCER.code(), diameterDWR.code());
180 void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
181 if(wp < ClientSession::DefaultWatchdogPeriod) {
182 throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION);
185 a_watchdogPeriod = wp;
188 void comm::Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) {
189 socket_v::const_iterator it;
190 socket_v::const_iterator it_min(v.begin());
191 socket_v::const_iterator it_max(v.end());
193 for(it = it_min; it != it_max; it++) {
194 server_iterator ii = server_find(*it);
196 if(ii != server_end())
197 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Server is already reserved by a former created entity. Use another", ANNA_FILE_LOCATION);
200 // Check repetitions:
201 std::map < socket_t, int/*dummy*/ > auxMap;
203 for(it = it_min; it != it_max; it++) auxMap[(*it)] = 0;
205 if(auxMap.size() != v.size())
206 throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION);
209 comm::Entity* comm::Engine::createEntity(const socket_v & socketList, const std::string &description)
210 throw(anna::RuntimeException) {
211 Entity* result(NULL);
212 anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity");
214 if(socketList.size() == 0)
215 throw anna::RuntimeException("diameter::comm::Engine::createEntity Address/Port server list provided is empty", ANNA_FILE_LOCATION);
217 // Proteccion antes de reservar memoria para una entidad (allocateEntity):
218 checkEntityCollision(socketList);
220 if((result = allocateEntity()) == NULL)
221 throw anna::RuntimeException("diameter::comm::Engine::allocateEntity returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
224 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty servers vector.
225 // Assignments (it could be done at allocate):
226 result->setEngine(this); // lo podia haber asignado en el allocateEntity (no importa)
227 result->setMaxServers(socketList.size());
228 result->setDescription(description);
229 entity_key key(getEntityKey(socketList));
230 result->a_socketListLiteral = key;
231 // Create associated servers:
232 socket_v::const_iterator it;
233 socket_v::const_iterator it_min(socketList.begin());
234 socket_v::const_iterator it_max(socketList.end());
237 for(it = it_min; it != it_max; it++) {
238 result->addServer(*it);
240 if(count == 1) result->a_primarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
242 if(count == 2) result->a_secondarySocketLiteral = anna::functions::socketLiteralAsString((*it).first, (*it).second);
247 a_entities.insert(entity_value_type(key, result));
249 string msg("diameter::comm::Engine::createEntity | ");
250 msg += result->asString();
251 msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
252 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
258 comm::LocalServer *comm::Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description)
259 throw(anna::RuntimeException) {
260 LocalServer* result(NULL);
261 anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer");
262 // Proteccion antes de reservar memoria para un LocalServer
263 socket_t key(addr, port);
265 if(a_localServers.find(key) != a_localServers.end())
266 throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION);
268 if((result = allocateLocalServer()) == NULL)
269 throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION);
271 result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa)
273 result->setCategory(category);
274 result->setDescription(description);
275 result->setAllowedInactivityTime(allowedInactivityTime);
276 result->initializeStatisticResources();
277 // Los saco con metodos virtuales readXXX del motor:
278 // if ((a_cea.isEmpty()) || (a_dwa.isEmpty()))
279 // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION);
280 a_localServers.insert(localServer_value_type(key, result));
282 string msg("diameter::comm::Engine::createLocalServer | ");
283 msg += result->asString();
284 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
287 // /*if (a_autoListen) */result->enable(); // creates server socket
288 result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not
293 comm::Entity* comm::Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description)
294 throw(anna::RuntimeException) {
296 dualList.push_back(socket_t(addr1, port1));
297 dualList.push_back(socket_t(addr2, port2));
298 return (createEntity(dualList, description));
302 comm::Server* comm::Engine::createServer(Entity *entity, const socket_t & socket)
303 throw(anna::RuntimeException) {
304 Server* result(NULL);
305 anna::Guard guard(this, "anna::diameter::comm::Engine::createServer");
307 if((result = allocateServer()) == NULL)
308 throw anna::RuntimeException("diameter::comm::Engine::allocateServer returns NULL", ANNA_FILE_LOCATION);
311 result->initialize(); // warning: recycler does not initialize its objects and at least, is important to empty client-sessions vector.
312 // Assignments (it could be done at allocate):
313 result->a_parent = entity;
314 result->a_socket = socket;
315 result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
316 result->a_engine = this;
317 result->initializeStatisticResources();
319 for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
320 result->addClientSession(k);
322 a_servers.insert(server_value_type(socket, result));
323 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
324 // string msg("diameter::comm::Engine::resolveServer | ");
325 // msg += result->asString();
326 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
327 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
334 comm::ClientSession* comm::Engine::createClientSession(Server *server, int socketId)
335 throw(anna::RuntimeException) {
336 ClientSession* result(NULL);
337 anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession");
339 if((result = allocateClientSession()) == NULL)
340 throw anna::RuntimeException("diameter::comm::Engine::allocateClientSession returns NULL", ANNA_FILE_LOCATION);
343 result->initialize(); // warning: recycler does not initialize its objects and at least...
344 // Assignments (it could be done at allocate):
346 if((a_cer.isEmpty()) || (a_dwr.isEmpty()))
347 throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION);
349 result->a_cer.setBody(a_cer);
350 result->a_dwr.setBody(a_dwr);
351 result->setWatchdogPeriod(a_watchdogPeriod);
352 result->a_parent = server;
353 result->a_socketId = socketId;
354 result->initializeSequences(); // despu�s de asignar el server y el socketId (*)
355 // (*) 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)));
356 result->a_engine = this;
357 clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
358 a_clientSessions.insert(clientSession_value_type(key, result));
359 // LOGDEBUG( Lo comento, porque ya se tracea en el createEntity
360 // string msg("diameter::comm::Engine::createClientSession | ");
361 // msg += result->asString();
362 // msg += anna::functions::asText(" | AutoBind: ", a_autoBind);
363 // anna::Logger::debug(msg, ANNA_FILE_LOCATION);
366 anna::comm::Network& network = anna::comm::Network::instantiate();
367 result->a_server = network.resolveServer(server->getAddress().c_str(), server->getPort(), true /* autoRecovery */,
368 result->a_receiverFactory, &anna::diameter::comm::Transport::getFactory(),
369 anna::comm::Network::Port::Multiple, anna::comm::Network::DoConnect::No /* (*) */);
370 // Delay time on tcp connect:
371 result->a_server->setMaxConnectionDelay(a_maxConnectionDelay); // (*)
374 if(a_autoBind) result->bind();
380 bool comm::Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) {
381 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION));
385 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
387 ok = entity(it)->broadcast(message);
389 if(!ok) allok = false;
390 } catch(anna::RuntimeException &ex) {
399 bool comm::Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) {
400 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION));
404 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
406 ok = localServer(it)->broadcast(message);
408 if(!ok) allok = false;
409 } catch(anna::RuntimeException &ex) {
418 bool comm::Engine::bind() throw(anna::RuntimeException) {
419 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION));
420 bool result = true; // all OK return
422 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
425 } catch(anna::RuntimeException &ex) {
434 comm::ClientSession* comm::Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode)
435 throw(anna::RuntimeException) {
436 return findClientSession(ClientSession::getKey(addr, port, socketId), emode);
439 comm::ClientSession* comm::Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode)
440 throw(anna::RuntimeException) {
441 anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession");
442 clientSession_iterator ii = clientSession_find(key);
444 if(ii != clientSession_end())
445 return clientSession(ii);
447 if(emode != anna::Exception::Mode::Ignore) {
448 string msg("diameter::comm::Engine::findClientSession | [addr:port|socketId] = ");
450 msg += " | ClientSession not found";
451 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
453 if(emode == anna::Exception::Mode::Throw)
463 comm::Server* comm::Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
464 throw(anna::RuntimeException) {
465 anna::Guard guard(this, "anna::diameter::comm::Engine::findServer");
466 server_iterator ii = server_find(server_key(addr, port));
468 if(ii != server_end())
471 if(emode != anna::Exception::Mode::Ignore) {
472 string msg("diameter::comm::Engine::findServer | addr: ");
474 msg += anna::functions::asText(" | port: ", port);
475 msg += " | Server not found";
476 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
478 if(emode == anna::Exception::Mode::Throw)
487 comm::Entity* comm::Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode)
488 throw(anna::RuntimeException) {
489 anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity");
490 entity_key key(getEntityKey(socketList));
491 entity_iterator ii = entity_find(key);
493 if(ii != entity_end())
496 if(emode != anna::Exception::Mode::Ignore) {
497 string msg("diameter::comm::Engine::findEntity | socket list: ");
499 msg += " | Entity not found";
500 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
502 if(emode == anna::Exception::Mode::Throw)
511 comm::Entity* comm::Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode)
512 throw(anna::RuntimeException) {
514 dualList.push_back(socket_t(addr1, port1));
515 dualList.push_back(socket_t(addr2, port2));
516 return (findEntity(dualList, emode));
520 //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
521 //throw(anna::RuntimeException) {
525 // for (entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
526 // entity = entity(it);
527 // if (entity->getCategory() == category) return entity;
534 comm::LocalServer* comm::Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode)
535 throw(anna::RuntimeException) {
536 anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer");
537 socket_t key(addr, port);
538 localServer_iterator ii = localServer_find(key);
540 if(ii != localServer_end())
541 return localServer(ii);
543 if(emode != anna::Exception::Mode::Ignore) {
544 string msg("diameter::comm::Engine::findLocalServer | addr: ");
546 msg += anna::functions::asText(" | port: ", port);
547 msg += " | LocalServer not found";
548 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
550 if(emode == anna::Exception::Mode::Throw)
560 comm::ServerSession* comm::Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) {
561 anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession");
562 ServerSession *result;
564 // Search at each local server:
565 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) {
566 result = localServer(it)->findServerSession(socketId, anna::Exception::Mode::Ignore);
568 if(result) return result;
571 if(emode != anna::Exception::Mode::Ignore) {
572 string msg("diameter::comm::Engine::findServerSession | socketId: ");
573 msg += anna::functions::asString(socketId);
574 msg += " | ServerSession not found";
575 anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
577 if(emode == anna::Exception::Mode::Throw)
587 void comm::Engine::closeClientSession(comm::ClientSession* clientSession, bool destroy)
588 throw(anna::RuntimeException) {
589 if(clientSession == NULL)
593 string msg("diameter::comm::Engine::closeClientSession | ");
594 msg += clientSession->asString();
595 msg += " | Destroy: ";
596 msg += (destroy ? "yes" : "no");
597 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
599 anna::Guard guard(this, "anna::diameter::comm::Engine::closeClientSession");
600 clientSession_iterator ii = clientSession_find(clientSession->getKey());
602 if(ii == clientSession_end())
606 clientSession->setState(ClientSession::State::Closing);
608 if(destroy) clientSession->setAutoRecovery(false);
610 clientSession->unbind(destroy /* destroy needs to perform immediate close */);
614 releaseClientSession(clientSession);
615 } catch(anna::RuntimeException& ex) {
619 a_clientSessions.erase(ii);
625 void comm::Engine::closeServer(comm::Server* server, bool destroy)
626 throw(anna::RuntimeException) {
631 string msg("diameter::comm::Engine::closeServer | ");
632 msg += server->asString();
633 msg += " | Destroy: ";
634 msg += (destroy ? "yes" : "no");
635 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
637 anna::Guard guard(this, "anna::diameter::comm::Engine::closeServer");
638 server_iterator ii = server_find(server->a_socket);
640 if(ii == server_end())
644 server->close(destroy);
648 releaseServer(server);
649 } catch(anna::RuntimeException& ex) {
657 void comm::Engine::closeEntity(comm::Entity* entity, bool destroy)
658 throw(anna::RuntimeException) {
663 string msg("diameter::comm::Engine::closeEntity | ");
664 msg += entity->asString();
665 msg += " | Destroy: ";
666 msg += (destroy ? "yes" : "no");
667 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
669 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntity");
670 entity_iterator ii = entity_find(entity->a_socketListLiteral);
672 if(ii == entity_end())
676 entity->close(destroy);
680 if(!entity->idle()) { entity->setDeprecated(true); return; }
682 releaseEntity(entity);
683 } catch(anna::RuntimeException& ex) {
687 a_entities.erase(ii);
692 void comm::Engine::closeLocalServer(comm::LocalServer* localServer, bool destroy)
693 throw(anna::RuntimeException) {
694 if(localServer == NULL)
698 string msg("diameter::comm::Engine::closeLocalServer | ");
699 msg += localServer->asString();
700 msg += " | Destroy: ";
701 msg += (destroy ? "yes" : "no");
702 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
704 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServer");
705 localServer_iterator ii = localServer_find(localServer->getKey());
707 if(ii == localServer_end())
711 localServer->close();
715 releaseLocalServer(localServer);
716 } catch(anna::RuntimeException& ex) {
720 a_localServers.erase(ii);
725 void comm::Engine::closeEntities(bool destroy) throw(anna::RuntimeException) {
726 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION));
727 anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities");
729 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
730 closeEntity(entity(it), destroy);
733 void comm::Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) {
734 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION));
735 anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers");
737 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
738 closeLocalServer(localServer(it), destroy);
741 void comm::Engine::eraseDeprecatedIdleEntities() throw() {
742 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION));
745 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) {
748 if(et->isDeprecated() && et->idle()) closeEntity(et, true /* destroy */);
752 int comm::Engine::getOTARequestsForEntities() const throw() {
755 for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
756 result += entity(it)->getOTARequests();
761 int comm::Engine::getOTARequestsForLocalServers() const throw() {
764 for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
765 result += localServer(it)->getOTARequests();
771 void comm::Engine::setOriginRealm(const std::string & originRealm) throw() {
772 a_originRealm = ((originRealm != "") ? originRealm : anna::functions::getDomainname());
776 void comm::Engine::setOriginHost(const std::string & originHost) throw() {
777 a_originHost = ((originHost != "") ? originHost : anna::functions::getHostname());
782 void comm::Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
783 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION));
785 for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++)
786 entity(it)->raiseAutoRecovery(autoRecovery);
789 void comm::Engine::do_stop()
791 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION));
792 close(true /* destroy */);
795 std::string comm::Engine::asString(void) const throw() {
797 trace = "\n================================";
798 trace += "\nDiameter comm Engine information";
799 trace += "\n================================";
800 trace += "\nAutoBind: ";
801 trace += a_autoBind ? "yes" : "no";
802 trace += "\nMaxConnectionDelay: ";
803 trace += a_maxConnectionDelay.asString();
804 trace += "\nAvailable for entities: ";
805 trace += a_availableForEntities ? "yes" : "no";
806 trace += "\nAvailable for local servers: ";
807 trace += a_availableForLocalServers ? "yes" : "no";
808 trace += "\nOTA requests: ";
809 trace += anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : "");
810 trace += "\nOTA requests for entities: ";
811 trace += anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : "");
812 trace += "\nOTA requests for local servers: ";
813 trace += anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : "");
815 trace += "\nNumber of entities: ";
816 trace += anna::functions::asString(a_entities.size());
818 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++) {
820 trace += entity(it)->asString();
824 trace += "\nNumber of LocalServers: ";
825 trace += anna::functions::asString(a_localServers.size());
827 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) {
829 trace += localServer(it)->asString();
836 anna::xml::Node* comm::Engine::asXML(anna::xml::Node* parent) const
838 parent = anna::app::Component::asXML(parent);
839 anna::xml::Node* result = parent->createChild("diameter.comm.Engine");
840 result->createAttribute("AutoBind", a_autoBind ? "yes" : "no");
841 result->createAttribute("MaxConnectionDelay", a_maxConnectionDelay.asString());
842 result->createAttribute("AvailableForEntities", a_availableForEntities ? "yes" : "no");
843 result->createAttribute("AvailableForLocalServers", a_availableForLocalServers ? "yes" : "no");
844 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
845 result->createAttribute("OTArequestsForEntities", anna::functions::asString("%d%s", getOTARequestsForEntities(), idleForEntities() ? " (idle)" : ""));
846 result->createAttribute("OTArequestsForLocalServers", anna::functions::asString("%d%s", getOTARequestsForLocalServers(), idleForLocalServers() ? " (idle)" : ""));
847 result->createAttribute("NumberOfEntities", a_entities.size());
848 anna::xml::Node* entities = result->createChild("Engine.Entities");
850 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
851 entity(it)->asXML(entities);
853 result->createAttribute("NumberOfLocalServers", a_localServers.size());
854 anna::xml::Node* localServers = result->createChild("Engine.LocalServers");
856 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
857 localServer(it)->asXML(localServers);
861 // <Engine.RemoteRealm Name="afNodeHostRealm.com">
862 // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:4"/>
863 // </Engine.RemoteRealm>
864 // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
865 // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:6"/>
866 // </Engine.RemoteRealm>
867 for (dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.begin(); drit != a_dr_dh_server_sessions.end(); drit++) {
868 anna::xml::Node* remoteRealm = result->createChild("Engine.RemoteRealm");
869 remoteRealm->createAttribute("Name", drit->first);
870 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
871 for (dh_server_sessions_it_t dhit = dhServerSessions->begin(); dhit != dhServerSessions->end(); dhit++) {
872 anna::xml::Node* remoteRealmHost = remoteRealm->createChild("Engine.RemoteRealmHost");
873 remoteRealmHost->createAttribute("Name", dhit->first);
874 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
875 for (server_sessions_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
876 std::string socket = anna::functions::socketLiteralAsString((*ssit)->getAddress(), (*ssit)->getPort());
877 std::string ss_desc = socket + anna::functions::asString("|ServerSessionId:%d", (*ssit)->getSocketId());
878 remoteRealmHost->createAttribute("ServerSession", ss_desc);
886 comm::Engine::clientSession_iterator comm::Engine::clientSession_find(const clientSession_key &key) throw() {
887 return a_clientSessions.find(key);
890 comm::Engine::server_iterator comm::Engine::server_find(const server_key &key) throw() {
891 return a_servers.find(key);
894 comm::Engine::entity_iterator comm::Engine::entity_find(const entity_key &key) throw() {
895 return a_entities.find(key);
898 comm::Engine::localServer_iterator comm::Engine::localServer_find(const socket_t &key) throw() {
899 return a_localServers.find(key);
902 comm::Engine::entity_key comm::Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() {
904 dualList.push_back(socket_t(addr1, port1));
905 dualList.push_back(socket_t(addr2, port2));
906 return (getEntityKey(dualList));
909 comm::Engine::entity_key comm::Engine::getEntityKey(const socket_v &v) const throw() {
911 socket_v::const_iterator it;
912 socket_v::const_iterator it_min(v.begin());
913 socket_v::const_iterator it_max(v.end());
915 for(it = it_min; it != it_max; it++) {
916 result += anna::functions::socketLiteralAsString((*it).first, (*it).second);
920 result.erase(result.size() - 1, 1); // remove last space
921 //return anna::functions::exclusiveHash(result);
926 void comm::Engine::availabilityLostForEntities() throw() {
927 a_availableForEntities = false;
929 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
930 msg += getOriginRealm();
931 msg += " | Origin-Host: ";
932 msg += getOriginHost();
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 { Origin-Realm: ";
949 msg += getOriginRealm();
950 msg += " | Origin-Host: ";
951 msg += getOriginHost();
952 msg += " } has recovered its availability for entities";
953 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
956 OamModule &oamModule = OamModule::instantiate();
957 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName());
958 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities);
960 availabilityRecoveredForEntities(this);
964 void comm::Engine::availabilityLostForLocalServers() throw() {
965 a_availableForLocalServers = false;
967 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
968 msg += getOriginRealm();
969 msg += " | Origin-Host: ";
970 msg += getOriginHost();
971 msg += " } has lost its availability for local servers";
972 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
975 OamModule &oamModule = OamModule::instantiate();
976 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
977 oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers);
979 availabilityLostForLocalServers(this);
983 void comm::Engine::availabilityRecoveredForLocalServers() throw() {
984 a_availableForLocalServers = true;
986 std::string msg = "diameter::comm::Engine { Origin-Realm: ";
987 msg += getOriginRealm();
988 msg += " | Origin-Host: ";
989 msg += getOriginHost();
990 msg += " } has recovered its availability for local servers";
991 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
994 OamModule &oamModule = OamModule::instantiate();
995 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName());
996 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers);
998 availabilityRecoveredForLocalServers(this);
1002 bool comm::Engine::refreshAvailabilityForEntities() throw() {
1004 if(a_availableForEntities) { // check not-bound state for all client-sessions:
1005 bool isolate = true;
1007 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
1008 if(entity(it)->isAvailable()) { isolate = false; break; }
1011 availabilityLostForEntities();
1018 // Here not available
1019 for(const_entity_iterator it = entity_begin(); it != entity_end(); it++)
1020 if(entity(it)->isAvailable()) {
1021 availabilityRecoveredForEntities();
1028 bool comm::Engine::refreshAvailabilityForLocalServers() throw() {
1030 if(a_availableForLocalServers) { // check not-bound state for all client-sessions:
1031 bool isolate = true;
1033 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
1034 if(localServer(it)->isAvailable()) { isolate = false; break; }
1037 availabilityLostForLocalServers();
1044 // Here not available
1045 for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
1046 if(localServer(it)->isAvailable()) {
1047 availabilityRecoveredForLocalServers();
1055 void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
1057 // Check for base protocol codec engine health:
1058 assertBaseProtocolHealth();
1060 // Default DPA implementation:
1062 // 'Disconnect-Peer-Answer' (282,answer)
1063 // {Result-Code}...................................(268,0)
1064 // {Origin-Host}...................................(264,0)
1065 // {Origin-Realm}..................................(296,0)
1066 // [Error-Message].................................(281,0)
1067 // *[Failed-AVP]....................................(279,0)
1069 anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine());
1070 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1071 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1072 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1074 diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
1075 diameterDPA.setVersion(1);
1076 diameterDPA.setApplicationId(codec::functions::getApplicationId(dpr));
1077 diameterDPA.setHopByHop(codec::functions::getHopByHop(dpr));
1078 diameterDPA.setEndToEnd(codec::functions::getEndToEnd(dpr));
1080 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1081 avpRC.setMandatoryBit();
1082 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1084 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1085 avpOH.setMandatoryBit();
1086 avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
1088 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1089 avpOR.setMandatoryBit();
1090 avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
1091 diameterDPA.addAvp(&avpRC);
1092 diameterDPA.addAvp(&avpOH);
1093 diameterDPA.addAvp(&avpOR);
1095 dpa = diameterDPA.code();
1096 } catch(anna::RuntimeException &ex) {
1097 std::string msg = ex.getText();
1098 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)";
1099 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1100 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1105 void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() {
1107 // Check for base protocol codec engine health:
1108 assertBaseProtocolHealth();
1110 // Default CEA implementation:
1112 // 'Capabilities-Exchange-Answer' (257,answer)
1113 // {Result-Code}...................................(268,0)
1114 // {Origin-Host}...................................(264,0)
1115 // {Origin-Realm}..................................(296,0)
1116 // 1*{Host-IP-Address}...............................(257,0)
1117 // {Vendor-Id}.....................................(266,0)
1118 // {Product-Name}..................................(269,0)
1119 // [Origin-State-Id]...............................(278,0)
1120 // [Error-Message].................................(281,0)
1121 // *[Failed-AVP]....................................(279,0)
1122 // *[Supported-Vendor-Id]...........................(265,0)
1123 // *[Auth-Application-Id]...........................(258,0)
1124 // *[Inband-Security-Id]............................(299,0)
1125 // *[Acct-Application-Id]...........................(259,0)
1126 // [Vendor-Specific-Application-Id]................(260,0)
1127 // [Firmware-Revision].............................(267,0)
1128 // *[AVP]...........................................(0,0)
1130 anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
1131 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1132 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1133 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1135 diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
1136 diameterCEA.setVersion(1);
1137 diameterCEA.setApplicationId(codec::functions::getApplicationId(cer));
1138 diameterCEA.setHopByHop(codec::functions::getHopByHop(cer));
1139 diameterCEA.setEndToEnd(codec::functions::getEndToEnd(cer));
1141 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1142 avpRC.setMandatoryBit();
1143 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); // re-implementations could analyze CER to accept or not
1145 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1146 avpOH.setMandatoryBit();
1147 avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
1149 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1150 avpOR.setMandatoryBit();
1151 avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
1152 diameterCEA.addAvp(&avpRC);
1153 diameterCEA.addAvp(&avpOH);
1154 diameterCEA.addAvp(&avpOR);
1156 std::string hostIP = anna::functions::getHostnameIP(); // Address
1157 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str());
1159 int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
1160 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
1162 std::string productName = "Diameter Server"; // UTF8String
1163 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
1165 cea = diameterCEA.code();
1166 } catch(anna::RuntimeException &ex) {
1167 std::string msg = ex.getText();
1168 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)";
1169 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1170 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1174 void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) throw() {
1176 // Decode CER (TODO: use raw buffer helpers)
1177 std::string destinationRealm, destinationHost;
1178 codec::Message codecMsg(getBaseProtocolCodecEngine());
1180 codecMsg.decode(ss->a_cer);
1181 destinationRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue();
1182 destinationHost = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->getValue();
1184 catch(anna::RuntimeException &ex) {
1189 dr_dh_server_sessions_nc_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
1190 if (drit != a_dr_dh_server_sessions.end()) { // found
1191 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
1192 dh_server_sessions_nc_it_t dhit = dhServerSessions->find(destinationHost);
1193 if (dhit != dhServerSessions->end()) { // found
1194 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
1195 if (register_or_desregister) { // REGISTER
1196 serverSessions->push_back(ss);
1198 else { // DESREGISTER
1199 // Sequential search the specific server session:
1200 for (server_sessions_nc_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) {
1201 if ((*ssit)->getAddress() != ss->getAddress()) continue;
1202 if ((*ssit)->getPort() != ss->getPort()) continue;
1203 if ((*ssit)->getSocketId() != ss->getSocketId()) continue;
1204 serverSessions->erase(ssit); // if it is the last server session removed in DR-DH path, the XML will show this tree empty
1205 // (it could be a hint for past registerings):
1206 // <Engine.RemoteRealm Name="afNodeHostRealm.com">
1207 // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com"/>
1208 // </Engine.RemoteRealm>
1209 // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
1210 // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com"/>
1211 // </Engine.RemoteRealm>
1218 if (!register_or_desregister) return; // strange (host not found)
1219 server_sessions_vector_t ssVector;
1220 ssVector.push_back(ss);
1221 (*dhServerSessions)[destinationHost] = ssVector;
1225 if (!register_or_desregister) return; // strange (realm not found)
1226 server_sessions_vector_t ssVector;
1227 ssVector.push_back(ss);
1228 dh_server_sessions_map_t dhServerSessions;
1229 dhServerSessions[destinationHost] = ssVector;
1230 a_dr_dh_server_sessions[destinationRealm] = dhServerSessions;
1234 void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() {
1236 // Check for base protocol codec engine health:
1237 assertBaseProtocolHealth();
1239 // Default DWA implementation:
1241 // 'Device-Watchdog-Answer' (280,answer)
1242 // {Result-Code}...................................(268,0)
1243 // {Origin-Host}...................................(264,0)
1244 // {Origin-Realm}..................................(296,0)
1245 // [Error-Message].................................(281,0)
1246 // *[Failed-AVP]....................................(279,0)
1247 // [Origin-State-Id]...............................(278,0)
1249 anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine());
1250 anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
1251 anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
1252 anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
1254 diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
1255 diameterDWA.setVersion(1);
1256 diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr));
1257 diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr));
1258 diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr));
1260 avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code);
1261 avpRC.setMandatoryBit();
1262 avpRC.getUnsigned32()->setValue(helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS);
1264 avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host);
1265 avpOH.setMandatoryBit();
1266 avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str());
1268 avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm);
1269 avpOR.setMandatoryBit();
1270 avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str());
1271 diameterDWA.addAvp(&avpRC);
1272 diameterDWA.addAvp(&avpOH);
1273 diameterDWA.addAvp(&avpOR);
1275 dwa = diameterDWA.code();
1276 } catch(anna::RuntimeException &ex) {
1277 std::string msg = ex.getText();
1278 msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)";
1279 anna::Logger::error(msg, ANNA_FILE_LOCATION);
1280 //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1284 void comm::Engine::resetStatistics() throw() {
1285 for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++)
1286 server(it)->resetStatistics();
1288 for(localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++)
1289 localServer(it)->resetStatistics();
1292 void comm::Engine::do_initialize() throw(RuntimeException) {
1293 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION));
1294 LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION));
1297 void comm::Engine::lazyInitialize() throw(RuntimeException) {
1298 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION));
1299 anna::app::Component::initialize(); // this will invoke do_initialize
1303 const comm::Response* comm::Engine::sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost) throw(anna::RuntimeException) {
1305 if (destinationRealm == "")
1306 throw anna::RuntimeException("Unable to resolve the destination: empty provided Destination-Realm name", ANNA_FILE_LOCATION);
1308 // Get the server sessions which fulfill the restrictions:
1309 dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.find(destinationRealm);
1310 if (drit == a_dr_dh_server_sessions.end())
1311 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);
1313 dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second);
1314 // randomize between all server sessions for all hosts:
1315 dh_server_sessions_nc_it_t dhit;
1316 int hostsN = dhServerSessions->size();
1317 if (hostsN == 0) // avoids next division by cero (rand() % 0)
1318 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);
1320 if (destinationHost == "") {
1321 // in this case, randomize the host:
1322 dhit = dhServerSessions->begin();
1323 int randomHostIndx = rand() % hostsN; // number between 0 and the number of hosts - 1
1324 std::advance (dhit, randomHostIndx);
1327 dhit = dhServerSessions->find(destinationHost);
1328 if (dhit == dhServerSessions->end())
1329 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);
1332 // Now, randomize the available server sessions:
1333 server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second);
1334 int serverSessionN = serverSessions->size();
1335 if (serverSessionN == 0) { // avoids next division by cero (rand() % 0)
1336 std::string aux = "";
1337 if (destinationHost != "") { aux = "to Destination-Host '"; aux += destinationHost; aux += "'"; }
1338 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());
1339 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
1342 server_sessions_nc_it_t ssit = serverSessions->begin();
1343 int randomServerSessionIndx = rand() % serverSessionN; // number between 0 and the number of server sessions - 1
1344 std::advance (ssit, randomServerSessionIndx);
1345 return (*ssit)->send(message);