X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=source%2Fdiameter.comm%2FEngine.cpp;h=f860a15e5a1597a0b59cc5468fbf42f61ade68db;hb=HEAD;hp=53de6ac0a51e1570a24a235e0f131db6bf13ae23;hpb=129500a50678c43ff28fb0054d6197899b8c0b2c;p=anna.git diff --git a/source/diameter.comm/Engine.cpp b/source/diameter.comm/Engine.cpp index 53de6ac..f860a15 100644 --- a/source/diameter.comm/Engine.cpp +++ b/source/diameter.comm/Engine.cpp @@ -5,16 +5,17 @@ // See project site at http://redmine.teslayout.com/projects/anna-suite // // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // +// Standard +#include // rand() -#include +#include #include #include #include #include #include #include - #include #include #include @@ -29,64 +30,162 @@ #include #include #include +#include // STD #include using namespace std; -using namespace anna::diameter::comm; +using namespace anna::diameter; -Engine::Engine(const char *className) : +namespace anna { + namespace diameter { + namespace stack { + class Dictionary; + } + } +} + +comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtocolDictionary) : anna::app::Component(className), a_autoBind(true), a_availableForEntities(false), a_availableForLocalServers(false), - a_cer(true), - a_dwr(true), + a_client_cer(true), + a_client_dwr(true), // a_cea(true), // a_dwa(true), a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod), a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/), - a_numberOfClientSessionsPerServer(1) { + a_numberOfClientSessionsPerServer(1), + a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str(), baseProtocolDictionary) +{ anna::diameter::sccs::activate(); - a_realm = anna::functions::getDomainname(); - a_host = anna::functions::getHostname(); + a_originRealm = anna::functions::getDomainname(); + a_originHost = anna::functions::getHostname(); + a_ceaPathfile = ""; + + // Internal base protocol codec engine: + a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding +} + + +void comm::Engine::assertBaseProtocolHealth() const noexcept(false) { + if (!getBaseProtocolCodecEngine()->getDictionary()) + throw anna::RuntimeException("Invalid diameter::comm::Engine object: base protocol dictionary provided on constructor was NULL", ANNA_FILE_LOCATION); + // it would be interesting to check and identify certain base protocol elements in the dictionary ... + // but these things will be checked in runtime and will fail if they should. } -Server* Engine::allocateServer() throw() { return a_serversRecycler.create(); } -void Engine::releaseServer(Server *server) throw() { a_serversRecycler.release(server); } -ClientSession* Engine::allocateClientSession() throw() { return a_clientSessionsRecycler.create(); } -void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); } +comm::Server* comm::Engine::allocateServer() { return a_serversRecycler.create(); } +void comm::Engine::releaseServer(Server *server) { a_serversRecycler.release(server); } +comm::ClientSession* comm::Engine::allocateClientSession() { return a_clientSessionsRecycler.create(); } +void comm::Engine::releaseClientSession(ClientSession *clientSession) { a_clientSessionsRecycler.release(clientSession); } -void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) { +void comm::Engine::setClientCER(const anna::DataBlock & cer) noexcept(false) { if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) { throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION); } + a_client_cer = cer; +} + +void comm::Engine::setClientDWR(const anna::DataBlock & dwr) noexcept(false) { if(codec::functions::getCommandId(dwr) != helpers::base::COMMANDID__Device_Watchdog_Request) { throw anna::RuntimeException("The message provided as 'DWR' is not a Device-Watchdog-Request", ANNA_FILE_LOCATION); } - a_cer = cer; - a_dwr = dwr; + a_client_dwr = dwr; } -//void Engine::setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException) { -// if (codec::functions::getCommandId(cea) != helpers::base::COMMANDID__Capabilities_Exchange_Answer) { -// throw anna::RuntimeException("The message provided as 'CEA' is not a Capabilities-Exchange-Answer", ANNA_FILE_LOCATION); -// } -// -// if (codec::functions::getCommandId(dwa) != helpers::base::COMMANDID__Device_Watchdog_Answer) { -// throw anna::RuntimeException("The message provided as 'DWA' is not a Device-Watchdog-Answer", ANNA_FILE_LOCATION); -// } -// -// a_cea = cea; -// a_dwa = dwa; -//} +void comm::Engine::setClientCER(const std::string & cerPathfile) noexcept(false) { + + // Check for base protocol codec engine health: + assertBaseProtocolHealth(); -void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) { + anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine()); + try { + diameterCER.loadXMLFile(cerPathfile); + } catch(anna::RuntimeException &ex) { + anna::Logger::error("CER file not found or unable to parse. Nothing done !", ANNA_FILE_LOCATION); + return; + } + + // Assignment for internal encoded version: + setClientCER(diameterCER.code()); +} + +void comm::Engine::setClientDWR(const std::string & dwrPathfile) noexcept(false) { + + // Check for base protocol codec engine health: + assertBaseProtocolHealth(); + + anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine()); + std::string OH = getOriginHostName(); + std::string OR = getOriginRealmName(); + + if (!dwrPathfile.empty()) { + try { + diameterDWR.loadXMLFile(dwrPathfile); + } catch(anna::RuntimeException &ex) { + anna::Logger::error("DWR file not found or unable to parse. Nothing done !", ANNA_FILE_LOCATION); + return; + } + } + + // DEFAULT VERSION: + // Build DWR + // ::= < Diameter Header: 280, REQ > + // { Origin-Host } + // { Origin-Realm } + diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request); + diameterDWR.setApplicationId(0); // base protocol + diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH); + diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR); + + // Assignment for internal encoded version: + setClientDWR(diameterDWR.code()); +} + +void comm::Engine::setClientCER(const anna::U32 &applicationId) noexcept(false) { + + // Check for base protocol codec engine health: + assertBaseProtocolHealth(); + + // Build CER + // ::= < Diameter Header: 257, REQ > + // { Origin-Host } 264 diameterIdentity + // { Origin-Realm } 296 idem + // 1* { Host-IP-Address } 257, address + // { Vendor-Id } 266 Unsigned32 + // { Product-Name } 269 UTF8String + // [Origin-State-Id] 278 Unsigned32 + // * [ Supported-Vendor-Id ] 265 Unsigned32 + // * [ Auth-Application-Id ] 258 Unsigned32 + // * [Acct-Application-Id] 259 Unsigned32 + anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine()); + std::string OH = getOriginHostName(); + std::string OR = getOriginRealmName(); + std::string hostIP = anna::functions::getHostnameIP(); // Address + int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32 + std::string productName = "ANNA Diameter Client"; // UTF8String + + diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request); + diameterCER.setApplicationId(0); // base protocol + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR); + 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|" + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName); + diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId); + + // Assignment for internal encoded versions: + setClientCER(diameterCER.code()); +} + +void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) noexcept(false) { if(wp < ClientSession::DefaultWatchdogPeriod) { throw anna::RuntimeException(anna::functions::asString("Please set watchdog period over %s", ClientSession::DefaultWatchdogPeriod.asString().c_str()), ANNA_FILE_LOCATION); } @@ -94,7 +193,7 @@ void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::Runtime a_watchdogPeriod = wp; } -void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeException) { +void comm::Engine::checkEntityCollision(const socket_v &v) noexcept(false) { socket_v::const_iterator it; socket_v::const_iterator it_min(v.begin()); socket_v::const_iterator it_max(v.end()); @@ -115,8 +214,8 @@ void Engine::checkEntityCollision(const socket_v &v) throw(anna::RuntimeExceptio throw anna::RuntimeException("diameter::comm::Engine::checkEntityCollision: Provided addresses list (sockets) must have all items different", ANNA_FILE_LOCATION); } -Entity* Engine::createEntity(const socket_v & socketList, const std::string &description) -throw(anna::RuntimeException) { +comm::Entity* comm::Engine::createEntity(const socket_v & socketList, const std::string &description) +noexcept(false) { Entity* result(NULL); anna::Guard guard(this, "anna::diameter::comm::Engine::createEntity"); @@ -164,25 +263,26 @@ throw(anna::RuntimeException) { } -LocalServer *Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description) -throw(anna::RuntimeException) { +comm::LocalServer *comm::Engine::createLocalServer(const std::string & addr, int port, int maxConnections, const anna::Millisecond & allowedInactivityTime, int category, const std::string & description) +noexcept(false) { LocalServer* result(NULL); anna::Guard guard(this, "anna::diameter::comm::Engine::createLocalServer"); // Proteccion antes de reservar memoria para un LocalServer socket_t key(addr, port); - if(a_localServers.find(key) != a_localServers.end()) + if(a_localServers.find(key) != a_localServers.end()) { throw anna::RuntimeException("LocalServer is already reserved by a former created access point. Cannot create again", ANNA_FILE_LOCATION); + } if((result = allocateLocalServer()) == NULL) throw anna::RuntimeException("diameter::comm::Engine::allocateLocalServer returns NULL (perhaps virtual method was not implemented)", ANNA_FILE_LOCATION); - result->setEngine(this); // lo podia haber asignado en el allocateLocalServer (no importa) + result->setEngine(this); // only to refresh availability result->setKey(key); result->setCategory(category); result->setDescription(description); result->setAllowedInactivityTime(allowedInactivityTime); - result->initializeStatisticConcepts(); + result->initializeStatisticResources(); // Los saco con metodos virtuales readXXX del motor: // if ((a_cea.isEmpty()) || (a_dwa.isEmpty())) // throw anna::RuntimeException("Must define valid CEA and DWA messages by mean setCEAandDWA()", ANNA_FILE_LOCATION); @@ -194,13 +294,14 @@ throw(anna::RuntimeException) { ); // // Listen: (*) // /*if (a_autoListen) */result->enable(); // creates server socket + // ENABLE THE SERVER: if already open (other comm engine for another origin host in the same address), nothing done. But the reference to the server is doubled along 2 comm engines ... result->setMaxConnections(maxConnections); // (*) this enables the listen port ... or not return result; } -Entity* Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description) -throw(anna::RuntimeException) { +comm::Entity* comm::Engine::createEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, const std::string &description) +noexcept(false) { socket_v dualList; dualList.push_back(socket_t(addr1, port1)); dualList.push_back(socket_t(addr2, port2)); @@ -208,8 +309,8 @@ throw(anna::RuntimeException) { } -Server* Engine::createServer(Entity *entity, const socket_t & socket) -throw(anna::RuntimeException) { +comm::Server* comm::Engine::createServer(Entity *entity, const socket_t & socket) +noexcept(false) { Server* result(NULL); anna::Guard guard(this, "anna::diameter::comm::Engine::createServer"); @@ -222,9 +323,9 @@ throw(anna::RuntimeException) { result->a_parent = entity; result->a_socket = socket; result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */); - result->a_engine = this; - result->initializeStatisticConcepts(); + result->initializeStatisticResources(); + result->a_engine = this; for(int k = 0; k < a_numberOfClientSessionsPerServer; k++) result->addClientSession(k); @@ -240,8 +341,8 @@ throw(anna::RuntimeException) { // Lohacemos privado -ClientSession* Engine::createClientSession(Server *server, int socketId) -throw(anna::RuntimeException) { +comm::ClientSession* comm::Engine::createClientSession(Server *server, int socketId) +noexcept(false) { ClientSession* result(NULL); anna::Guard guard(this, "anna::diameter::comm::Engine::createClientSession"); @@ -252,16 +353,15 @@ throw(anna::RuntimeException) { result->initialize(); // warning: recycler does not initialize its objects and at least... // Assignments (it could be done at allocate): - if((a_cer.isEmpty()) || (a_dwr.isEmpty())) - throw anna::RuntimeException("Must define valid CER and DWR messages by mean setCERandDWR()", ANNA_FILE_LOCATION); + if((a_client_cer.isEmpty()) || (a_client_dwr.isEmpty())) + throw anna::RuntimeException("Must define valid CER and DWR messages by mean setClientCER and setClientDWR()", ANNA_FILE_LOCATION); - result->a_cer.setBody(a_cer); - result->a_dwr.setBody(a_dwr); + result->a_cer.setBody(a_client_cer); + result->a_dwr.setBody(a_client_dwr); result->setWatchdogPeriod(a_watchdogPeriod); result->a_parent = server; result->a_socketId = socketId; - result->initializeSequences(); // despu�s de asignar el server y el socketId (*) - // (*) 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))); + result->initializeSequences(); // despues de asignar el server y el socketId (sequences are seed-based by mean exclusive hash) result->a_engine = this; clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId); a_clientSessions.insert(clientSession_value_type(key, result)); @@ -286,7 +386,7 @@ throw(anna::RuntimeException) { } -bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeException) { +bool comm::Engine::broadcastEntities(const Message* message) noexcept(false) { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastEntities", ANNA_FILE_LOCATION)); bool allok = true; bool ok; @@ -305,7 +405,7 @@ bool Engine::broadcastEntities(const Message* message) throw(anna::RuntimeExcept return allok; } -bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeException) { +bool comm::Engine::broadcastLocalServers(const Message* message) noexcept(false) { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "broadcastLocalServers", ANNA_FILE_LOCATION)); bool allok = true; bool ok; @@ -324,7 +424,7 @@ bool Engine::broadcastLocalServers(const Message* message) throw(anna::RuntimeEx return allok; } -bool Engine::bind() throw(anna::RuntimeException) { +bool comm::Engine::bind() noexcept(false) { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "bind", ANNA_FILE_LOCATION)); bool result = true; // all OK return @@ -340,13 +440,13 @@ bool Engine::bind() throw(anna::RuntimeException) { return result; } -ClientSession* Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode) -throw(anna::RuntimeException) { +comm::ClientSession* comm::Engine::findClientSession(const std::string & addr, int port, int socketId, anna::Exception::Mode::_v emode) +noexcept(false) { return findClientSession(ClientSession::getKey(addr, port, socketId), emode); } -ClientSession* Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode) -throw(anna::RuntimeException) { +comm::ClientSession* comm::Engine::findClientSession(const std::string & key, anna::Exception::Mode::_v emode) +noexcept(false) { anna::Guard guard(this, "anna::diameter::comm::Engine::findClientSession"); clientSession_iterator ii = clientSession_find(key); @@ -369,8 +469,8 @@ throw(anna::RuntimeException) { } -Server* Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode) -throw(anna::RuntimeException) { +comm::Server* comm::Engine::findServer(const std::string & addr, int port, anna::Exception::Mode::_v emode) +noexcept(false) { anna::Guard guard(this, "anna::diameter::comm::Engine::findServer"); server_iterator ii = server_find(server_key(addr, port)); @@ -393,8 +493,8 @@ throw(anna::RuntimeException) { return NULL; } -Entity* Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode) -throw(anna::RuntimeException) { +comm::Entity* comm::Engine::findEntity(const socket_v & socketList, anna::Exception::Mode::_v emode) +noexcept(false) { anna::Guard guard(this, "anna::diameter::comm::Engine::findEntity"); entity_key key(getEntityKey(socketList)); entity_iterator ii = entity_find(key); @@ -417,8 +517,8 @@ throw(anna::RuntimeException) { return NULL; } -Entity* Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode) -throw(anna::RuntimeException) { +comm::Entity* comm::Engine::findEntity(const std::string & addr1, int port1, const std::string & addr2, int port2, anna::Exception::Mode::_v emode) +noexcept(false) { socket_v dualList; dualList.push_back(socket_t(addr1, port1)); dualList.push_back(socket_t(addr2, port2)); @@ -427,7 +527,7 @@ throw(anna::RuntimeException) { //Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode) -//throw(anna::RuntimeException) { +//noexcept(false) { // // Entity *entity; // @@ -440,8 +540,8 @@ throw(anna::RuntimeException) { //} -LocalServer* Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode) -throw(anna::RuntimeException) { +comm::LocalServer* comm::Engine::findLocalServer(const std::string & addr, int port, anna::Exception::Mode::_v emode) +noexcept(false) { anna::Guard guard(this, "anna::diameter::comm::Engine::findLocalServer"); socket_t key(addr, port); localServer_iterator ii = localServer_find(key); @@ -466,7 +566,7 @@ throw(anna::RuntimeException) { } -ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) throw(anna::RuntimeException) { +comm::ServerSession* comm::Engine::findServerSession(int socketId, anna::Exception::Mode::_v emode) noexcept(false) { anna::Guard guard(this, "anna::diameter::comm::Engine::findServerSession"); ServerSession *result; @@ -493,8 +593,8 @@ ServerSession* Engine::findServerSession(int socketId, anna::Exception::Mode::_v } -void Engine::closeClientSession(ClientSession* clientSession, bool destroy) -throw(anna::RuntimeException) { +void comm::Engine::closeClientSession(comm::ClientSession* clientSession, bool destroy) +noexcept(false) { if(clientSession == NULL) return; @@ -531,8 +631,8 @@ throw(anna::RuntimeException) { -void Engine::closeServer(Server* server, bool destroy) -throw(anna::RuntimeException) { +void comm::Engine::closeServer(comm::Server* server, bool destroy) +noexcept(false) { if(server == NULL) return; @@ -563,8 +663,8 @@ throw(anna::RuntimeException) { } -void Engine::closeEntity(Entity* entity, bool destroy) -throw(anna::RuntimeException) { +void comm::Engine::closeEntity(comm::Entity* entity, bool destroy) +noexcept(false) { if(entity == NULL) return; @@ -598,8 +698,8 @@ throw(anna::RuntimeException) { -void Engine::closeLocalServer(LocalServer* localServer, bool destroy) -throw(anna::RuntimeException) { +void comm::Engine::closeLocalServer(comm::LocalServer* localServer, bool destroy) +noexcept(false) { if(localServer == NULL) return; @@ -631,7 +731,7 @@ throw(anna::RuntimeException) { -void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) { +void comm::Engine::closeEntities(bool destroy) noexcept(false) { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeEntities", ANNA_FILE_LOCATION)); anna::Guard guard(this, "anna::diameter::comm::Engine::closeEntities"); @@ -639,7 +739,7 @@ void Engine::closeEntities(bool destroy) throw(anna::RuntimeException) { closeEntity(entity(it), destroy); } -void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) { +void comm::Engine::closeLocalServers(bool destroy) noexcept(false) { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "closeLocalServers", ANNA_FILE_LOCATION)); anna::Guard guard(this, "anna::diameter::comm::Engine::closeLocalServers"); @@ -647,7 +747,7 @@ void Engine::closeLocalServers(bool destroy) throw(anna::RuntimeException) { closeLocalServer(localServer(it), destroy); } -void Engine::eraseDeprecatedIdleEntities() throw() { +void comm::Engine::eraseDeprecatedIdleEntities() { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "eraseDeprecatedIdleEntities", ANNA_FILE_LOCATION)); Entity *et; @@ -658,7 +758,7 @@ void Engine::eraseDeprecatedIdleEntities() throw() { } } -int Engine::getOTARequestsForEntities() const throw() { +int comm::Engine::getOTARequestsForEntities() const { int result = 0; for(const_entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) @@ -667,7 +767,7 @@ int Engine::getOTARequestsForEntities() const throw() { return result; } -int Engine::getOTARequestsForLocalServers() const throw() { +int comm::Engine::getOTARequestsForLocalServers() const { int result = 0; for(const_localServer_iterator it = localServer_begin(), maxii = localServer_end(); it != maxii; it ++) @@ -677,31 +777,31 @@ int Engine::getOTARequestsForLocalServers() const throw() { } -void Engine::setRealm(const std::string & name) throw() { - a_realm = ((name != "") ? name : anna::functions::getDomainname()); +void comm::Engine::setOriginRealmName(const std::string & originRealmName) { + a_originRealm = ((originRealmName != "") ? originRealmName : anna::functions::getDomainname()); } -void Engine::setHost(const std::string & name) throw() { - a_host = ((name != "") ? name : anna::functions::getHostname()); +void comm::Engine::setOriginHostName(const std::string & originHostName) { + a_originHost = ((originHostName != "") ? originHostName : anna::functions::getHostname()); } -void Engine::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) { +void comm::Engine::raiseAutoRecovery(bool autoRecovery) noexcept(false) { LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "raiseAutoRecovery", ANNA_FILE_LOCATION)); for(entity_iterator it = entity_begin(), maxii = entity_end(); it != maxii; it ++) entity(it)->raiseAutoRecovery(autoRecovery); } -void Engine::do_stop() -throw() { +void comm::Engine::do_stop() +{ LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_stop", ANNA_FILE_LOCATION)); close(true /* destroy */); } -std::string Engine::asString(void) const throw() { +std::string comm::Engine::asString(void) const { std::string trace; trace = "\n================================"; trace += "\nDiameter comm Engine information"; @@ -742,8 +842,8 @@ std::string Engine::asString(void) const throw() { } -anna::xml::Node* Engine::asXML(anna::xml::Node* parent) const -throw() { +anna::xml::Node* comm::Engine::asXML(anna::xml::Node* parent) const +{ parent = anna::app::Component::asXML(parent); anna::xml::Node* result = parent->createChild("diameter.comm.Engine"); result->createAttribute("AutoBind", a_autoBind ? "yes" : "no"); @@ -765,33 +865,57 @@ throw() { for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++) localServer(it)->asXML(localServers); + // DRA Basics + // Aspect: + // + // + // + // + // + // + for (dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.begin(); drit != a_dr_dh_server_sessions.end(); drit++) { + anna::xml::Node* remoteRealm = result->createChild("Engine.RemoteRealm"); + remoteRealm->createAttribute("Name", drit->first); + dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second); + for (dh_server_sessions_it_t dhit = dhServerSessions->begin(); dhit != dhServerSessions->end(); dhit++) { + anna::xml::Node* remoteRealmHost = remoteRealm->createChild("Engine.RemoteRealmHost"); + remoteRealmHost->createAttribute("Name", dhit->first); + server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second); + for (server_sessions_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) { + std::string socket = anna::functions::socketLiteralAsString((*ssit)->getAddress(), (*ssit)->getPort()); + std::string ss_desc = socket + anna::functions::asString("|ServerSessionId:%d", (*ssit)->getSocketId()); + remoteRealmHost->createAttribute("ServerSession", ss_desc); + } + } + } + return result; } -Engine::clientSession_iterator Engine::clientSession_find(const clientSession_key &key) throw() { +comm::Engine::clientSession_iterator comm::Engine::clientSession_find(const clientSession_key &key) { return a_clientSessions.find(key); } -Engine::server_iterator Engine::server_find(const server_key &key) throw() { +comm::Engine::server_iterator comm::Engine::server_find(const server_key &key) { return a_servers.find(key); } -Engine::entity_iterator Engine::entity_find(const entity_key &key) throw() { +comm::Engine::entity_iterator comm::Engine::entity_find(const entity_key &key) { return a_entities.find(key); } -Engine::localServer_iterator Engine::localServer_find(const socket_t &key) throw() { +comm::Engine::localServer_iterator comm::Engine::localServer_find(const socket_t &key) { return a_localServers.find(key); } -Engine::entity_key Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const throw() { +comm::Engine::entity_key comm::Engine::getEntityKey(const std::string & addr1, int port1, const std::string & addr2, int port2) const { socket_v dualList; dualList.push_back(socket_t(addr1, port1)); dualList.push_back(socket_t(addr2, port2)); return (getEntityKey(dualList)); } -Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() { +comm::Engine::entity_key comm::Engine::getEntityKey(const socket_v &v) const { std::string result; socket_v::const_iterator it; socket_v::const_iterator it_min(v.begin()); @@ -803,16 +927,17 @@ Engine::entity_key Engine::getEntityKey(const socket_v &v) const throw() { } result.erase(result.size() - 1, 1); // remove last space - //return anna::functions::exclusiveHash(result); return result; } -void Engine::availabilityLostForEntities() throw() { +void comm::Engine::availabilityLostForEntities() { a_availableForEntities = false; LOGDEBUG( - std::string msg = "diameter::comm::Engine { Realm: "; - msg += getRealm(); + std::string msg = "diameter::comm::Engine { Origin-Realm: "; + msg += getOriginRealmName(); + msg += " | Origin-Host: "; + msg += getOriginHostName(); msg += " } has lost its availability for entities"; anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); @@ -820,16 +945,16 @@ void Engine::availabilityLostForEntities() throw() { OamModule &oamModule = OamModule::instantiate(); oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities); - // Virtual - availabilityLostForEntities(this); } -void Engine::availabilityRecoveredForEntities() throw() { +void comm::Engine::availabilityRecoveredForEntities() { a_availableForEntities = true; LOGDEBUG( - std::string msg = "diameter::comm::Engine { Realm: "; - msg += getRealm(); + std::string msg = "diameter::comm::Engine { Origin-Realm: "; + msg += getOriginRealmName(); + msg += " | Origin-Host: "; + msg += getOriginHostName(); msg += " } has recovered its availability for entities"; anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); @@ -837,16 +962,16 @@ void Engine::availabilityRecoveredForEntities() throw() { OamModule &oamModule = OamModule::instantiate(); oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities); - // Virtual - availabilityRecoveredForEntities(this); } -void Engine::availabilityLostForLocalServers() throw() { +void comm::Engine::availabilityLostForLocalServers() { a_availableForLocalServers = false; LOGDEBUG( - std::string msg = "diameter::comm::Engine { Realm: "; - msg += getRealm(); + std::string msg = "diameter::comm::Engine { Origin-Realm: "; + msg += getOriginRealmName(); + msg += " | Origin-Host: "; + msg += getOriginHostName(); msg += " } has lost its availability for local servers"; anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); @@ -854,16 +979,16 @@ void Engine::availabilityLostForLocalServers() throw() { OamModule &oamModule = OamModule::instantiate(); oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers); - // Virtual - availabilityLostForLocalServers(this); } -void Engine::availabilityRecoveredForLocalServers() throw() { +void comm::Engine::availabilityRecoveredForLocalServers() { a_availableForLocalServers = true; LOGDEBUG( - std::string msg = "diameter::comm::Engine { Realm: "; - msg += getRealm(); + std::string msg = "diameter::comm::Engine { Origin-Realm: "; + msg += getOriginRealmName(); + msg += " | Origin-Host: "; + msg += getOriginHostName(); msg += " } has recovered its availability for local servers"; anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); @@ -871,12 +996,10 @@ void Engine::availabilityRecoveredForLocalServers() throw() { OamModule &oamModule = OamModule::instantiate(); oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers); - // Virtual - availabilityRecoveredForLocalServers(this); } -bool Engine::refreshAvailabilityForEntities() throw() { +bool comm::Engine::refreshAvailabilityForEntities() { // Here available if(a_availableForEntities) { // check not-bound state for all client-sessions: bool isolate = true; @@ -902,7 +1025,7 @@ bool Engine::refreshAvailabilityForEntities() throw() { return false; } -bool Engine::refreshAvailabilityForLocalServers() throw() { +bool comm::Engine::refreshAvailabilityForLocalServers() { // Here available if(a_availableForLocalServers) { // check not-bound state for all client-sessions: bool isolate = true; @@ -929,7 +1052,17 @@ bool Engine::refreshAvailabilityForLocalServers() throw() { } -void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() { +void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) const { + + // Check for base protocol codec engine health: + try { + assertBaseProtocolHealth(); + } + catch(anna::RuntimeException &ex) { + ex.trace(); + return; + } + // Default DPA implementation: // // 'Disconnect-Peer-Answer' (282,answer) @@ -939,10 +1072,10 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() // [Error-Message].................................(281,0) // *[Failed-AVP]....................................(279,0) try { - anna::diameter::codec::Message diameterDPA; - anna::diameter::codec::Avp avpRC; - anna::diameter::codec::Avp avpOH; - anna::diameter::codec::Avp avpOR; + anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine()); // Message header diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer); diameterDPA.setVersion(1); @@ -956,23 +1089,49 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() // Origin-Host avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host); avpOH.setMandatoryBit(); - avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str()); + avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str()); // Origin-Realm avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm); avpOR.setMandatoryBit(); - avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str()); + avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str()); diameterDPA.addAvp(&avpRC); diameterDPA.addAvp(&avpOH); diameterDPA.addAvp(&avpOR); // Encode dpa = diameterDPA.code(); } catch(anna::RuntimeException &ex) { - ex.trace(); + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } } -void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() { +void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock &cer) const { + + // Check for base protocol codec engine health: + assertBaseProtocolHealth(); + + if (getCEA() != "") { + anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine()); + + try { + diameterCEA.loadXMLFile(getCEA()); + diameterCEA.setHopByHop(anna::diameter::codec::functions::getHopByHop(cer)); + diameterCEA.setEndToEnd(anna::diameter::codec::functions::getEndToEnd(cer)); + cea = diameterCEA.code(); + + } catch(anna::RuntimeException &ex) { + ex.trace(); + LOGWARNING(anna::Logger::warning("CEA file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION)); + //return anna::diameter::comm::Engine::readCEA(cea, cer); + // will fail with empty cea + } + + return; + } + // Default CEA implementation: // // 'Capabilities-Exchange-Answer' (257,answer) @@ -993,10 +1152,10 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() // [Firmware-Revision].............................(267,0) // *[AVP]...........................................(0,0) try { - anna::diameter::codec::Message diameterCEA; - anna::diameter::codec::Avp avpRC; - anna::diameter::codec::Avp avpOH; - anna::diameter::codec::Avp avpOR; + anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine()); // Message header diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer); diameterCEA.setVersion(1); @@ -1010,11 +1169,11 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() // Origin-Host avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host); avpOH.setMandatoryBit(); - avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str()); + avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str()); // Origin-Realm avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm); avpOR.setMandatoryBit(); - avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str()); + avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str()); diameterCEA.addAvp(&avpRC); diameterCEA.addAvp(&avpOH); diameterCEA.addAvp(&avpOR); @@ -1025,17 +1184,83 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32 diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId); // Product-Name - std::string productName = "OCS Diameter Server"; // UTF8String + std::string productName = "Diameter Server"; // UTF8String diameterCEA.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName); // Encode cea = diameterCEA.code(); } catch(anna::RuntimeException &ex) { + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } +} + +void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_desregister) { + + // Decode CER (TODO: use raw buffer helpers) + std::string destinationRealm, destinationHost; + codec::Message codecMsg(getBaseProtocolCodecEngine()); + try { + codecMsg.decode(a_client_cer); + destinationRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue(); + destinationHost = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->getValue(); + } + catch(anna::RuntimeException &ex) { ex.trace(); + return; + } + + dr_dh_server_sessions_nc_it_t drit = a_dr_dh_server_sessions.find(destinationRealm); + if (drit != a_dr_dh_server_sessions.end()) { // found + dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second); + dh_server_sessions_nc_it_t dhit = dhServerSessions->find(destinationHost); + if (dhit != dhServerSessions->end()) { // found + server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second); + if (register_or_desregister) { // REGISTER + serverSessions->push_back(ss); + } + else { // DESREGISTER + // Sequential search the specific server session: + for (server_sessions_nc_it_t ssit = serverSessions->begin(); ssit != serverSessions->end(); ssit++) { + if ((*ssit)->getAddress() != ss->getAddress()) continue; + if ((*ssit)->getPort() != ss->getPort()) continue; + if ((*ssit)->getSocketId() != ss->getSocketId()) continue; + serverSessions->erase(ssit); // if it is the last server session removed in DR-DH path, the XML will show this tree empty + // (it could be a hint for past registerings): + // + // + // + // + // + // + + break; + } + } + } + else { + if (!register_or_desregister) return; // strange (host not found) + server_sessions_vector_t ssVector; + ssVector.push_back(ss); + (*dhServerSessions)[destinationHost] = ssVector; + } + } + else { + if (!register_or_desregister) return; // strange (realm not found) + server_sessions_vector_t ssVector; + ssVector.push_back(ss); + dh_server_sessions_map_t dhServerSessions; + dhServerSessions[destinationHost] = ssVector; + a_dr_dh_server_sessions[destinationRealm] = dhServerSessions; } } +void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) const { + + // Check for base protocol codec engine health: + assertBaseProtocolHealth(); -void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() { // Default DWA implementation: // // 'Device-Watchdog-Answer' (280,answer) @@ -1046,16 +1271,16 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() // *[Failed-AVP]....................................(279,0) // [Origin-State-Id]...............................(278,0) try { - anna::diameter::codec::Message diameterDWA; - anna::diameter::codec::Avp avpRC; - anna::diameter::codec::Avp avpOH; - anna::diameter::codec::Avp avpOR; + anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine()); // Message header diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer); diameterDWA.setVersion(1); - diameterDWA.setApplicationId(codec::functions::getApplicationId(dwr)); - diameterDWA.setHopByHop(codec::functions::getHopByHop(dwr)); - diameterDWA.setEndToEnd(codec::functions::getEndToEnd(dwr)); + diameterDWA.setApplicationId(anna::diameter::codec::functions::getApplicationId(dwr)); + diameterDWA.setHopByHop(anna::diameter::codec::functions::getHopByHop(dwr)); + diameterDWA.setEndToEnd(anna::diameter::codec::functions::getEndToEnd(dwr)); // Result-Code avpRC.setId(anna::diameter::helpers::base::AVPID__Result_Code); avpRC.setMandatoryBit(); @@ -1063,22 +1288,25 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() // Origin-Host avpOH.setId(anna::diameter::helpers::base::AVPID__Origin_Host); avpOH.setMandatoryBit(); - avpOH.getDiameterIdentity()->fromPrintableString(a_host.c_str()); + avpOH.getDiameterIdentity()->fromPrintableString(a_originHost.c_str()); // Origin-Realm avpOR.setId(anna::diameter::helpers::base::AVPID__Origin_Realm); avpOR.setMandatoryBit(); - avpOR.getDiameterIdentity()->fromPrintableString(a_realm.c_str()); + avpOR.getDiameterIdentity()->fromPrintableString(a_originRealm.c_str()); diameterDWA.addAvp(&avpRC); diameterDWA.addAvp(&avpOH); diameterDWA.addAvp(&avpOR); // Encode dwa = diameterDWA.code(); } catch(anna::RuntimeException &ex) { - ex.trace(); + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } } -void Engine::resetStatistics() throw() { +void comm::Engine::resetStatistics() { for(server_iterator it = server_begin(), maxii = server_end(); it != maxii; it ++) server(it)->resetStatistics(); @@ -1086,4 +1314,58 @@ void Engine::resetStatistics() throw() { localServer(it)->resetStatistics(); } +void comm::Engine::do_initialize() noexcept(false) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "do_initialize", ANNA_FILE_LOCATION)); + LOGDEBUG(anna::Logger::debug("Nothing special done on component initialization", ANNA_FILE_LOCATION)); +} + +void comm::Engine::lazyInitialize() noexcept(false) { + LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Engine", "lazyInitialize", ANNA_FILE_LOCATION)); + anna::app::Component::initialize(); // this will invoke do_initialize +} + +// Not tested yet +const comm::Response* comm::Engine::sendRealmHost(const Message* message, const std::string &destinationRealm, const std::string &destinationHost) noexcept(false) { + + if (destinationRealm == "") + throw anna::RuntimeException("Unable to resolve the destination: empty provided Destination-Realm name", ANNA_FILE_LOCATION); + + // Get the server sessions which fulfill the restrictions: + dr_dh_server_sessions_it_t drit = a_dr_dh_server_sessions.find(destinationRealm); + if (drit == a_dr_dh_server_sessions.end()) + 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); + + dh_server_sessions_map_t *dhServerSessions = (dh_server_sessions_map_t *)&(drit->second); + // randomize between all server sessions for all hosts: + dh_server_sessions_nc_it_t dhit; + int hostsN = dhServerSessions->size(); + if (hostsN == 0) // avoids next division by cero (rand() % 0) + 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); + + if (destinationHost == "") { + // in this case, randomize the host: + dhit = dhServerSessions->begin(); + int randomHostIndx = rand() % hostsN; // number between 0 and the number of hosts - 1 + std::advance (dhit, randomHostIndx); + } + else { + dhit = dhServerSessions->find(destinationHost); + if (dhit == dhServerSessions->end()) + 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); + } + // Now, randomize the available server sessions: + server_sessions_vector_t *serverSessions = (server_sessions_vector_t *)&(dhit->second); + int serverSessionN = serverSessions->size(); + if (serverSessionN == 0) { // avoids next division by cero (rand() % 0) + std::string aux = ""; + if (destinationHost != "") { aux = "to Destination-Host '"; aux += destinationHost; aux += "'"; } + 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()); + throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); + } + + server_sessions_nc_it_t ssit = serverSessions->begin(); + int randomServerSessionIndx = rand() % serverSessionN; // number between 0 and the number of server sessions - 1 + std::advance (ssit, randomServerSessionIndx); + return (*ssit)->send(message); +}