-// ANNA - Anna is Not Nothingness Anymore
-//
-// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-//
-// http://redmine.teslayout.com/projects/anna-suite
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: eduardo.ramos.testillano@gmail.com
-// cisco.tierra@gmail.com
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// 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 <stdlib.h> // rand()
-#include <anna/diameter.comm/Engine.hpp>
+#include <anna/diameter.comm/Engine.hpp>
#include <anna/core/tracing/Logger.hpp>
#include <anna/core/tracing/TraceMethod.hpp>
#include <anna/xml/Node.hpp>
#include <anna/comm/Network.hpp>
#include <anna/comm/Host.hpp>
#include <anna/comm/ClientSocket.hpp>
-
#include <anna/diameter.comm/Transport.hpp>
#include <anna/diameter.comm/Engine.hpp>
#include <anna/diameter.comm/Entity.hpp>
#include <anna/diameter/helpers/helpers.hpp>
#include <anna/diameter/codec/Message.hpp>
#include <anna/diameter/codec/Avp.hpp>
+#include <anna/diameter.comm/Response.hpp>
// STD
#include <map>
using namespace std;
-using namespace anna::diameter::comm;
+using namespace anna::diameter;
-Engine::Engine() :
- anna::app::Component(getClassName()),
+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_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
a_numberOfClientSessionsPerServer(1),
- a_freezeEndToEndOnSending(false) {
+ 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() 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::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) 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_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::setClientCERandDWR(const std::string & cer, const std::string & dwr) noexcept(false) {
+
+ // Check for base protocol codec engine health:
+ assertBaseProtocolHealth();
+
+ // Build CER
+ // <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());
+ int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32
+ 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
+ bool encodeDefault = false;
+
+ if (cer != "") {
+ try {
+ diameterCER.loadXMLFile(cer);
+ } catch(anna::RuntimeException &ex) {
+ //ex.trace();
+ encodeDefault = true;
+ LOGWARNING(anna::Logger::warning("CER file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
+ }
+ }
+ else {
+ encodeDefault = true;
+ }
-void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
+ if(encodeDefault) {
+ diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request);
+ diameterCER.setApplicationId(applicationId);
+ 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|<ip address>"
+ 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);
+ }
+
+ // Build DWR
+ // <DWR> ::= < Diameter Header: 280, REQ >
+ // { Origin-Host }
+ // { Origin-Realm }
+ anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine());
+ encodeDefault = false;
+
+ if (dwr != "") {
+ try {
+ diameterDWR.loadXMLFile(dwr);
+ } catch(anna::RuntimeException &ex) {
+ //ex.trace();
+ encodeDefault = true;
+ LOGWARNING(anna::Logger::warning("DWR file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
+ }
+ }
+ else {
+ encodeDefault = true;
+ }
+
+ if(encodeDefault) {
+ diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request);
+ diameterDWR.setApplicationId(applicationId);
+ 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 versions:
+ setClientCERandDWR(diameterCER.code(), diameterDWR.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);
}
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());
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");
}
-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
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);
}
-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));
}
-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");
result->a_socket = socket;
result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */);
result->a_engine = this;
- result->initializeStatisticConcepts();
+ result->initializeStatisticResources();
- for(register int k = 0; k < a_numberOfClientSessionsPerServer; k++)
+ for(int k = 0; k < a_numberOfClientSessionsPerServer; k++)
result->addClientSession(k);
a_servers.insert(server_value_type(socket, result));
// 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");
// 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);
+ throw anna::RuntimeException("Must define valid CER and DWR messages by mean setClientCERandDWR()", ANNA_FILE_LOCATION);
result->a_cer.setBody(a_cer);
result->a_dwr.setBody(a_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));
}
-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;
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;
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
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);
}
-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));
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);
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));
//Entity* Engine::findEntity(int category, anna::Exception::Mode::_v emode)
-//throw(anna::RuntimeException) {
+//noexcept(false) {
//
// Entity *entity;
//
//}
-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);
}
-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;
}
-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;
-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;
}
-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;
-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;
-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");
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");
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;
}
}
-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 ++)
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 ++)
}
-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";
}
-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");
for(const_localServer_iterator it = localServer_begin(); it != localServer_end(); it++)
localServer(it)->asXML(localServers);
+ // DRA Basics
+ // Aspect:
+ // <Engine.RemoteRealm Name="afNodeHostRealm.com">
+ // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:4"/>
+ // </Engine.RemoteRealm>
+ // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
+ // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com" ServerSession="localhost:3868|ServerSessionId:6"/>
+ // </Engine.RemoteRealm>
+ 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());
}
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);
);
}
-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);
);
}
-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);
);
}
-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);
);
}
-bool Engine::refreshAvailabilityForEntities() throw() {
+bool comm::Engine::refreshAvailabilityForEntities() {
// Here available
if(a_availableForEntities) { // check not-bound state for all client-sessions:
bool isolate = true;
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;
}
-void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {
+void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) {
+
+ // Check for base protocol codec engine health:
+ try {
+ assertBaseProtocolHealth();
+ }
+ catch(anna::RuntimeException &ex) {
+ ex.trace();
+ return;
+ }
+
// Default DPA implementation:
//
// 'Disconnect-Peer-Answer' (282,answer)
// [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);
// 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) {
+
+ // Check for base protocol codec engine health:
+ assertBaseProtocolHealth();
+
+ if (a_ceaPathfile != "") {
+ anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
+
+ try {
+ diameterCEA.loadXMLFile(a_ceaPathfile);
+ 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)
// [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);
// 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);
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(ss->a_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):
+ // <Engine.RemoteRealm Name="afNodeHostRealm.com">
+ // <Engine.RemoteRealmHost Name="afNodeHostname.afNodeHostRealm.com"/>
+ // </Engine.RemoteRealm>
+ // <Engine.RemoteRealm Name="ggsnNodeHostRealm.com">
+ // <Engine.RemoteRealmHost Name="ggsnNodeHostname.ggsnNodeHostRealm.com"/>
+ // </Engine.RemoteRealm>
+
+ 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) {
+
+ // 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)
// *[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);
// 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();
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);
+}