From e14f6ba5183403d7bbf589ef87b0643b12a0f72c Mon Sep 17 00:00:00 2001 From: eramos Date: Sun, 20 Aug 2023 01:29:34 +0200 Subject: [PATCH] Fix local server for multiple applications There was a historic bug/limitation, due to the diameter.comm module design. We were not able to set two (or more) origin hosts sharing the same local server. So, we needed to set different ports (3868, 3869, etc.) to listen for different diameter applications as a server. This was because a poor design where LocalServer was tied to specific engine, and then, depending on when the service was registered (services.xml), one engine or the other was enabled to manage traffic. So, the server was unable to respond correctly one of the applications. We have implemented a map of remote origin hosts with local origin hosts, and when we have a reception, we check the origin host of the message and retrieve the own origin host which was configured for it. This is primarly done at CER/CEA exchange. When the CER arrives, we get the Auth-Application-Id, and we know the corresponding stack and answer in consequence. Also, we store the relation remote-local origin host in the origin host manager map. All the virtual methods must carry the origin host which applies, to operate. Also, many virtuals with default empty implementation but not used have been removed. Reacting answers are now stored in specific origin host. We could even improve the fact that operated host is not needed to be set when programming reacting answers, because all depends on the origin host for those answers. But this way, we allow to do rare things (tests). CER and DWR configuration have been separated. And setClientCER now have specific prototype for default CER, which needs the application-id which will be set as Auth-Application-Id. Entity and client sessions, still keep a_engine most of the cases. Component Test have been tested OK. New version will be 1.0.6 --- CMakeLists.txt | 2 +- docker-images/anna-adml-http/Dockerfile | 1 + example/diameter/launcher/EventOperation.cpp | 24 +-- example/diameter/launcher/Launcher.cpp | 38 ++-- .../diameter/launcher/MyDiameterEntity.cpp | 12 +- .../diameter/launcher/MyDiameterEntity.hpp | 12 +- example/diameter/launcher/MyLocalServer.cpp | 76 ++++---- example/diameter/launcher/MyLocalServer.hpp | 12 +- .../launcher/resources/rest_api/ct/ct.sh | 4 +- .../resources/scripts/tinyTestcase.sh | 8 +- .../rxSimpleTest/MyDiameterEntity.cpp | 12 +- .../rxSimpleTest/MyDiameterEntity.hpp | 8 +- .../diameter/rxSimpleTest/MyLocalServer.cpp | 22 +-- .../diameter/rxSimpleTest/MyLocalServer.hpp | 8 +- .../diameter/rxSimpleTest/rxSimpleTest.cpp | 4 +- include/anna/diameter.comm/ClientSession.hpp | 21 +-- include/anna/diameter.comm/Engine.hpp | 126 +++++-------- include/anna/diameter.comm/Entity.hpp | 12 +- include/anna/diameter.comm/LocalServer.hpp | 22 +-- include/anna/diameter.comm/OriginHost.hpp | 5 + .../anna/diameter.comm/OriginHostManager.hpp | 35 ++++ include/anna/diameter.comm/Server.hpp | 10 +- include/anna/diameter.comm/ServerSession.hpp | 37 ++-- include/anna/diameter.comm/Session.hpp | 20 +- source/diameter.comm/ClientSession.cpp | 46 ++--- source/diameter.comm/Engine.cpp | 171 +++++++++--------- source/diameter.comm/Entity.cpp | 2 - source/diameter.comm/LocalServer.cpp | 14 +- source/diameter.comm/MessageStatistics.cpp | 7 +- source/diameter.comm/OriginHost.cpp | 1 + source/diameter.comm/OriginHostManager.cpp | 26 +++ source/diameter.comm/Server.cpp | 18 +- source/diameter.comm/ServerSession.cpp | 149 +++++++++------ source/diameter.comm/Session.cpp | 29 ++- 34 files changed, 525 insertions(+), 469 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e28115d..fcaf4ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ enable_language(C CXX) # Project version set(VERSION_MAJOR 1) set(VERSION_MINOR 0) -set(VERSION_PATCH 5) +set(VERSION_PATCH 6) # Dynamic libraries not linked to build tree: set(CMAKE_SKIP_RPATH TRUE) diff --git a/docker-images/anna-adml-http/Dockerfile b/docker-images/anna-adml-http/Dockerfile index 2e395c9..59fb2fb 100644 --- a/docker-images/anna-adml-http/Dockerfile +++ b/docker-images/anna-adml-http/Dockerfile @@ -5,6 +5,7 @@ COPY opt/adml/ /opt/adml RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y tshark RUN apt-get update && apt-get install -y \ + vim \ net-tools \ procps \ jq \ diff --git a/example/diameter/launcher/EventOperation.cpp b/example/diameter/launcher/EventOperation.cpp index 8b45e61..cab0e83 100644 --- a/example/diameter/launcher/EventOperation.cpp +++ b/example/diameter/launcher/EventOperation.cpp @@ -465,23 +465,23 @@ bool EventOperation::answermsg_action_2e(std::string &response, const std::strin int code = message->getId().first; LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); response = "Added 'answer to entity' to the FIFO queue corresponding to its message code"; - my_app.getOperatedEntity()->getReactingAnswers()->addMessage(code, message); + my_app.getOperatedHost()->getReactingAnswers()->addMessage(code, message); } else { // action if(diameterJson_or_action == "list") { // programmed answers FIFO's to stdout - response = anna::functions::encodeBase64(my_app.getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY")); + response = anna::functions::encodeBase64(my_app.getOperatedHost()->getReactingAnswers()->asString("ANSWERS TO ENTITY")); } else if (diameterJson_or_action == "rotate") { - my_app.getOperatedEntity()->getReactingAnswers()->rotate(true); + my_app.getOperatedHost()->getReactingAnswers()->rotate(true); response = "rotate"; } else if (diameterJson_or_action == "exhaust") { - my_app.getOperatedEntity()->getReactingAnswers()->rotate(false); + my_app.getOperatedHost()->getReactingAnswers()->rotate(false); response = "exhaust"; } else if (diameterJson_or_action == "clear") { - my_app.getOperatedEntity()->getReactingAnswers()->clear(); + my_app.getOperatedHost()->getReactingAnswers()->clear(); response = "clear"; } else if (diameterJson_or_action == "dump") { - my_app.getOperatedEntity()->getReactingAnswers()->dump("programmed_answer"); + my_app.getOperatedHost()->getReactingAnswers()->dump("programmed_answer"); response = "dump"; } } @@ -523,24 +523,24 @@ bool EventOperation::answermsg_action_2c(std::string &response, const std::strin int code = message->getId().first; LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); - my_app.getOperatedServer()->getReactingAnswers()->addMessage(code, message); + my_app.getOperatedHost()->getReactingAnswers()->addMessage(code, message); response = "Added 'answer to client' to the FIFO queue corresponding to its message code"; } else { // action if(diameterJson_or_action == "list") { // programmed answers FIFO's to stdout - response = anna::functions::encodeBase64(my_app.getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT")); + response = anna::functions::encodeBase64(my_app.getOperatedHost()->getReactingAnswers()->asString("ANSWERS TO CLIENT")); } else if (diameterJson_or_action == "rotate") { - my_app.getOperatedServer()->getReactingAnswers()->rotate(true); + my_app.getOperatedHost()->getReactingAnswers()->rotate(true); response = "rotate"; } else if (diameterJson_or_action == "exhaust") { - my_app.getOperatedServer()->getReactingAnswers()->rotate(false); + my_app.getOperatedHost()->getReactingAnswers()->rotate(false); response = "exhaust"; } else if (diameterJson_or_action == "clear") { - my_app.getOperatedServer()->getReactingAnswers()->clear(); + my_app.getOperatedHost()->getReactingAnswers()->clear(); response = "clear"; } else if (diameterJson_or_action == "dump") { - my_app.getOperatedServer()->getReactingAnswers()->dump("programmed_answer"); + my_app.getOperatedHost()->getReactingAnswers()->dump("programmed_answer"); response = "dump"; } } diff --git a/example/diameter/launcher/Launcher.cpp b/example/diameter/launcher/Launcher.cpp index d3a9373..54fb750 100644 --- a/example/diameter/launcher/Launcher.cpp +++ b/example/diameter/launcher/Launcher.cpp @@ -362,7 +362,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool bindRes } ///////////////////////////////////////////////////////////////////////////////////////////// - // Diameter communication engine: + // Diameter communication engine: ONE ENGINE PER OWN ORIGIN HOST std::string commEngineName = originHost->getValue() + "_DiameterCommEngine"; MyDiameterEngine *commEngine = new MyDiameterEngine(commEngineName.c_str(), bpd); commEngine->setAutoBind(false); // allow to create client-sessions without binding them, in order to set timeouts. @@ -372,7 +372,7 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool bindRes if (originRealm) commEngine->setOriginRealmName(originRealm->getValue()); // Origin host node: - a_workingNode = new anna::diameter::comm::OriginHost((anna::diameter::comm::Engine*)commEngine, applicationId); + a_workingNode = new anna::diameter::comm::OriginHost((anna::diameter::comm::Engine*)commEngine, applicationId /* OriginHost constructor extracts corresponding stack codec engine */); a_workingNode->setRequestRetransmissions(retransmissions); ///////////////////////////////////////////////////////////////////////////////////////////// @@ -386,9 +386,13 @@ void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool bindRes commEngine->setNumberOfClientSessionsPerServer(sessions); // Client CER and DWR - std::string cerPathfile = cer ? cer->getValue() : ""; - std::string dwrPathfile = dwr ? dwr->getValue() : ""; - commEngine->setClientCERandDWR(cerPathfile, dwrPathfile); + if (cer) { // pathfile provided + commEngine->setClientCER(cer->getValue()); + } + else { + commEngine->setClientCER(applicationId); // default engine CER + } + commEngine->setClientDWR(dwr ? dwr->getValue() : "" /* default DWR */); // Register one entity for this engine: a_workingNode->createEntity(entity->getValue(), ceaTimeoutMs, answersTimeoutMs); @@ -1236,16 +1240,16 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons } else if(opType == "answerxml2e") { if(param1 == "") { // programmed answers FIFO's to stdout - response = getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY"); + response = getOperatedHost()->getReactingAnswers()->asString("ANSWERS TO ENTITY"); return true; // OK } else if (param1 == "rotate") { - getOperatedEntity()->getReactingAnswers()->rotate(true); + getOperatedHost()->getReactingAnswers()->rotate(true); } else if (param1 == "exhaust") { - getOperatedEntity()->getReactingAnswers()->rotate(false); + getOperatedHost()->getReactingAnswers()->rotate(false); } else if (param1 == "clear") { - getOperatedEntity()->getReactingAnswers()->clear(); + getOperatedHost()->getReactingAnswers()->clear(); } else if (param1 == "dump") { - getOperatedEntity()->getReactingAnswers()->dump("programmed_answer"); + getOperatedHost()->getReactingAnswers()->dump("programmed_answer"); } else { codecMsg.loadXMLFile(param1); updateOperatedOriginHostWithMessage(codecMsg); @@ -1257,21 +1261,21 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons int code = message->getId().first; LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to entity' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); - getOperatedEntity()->getReactingAnswers()->addMessage(code, message); + getOperatedHost()->getReactingAnswers()->addMessage(code, message); } } else if(opType == "answerxml2c") { if(param1 == "") { // programmed answers FIFO's to stdout - response = getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT"); + response = getOperatedHost()->getReactingAnswers()->asString("ANSWERS TO CLIENT"); return true; // OK } else if (param1 == "rotate") { - getOperatedServer()->getReactingAnswers()->rotate(true); + getOperatedHost()->getReactingAnswers()->rotate(true); } else if (param1 == "exhaust") { - getOperatedServer()->getReactingAnswers()->rotate(false); + getOperatedHost()->getReactingAnswers()->rotate(false); } else if (param1 == "clear") { - getOperatedServer()->getReactingAnswers()->clear(); + getOperatedHost()->getReactingAnswers()->clear(); } else if (param1 == "dump") { - getOperatedServer()->getReactingAnswers()->dump("programmed_answer"); + getOperatedHost()->getReactingAnswers()->dump("programmed_answer"); } else { codecMsg.loadXMLFile(param1); updateOperatedOriginHostWithMessage(codecMsg); @@ -1283,7 +1287,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons int code = message->getId().first; LOGDEBUG(anna::Logger::debug("Adding a new programed 'answer to client' to the FIFO queue corresponding to its message code ...", ANNA_FILE_LOCATION)); - getOperatedServer()->getReactingAnswers()->addMessage(code, message); + getOperatedHost()->getReactingAnswers()->addMessage(code, message); } } else if((opType == "burst")) { diff --git a/example/diameter/launcher/MyDiameterEntity.cpp b/example/diameter/launcher/MyDiameterEntity.cpp index 7bac08a..cba726a 100644 --- a/example/diameter/launcher/MyDiameterEntity.cpp +++ b/example/diameter/launcher/MyDiameterEntity.cpp @@ -52,7 +52,7 @@ void MyDiameterEntity::eventRequestRetransmission(const anna::diameter::comm::Cl } -void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventRequest", ANNA_FILE_LOCATION)); // Performance stats: @@ -77,7 +77,7 @@ noexcept(false) { // Lookup reacting answers list: int code = cid.first; - anna::diameter::codec::Message *answer_message = a_reactingAnswers.getMessage(code); + anna::diameter::codec::Message *answer_message = my_node->getReactingAnswers()->getMessage(code); if (answer_message) { // Prepare answer: my_app.getCommunicator()->prepareAnswer(answer_message, message); @@ -99,7 +99,7 @@ noexcept(false) { my_node->releaseCommMessage(msg); // Pop front the reacting answer: - a_reactingAnswers.nextMessage(code); + my_node->getReactingAnswers()->nextMessage(code); return; } @@ -137,7 +137,7 @@ noexcept(false) { anna::testing::TestManager::instantiate().receiveDiameterMessage(message, clientSession); } -void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response) +void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventResponse", ANNA_FILE_LOCATION)); Launcher& my_app = static_cast (anna::app::functions::getApp()); @@ -230,7 +230,7 @@ noexcept(false) { if(isOK) anna::testing::TestManager::instantiate().receiveDiameterMessage(*message, clientSession); } -void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventUnknownResponse", ANNA_FILE_LOCATION)); // Performance stats: @@ -253,7 +253,7 @@ noexcept(false) { if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfe-ans-unknown", clientSession->asString()); } -void MyDiameterEntity::eventDPA(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +void MyDiameterEntity::eventDPA(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyDiameterEntity", "eventDPA", ANNA_FILE_LOCATION)); // Performance stats: diff --git a/example/diameter/launcher/MyDiameterEntity.hpp b/example/diameter/launcher/MyDiameterEntity.hpp index 554267b..bf474f9 100644 --- a/example/diameter/launcher/MyDiameterEntity.hpp +++ b/example/diameter/launcher/MyDiameterEntity.hpp @@ -11,7 +11,6 @@ // Project #include -#include namespace anna { @@ -25,18 +24,15 @@ namespace anna { class MyDiameterEntity : public anna::diameter::comm::Entity { void eventRequestRetransmission(const anna::diameter::comm::ClientSession *, anna::diameter::comm::Message*) ; - void eventResponse(const anna::diameter::comm::Response&) noexcept(false); - void eventRequest(anna::diameter::comm::ClientSession *, const anna::DataBlock&) noexcept(false); - void eventUnknownResponse(anna::diameter::comm::ClientSession *, const anna::DataBlock&) noexcept(false); - void eventDPA(anna::diameter::comm::ClientSession *, const anna::DataBlock&) noexcept(false); + void eventResponse(const anna::diameter::comm::Response&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventRequest(anna::diameter::comm::ClientSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventUnknownResponse(anna::diameter::comm::ClientSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventDPA(anna::diameter::comm::ClientSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); public: MyDiameterEntity() {;} virtual ~MyDiameterEntity() {;} - - anna::diameter::codec::MessagesDeque a_reactingAnswers; - anna::diameter::codec::MessagesDeque *getReactingAnswers() { return (anna::diameter::codec::MessagesDeque*)&a_reactingAnswers; } }; #endif diff --git a/example/diameter/launcher/MyLocalServer.cpp b/example/diameter/launcher/MyLocalServer.cpp index 42b8b1e..31873c6 100644 --- a/example/diameter/launcher/MyLocalServer.cpp +++ b/example/diameter/launcher/MyLocalServer.cpp @@ -24,13 +24,16 @@ #include -void MyLocalServer::eventRequest(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +void MyLocalServer::eventRequest(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventRequest", ANNA_FILE_LOCATION)); + + // Protection: + if (!myNode) return; + // Performance stats: Launcher& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); - anna::diameter::codec::Engine *codecEngine = my_node->getCodecEngine(); + anna::diameter::codec::Engine *codecEngine = myNode->getCodecEngine(); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); @@ -46,27 +49,28 @@ noexcept(false) { ); // Write reception - if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfc", serverSession->asString()); + if(myNode->logEnabled()) myNode->writeLogFile(message, "recvfc", serverSession->asString()); // If no answer is programmed and entity is configured, the failed request would be forwarded even being wrong (delegates at the end point) int code = cid.first; - anna::diameter::codec::Message *programmed_answer = a_reactingAnswers.getMessage(code); + anna::diameter::codec::Message *programmed_answer = (const_cast(myNode))->getReactingAnswers()->getMessage(code); + bool programmed = (programmed_answer != NULL); - anna::diameter::comm::Entity *entity = my_node->getEntity(); + anna::diameter::comm::Entity *entity = myNode->getEntity(); if(!programmed && entity) { // forward condition (no programmed answer + entity available) - anna::diameter::comm::Message *msg = my_node->createCommMessage(); + anna::diameter::comm::Message *msg = (const_cast(myNode))->createCommMessage(); msg->forwardEndToEnd(); // end-to-end will be kept msg->setBody(message); msg->setRequestServerSessionKey(serverSession->getKey()); bool success = entity->send(msg); // Detailed log: - if(my_node->logEnabled()) { + if(myNode->logEnabled()) { anna::diameter::comm::Server *usedServer = entity->getLastUsedResource(); anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL; std::string detail = usedClientSession ? usedClientSession->asString() : "[null client session]"; // esto no deberia ocurrir - my_node->writeLogFile(message, (success ? "fwd2e" : "fwd2eError"), detail); // forwarded + myNode->writeLogFile(message, (success ? "fwd2e" : "fwd2eError"), detail); // forwarded } @@ -90,7 +94,7 @@ noexcept(false) { // Decode try { codecMsg.decode(message, answer_message); } catch(anna::RuntimeException &ex) { ex.trace(); } - answer_message->setStandardToAnswer(codecMsg, my_node->getCommEngine()->getOriginHostName(), my_node->getCommEngine()->getOriginRealmName()); + answer_message->setStandardToAnswer(codecMsg, myNode->getCommEngine()->getOriginHostName(), myNode->getCommEngine()->getOriginRealmName()); analysisOK = (answer_message->getResultCode() == anna::diameter::helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS); } @@ -116,34 +120,33 @@ noexcept(false) { anna::diameter::comm::Message *msg; try { - msg = my_node->createCommMessage(); + msg = (const_cast(myNode))->createCommMessage(); msg->setBody(answer_message->code()); /* response = NULL =*/serverSession->send(msg); - if(my_node->logEnabled()) my_node->writeLogFile(*answer_message, "sent2c", serverSession->asString()); + if(myNode->logEnabled()) myNode->writeLogFile(*answer_message, "sent2c", serverSession->asString()); } catch(anna::RuntimeException &ex) { ex.trace(); - if(my_node->logEnabled()) my_node->writeLogFile(*answer_message, "send2cError", serverSession->asString()); + if(myNode->logEnabled()) myNode->writeLogFile(*answer_message, "send2cError", serverSession->asString()); } // release msg - my_node->releaseCommMessage(msg); + (const_cast(myNode))->releaseCommMessage(msg); // Restore validation mode codecEngine->setValidationMode(backupVM); // Pop front the reacting answer: - if(analysisOK && programmed) a_reactingAnswers.nextMessage(code); + if(analysisOK && programmed) (const_cast(myNode))->getReactingAnswers()->nextMessage(code); // Testing: anna::testing::TestManager::instantiate().receiveDiameterMessage(message, serverSession); } -void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response) +void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventResponse", ANNA_FILE_LOCATION)); Launcher& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost * my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); anna::diameter::comm::ClassCode::_v code = response.getClassCode(); anna::diameter::comm::Response::ResultCode::_v result = response.getResultCode(); anna::diameter::comm::Message* request = const_cast(response.getRequest()); @@ -168,6 +171,9 @@ noexcept(false) { anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); + // Protection: + if (!myNode) return; + if(isUnavailable) { //if (isApplicationMessage) LOGWARNING(anna::Logger::warning("Diameter client unavailable for Diameter Request", ANNA_FILE_LOCATION)); @@ -178,7 +184,7 @@ noexcept(false) { LOGWARNING(anna::Logger::warning("Context Expired for Diameter Request which was sent to the client", ANNA_FILE_LOCATION)); if(request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) { // don't trace CEA - if(my_node->logEnabled()) my_node->writeLogFile(*request, "req2c-expired", serverSession->asString()); + if(myNode->logEnabled()) myNode->writeLogFile(*request, "req2c-expired", serverSession->asString()); } } @@ -190,20 +196,20 @@ noexcept(false) { ); // Write reception - if(my_node->logEnabled()) my_node->writeLogFile(*message, "recvfc", serverSession->asString()); + if(myNode->logEnabled()) myNode->writeLogFile(*message, "recvfc", serverSession->asString()); // This is not very usual, but answers could arrive from clients: - anna::diameter::comm::Entity *entity = my_node->getEntity(); + anna::diameter::comm::Entity *entity = myNode->getEntity(); if(entity) { - anna::diameter::comm::ClientSession *usedClientSession = my_node->getCommEngine()->findClientSession(request->getRequestClientSessionKey()); + anna::diameter::comm::ClientSession *usedClientSession = myNode->getCommEngine()->findClientSession(request->getRequestClientSessionKey()); std::string detail; - if(my_node->logEnabled()) detail = usedClientSession ? usedClientSession->asString() : "[null client session]"; // this should not happen + if(myNode->logEnabled()) detail = usedClientSession ? usedClientSession->asString() : "[null client session]"; // this should not happen anna::diameter::comm::Message *msg; try { - msg = my_node->createCommMessage(); + msg = (const_cast(myNode))->createCommMessage(); msg->forwardEndToEnd(); // end-to-end will be kept msg->setBody(*message); @@ -214,15 +220,15 @@ noexcept(false) { //msg->setRequestClientSessionKey(request->getRequestClientSessionKey()); //bool success = entity->send(msg); - if(my_node->logEnabled()) my_node->writeLogFile(*message, "fwd2e", detail); // forwarded + if(myNode->logEnabled()) myNode->writeLogFile(*message, "fwd2e", detail); // forwarded } catch(anna::RuntimeException &ex) { ex.trace(); - if(my_node->logEnabled()) my_node->writeLogFile(*message, "fwd2eError", detail); // forwarded + if(myNode->logEnabled()) myNode->writeLogFile(*message, "fwd2eError", detail); // forwarded } // release msgs - my_node->releaseCommMessage(msg); - my_node->releaseCommMessage(request); + (const_cast(myNode))->releaseCommMessage(msg); + (const_cast(myNode))->releaseCommMessage(request); } } @@ -230,12 +236,11 @@ noexcept(false) { if(isOK) anna::testing::TestManager::instantiate().receiveDiameterMessage(*message, serverSession); } -void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventUnknownResponse", ANNA_FILE_LOCATION)); // Performance stats: Launcher& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); LOGDEBUG @@ -249,15 +254,17 @@ noexcept(false) { anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); - if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfc-ans-unknown", serverSession->asString()); + // Protection: + if (!myNode) return; + + if(myNode->logEnabled()) myNode->writeLogFile(message, "recvfc-ans-unknown", serverSession->asString()); } -void MyLocalServer::eventDPA(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +void MyLocalServer::eventDPA(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("launcher::MyLocalServer", "eventDPA", ANNA_FILE_LOCATION)); // Performance stats: Launcher& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); LOGDEBUG @@ -271,8 +278,11 @@ noexcept(false) { anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); + // Protection: + if (!myNode) return; + // Write reception - if(my_node->logEnabled()) my_node->writeLogFile(message, "recvfc", serverSession->asString()); + if(myNode->logEnabled()) myNode->writeLogFile(message, "recvfc", serverSession->asString()); // Testing: anna::testing::TestManager::instantiate().receiveDiameterMessage(message, serverSession); diff --git a/example/diameter/launcher/MyLocalServer.hpp b/example/diameter/launcher/MyLocalServer.hpp index 17caf35..2ada2f4 100644 --- a/example/diameter/launcher/MyLocalServer.hpp +++ b/example/diameter/launcher/MyLocalServer.hpp @@ -11,7 +11,6 @@ // Project #include -#include namespace anna { @@ -24,16 +23,13 @@ namespace anna { class MyLocalServer : public anna::diameter::comm::LocalServer { - void eventResponse(const anna::diameter::comm::Response&) noexcept(false); - void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&) noexcept(false); - void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&) noexcept(false); - void eventDPA(anna::diameter::comm::ServerSession *, const anna::DataBlock&) noexcept(false); + void eventResponse(const anna::diameter::comm::Response&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventDPA(anna::diameter::comm::ServerSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); public: virtual ~MyLocalServer() {;} - - anna::diameter::codec::MessagesDeque a_reactingAnswers; - anna::diameter::codec::MessagesDeque *getReactingAnswers() { return (anna::diameter::codec::MessagesDeque*)&a_reactingAnswers; } }; #endif diff --git a/example/diameter/launcher/resources/rest_api/ct/ct.sh b/example/diameter/launcher/resources/rest_api/ct/ct.sh index a6e0d75..ac28e53 100755 --- a/example/diameter/launcher/resources/rest_api/ct/ct.sh +++ b/example/diameter/launcher/resources/rest_api/ct/ct.sh @@ -34,9 +34,9 @@ nghttp --version 2>/dev/null echo "Requirement found !" echo -echo "Rebuild ADML HTTP service image (y/n) [y]:" +echo "Rebuild ADML HTTP service image (y/n) [n]:" read opt -[ -z "${opt}" ] && opt=y +[ -z "${opt}" ] && opt=n if [ "${opt}" = "y" ] then ${REPO_DIR}/tools/build-anna-adml-http ${VARIANT} diff --git a/example/diameter/launcher/resources/scripts/tinyTestcase.sh b/example/diameter/launcher/resources/scripts/tinyTestcase.sh index 01674c2..ba867b2 100755 --- a/example/diameter/launcher/resources/scripts/tinyTestcase.sh +++ b/example/diameter/launcher/resources/scripts/tinyTestcase.sh @@ -128,7 +128,7 @@ search_xml () { return 1 } - + # $1: metadata file; $2: xml file; $3: check Result-Code indicator; $4: client/server (ADML node role) update_testcase () { # metadata aspect: @@ -193,7 +193,7 @@ update_testcase () { local ans_xml=${hbh_matchs[1]} local rc=2001 if [ -n "$ans_xml" ] - then + then _rc=$(getResultCode $ans_xml) [ -n "$_rc" ] && rc=$_rc fi @@ -304,7 +304,7 @@ do # Ignore keep alives: grep -q "^code=280$" $mtd [ $? -eq 0 ] && continue - + grep -q "^isrequest=1$" $mtd if [ $? -eq 0 ] then @@ -320,7 +320,7 @@ do fi # Other requests: echo $frame >> requests_4_sending - + # client or server: adml_type=$(grep -w "$originHost" $ohs_file | awk '{ print $NF }') update_testcase $mtd $xml check_result_code $adml_type diff --git a/example/diameter/rxSimpleTest/MyDiameterEntity.cpp b/example/diameter/rxSimpleTest/MyDiameterEntity.cpp index 69ccab2..9acd8fd 100755 --- a/example/diameter/rxSimpleTest/MyDiameterEntity.cpp +++ b/example/diameter/rxSimpleTest/MyDiameterEntity.cpp @@ -49,7 +49,7 @@ void MyDiameterEntity::eventRequestRetransmission(const anna::diameter::comm::Cl } -void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +void MyDiameterEntity::eventRequest(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyDiameterEntity", "eventRequest", ANNA_FILE_LOCATION)); // Performance stats: @@ -70,7 +70,7 @@ noexcept(false) { ); } -void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response) +void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyDiameterEntity", "eventResponse", ANNA_FILE_LOCATION)); RxSimpleTest& my_app = static_cast (anna::app::functions::getApp()); @@ -155,7 +155,7 @@ noexcept(false) { anna::diameter::comm::Message *msg; try { - msg = my_node->createCommMessage(); + msg = (const_cast(myNode))->createCommMessage(); msg->setBody(aar.code()); /* response = NULL =*/clientSession->send(msg); } catch(anna::RuntimeException &ex) { @@ -163,7 +163,7 @@ noexcept(false) { } // release msg - my_node->releaseCommMessage(msg); + (const_cast(myNode))->releaseCommMessage(msg); } else if(request_cid == anna::diameter::helpers::nas::COMMANDID__AA_Request) { // Decode @@ -179,7 +179,7 @@ noexcept(false) { } } -void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyDiameterEntity", "eventUnknownResponse", ANNA_FILE_LOCATION)); // Performance stats: @@ -199,7 +199,7 @@ noexcept(false) { ); } -void MyDiameterEntity::eventDPA(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) +void MyDiameterEntity::eventDPA(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyDiameterEntity", "eventDPA", ANNA_FILE_LOCATION)); // Performance stats: diff --git a/example/diameter/rxSimpleTest/MyDiameterEntity.hpp b/example/diameter/rxSimpleTest/MyDiameterEntity.hpp index d42016d..2c7f8d5 100755 --- a/example/diameter/rxSimpleTest/MyDiameterEntity.hpp +++ b/example/diameter/rxSimpleTest/MyDiameterEntity.hpp @@ -23,10 +23,10 @@ namespace anna { class MyDiameterEntity : public anna::diameter::comm::Entity { void eventRequestRetransmission(const anna::diameter::comm::ClientSession *, anna::diameter::comm::Message*) ; - void eventResponse(const anna::diameter::comm::Response&) noexcept(false); - void eventRequest(anna::diameter::comm::ClientSession *, const anna::DataBlock&) noexcept(false); - void eventUnknownResponse(anna::diameter::comm::ClientSession *, const anna::DataBlock&) noexcept(false); - void eventDPA(anna::diameter::comm::ClientSession *, const anna::DataBlock&) noexcept(false); + void eventResponse(const anna::diameter::comm::Response&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventRequest(anna::diameter::comm::ClientSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventUnknownResponse(anna::diameter::comm::ClientSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventDPA(anna::diameter::comm::ClientSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); public: diff --git a/example/diameter/rxSimpleTest/MyLocalServer.cpp b/example/diameter/rxSimpleTest/MyLocalServer.cpp index 1327dd1..a3809a1 100755 --- a/example/diameter/rxSimpleTest/MyLocalServer.cpp +++ b/example/diameter/rxSimpleTest/MyLocalServer.cpp @@ -23,13 +23,16 @@ #include -void MyLocalServer::eventRequest(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +void MyLocalServer::eventRequest(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyLocalServer", "eventRequest", ANNA_FILE_LOCATION)); + + // Protection: + if (!myNode) return; + // Performance stats: RxSimpleTest& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); - anna::diameter::codec::Engine *codecEngine = my_node->getCodecEngine(); + anna::diameter::codec::Engine *codecEngine = myNode->getCodecEngine(); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); @@ -51,7 +54,7 @@ noexcept(false) { anna::diameter::comm::Message *msg; try { - msg = my_node->createCommMessage(); + msg = (const_cast(myNode))->createCommMessage(); msg->setBody(answer_message->code()); /* response = NULL =*/serverSession->send(msg); } catch(anna::RuntimeException &ex) { @@ -59,14 +62,13 @@ noexcept(false) { } // release msg - my_node->releaseCommMessage(msg); + (const_cast(myNode))->releaseCommMessage(msg); } -void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response) +void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyLocalServer", "eventResponse", ANNA_FILE_LOCATION)); RxSimpleTest& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost * my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); anna::diameter::comm::ClassCode::_v code = response.getClassCode(); anna::diameter::comm::Response::ResultCode::_v result = response.getResultCode(); anna::diameter::comm::Message* request = const_cast(response.getRequest()); @@ -110,12 +112,11 @@ noexcept(false) { } } -void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyLocalServer", "eventUnknownResponse", ANNA_FILE_LOCATION)); // Performance stats: RxSimpleTest& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); LOGDEBUG @@ -130,12 +131,11 @@ noexcept(false) { ); } -void MyLocalServer::eventDPA(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) +void MyLocalServer::eventDPA(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { LOGMETHOD(anna::TraceMethod tm("rxSimpleTest::MyLocalServer", "eventDPA", ANNA_FILE_LOCATION)); // Performance stats: RxSimpleTest& my_app = static_cast (anna::app::functions::getApp()); - anna::diameter::comm::OriginHost *my_node = my_app.getOriginHost(getEngine()->getOriginHostName()); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); LOGDEBUG diff --git a/example/diameter/rxSimpleTest/MyLocalServer.hpp b/example/diameter/rxSimpleTest/MyLocalServer.hpp index 4f25615..6893c67 100755 --- a/example/diameter/rxSimpleTest/MyLocalServer.hpp +++ b/example/diameter/rxSimpleTest/MyLocalServer.hpp @@ -23,10 +23,10 @@ namespace anna { class MyLocalServer : public anna::diameter::comm::LocalServer { - void eventResponse(const anna::diameter::comm::Response&) noexcept(false); - void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&) noexcept(false); - void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&) noexcept(false); - void eventDPA(anna::diameter::comm::ServerSession *, const anna::DataBlock&) noexcept(false); + void eventResponse(const anna::diameter::comm::Response&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); + void eventDPA(anna::diameter::comm::ServerSession *, const anna::DataBlock&, const anna::diameter::comm::OriginHost*) noexcept(false); public: virtual ~MyLocalServer() {;} diff --git a/example/diameter/rxSimpleTest/rxSimpleTest.cpp b/example/diameter/rxSimpleTest/rxSimpleTest.cpp index 12fde94..ecde7ef 100755 --- a/example/diameter/rxSimpleTest/rxSimpleTest.cpp +++ b/example/diameter/rxSimpleTest/rxSimpleTest.cpp @@ -130,8 +130,8 @@ void RxSimpleTest::startService() noexcept(false) { // Diameter entity: commEngine->setNumberOfClientSessionsPerServer(1); - //commEngine->setClientCERandDWR("./cer.xml", "./dwr.xml"); - commEngine->setClientCERandDWR(); + commEngine->setClientCER(anna::diameter::helpers::APPID__3GPP_Rx); + commEngine->setClientDWR(); // default // Register one entity for this engine: a_workingNode->createEntity("localhost:3868", ceaTimeoutMs, answersTimeoutMs); diff --git a/include/anna/diameter.comm/ClientSession.hpp b/include/anna/diameter.comm/ClientSession.hpp index f653ee5..6df8a85 100644 --- a/include/anna/diameter.comm/ClientSession.hpp +++ b/include/anna/diameter.comm/ClientSession.hpp @@ -133,14 +133,6 @@ public: */ const anna::Millisecond & getMaxConnectionDelay() { return a_server->getMaxConnectionDelay(); } - /** - * Sets CER and DWR diameter messages to be used over created client-sessions - * - * @param cer Capabilities-Exchange-Request message (encoded) for the client-sessions bind. - * @param dwr Device-Watchdog-Request message (encoded) for the client-sessions keep-alive. - */ - void setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) noexcept(false); - // Internal void bind() noexcept(false); @@ -192,6 +184,7 @@ private: Server *a_parent; // ClientSession messages: + Engine *a_engine; // it is unique for a client session (not in server session, which have one per origin host) Message a_cer; Message a_dwr; @@ -243,30 +236,34 @@ private: Handler for diameter server (client-session) responses \param response Answer container object for corresponding diameter request + \param myNode Own origin host */ - void eventResponse(const Response& response) noexcept(false); + void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter server (client-session) requests \param request Request data block object for corresponding diameter reception + \param myNode Own origin host */ - void eventRequest(const anna::DataBlock& request) noexcept(false); + void eventRequest(const anna::DataBlock& request, const anna::diameter::comm::OriginHost *myNode) noexcept(false); //void eventRequest(const Message& request) noexcept(false); /** Handler for diameter server (client-session) responses out of context \param response Answer data block object without context match + \param myNode Own origin host */ - void eventUnknownResponse(const anna::DataBlock& response) noexcept(false); + void eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter server (client-session) Disconnect-Peer-Answer messages \param response Answer data block object without context match + \param myNode Own origin host */ - void eventDPA(const anna::DataBlock& response) noexcept(false); + void eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); diff --git a/include/anna/diameter.comm/Engine.hpp b/include/anna/diameter.comm/Engine.hpp index e8febc4..8da4a6b 100644 --- a/include/anna/diameter.comm/Engine.hpp +++ b/include/anna/diameter.comm/Engine.hpp @@ -25,6 +25,8 @@ #include #include #include +#include // U32 + // Standard #include @@ -184,22 +186,40 @@ public: bool bind() noexcept(false); /** - * Sets CER and DWR diameter messages to be used over created client-sessions. - * Its recommended to set this global configuration although it is possible to configure each client-session separately. + * Sets CER diameter messages to be used over created client-sessions. * * @param cer Capabilities-Exchange-Request message (encoded) for the client-sessions bind. + */ + void setClientCER(const anna::DataBlock & cer) noexcept(false); + + /** + * Sets CER diameter messages to be used over created client-sessions. + * + * @param cerPathFile Capabilities-Exchange-Request xml message path file for the client-sessions bind. + */ + void setClientCER(const std::string & cerPathFile) noexcept(false); + + /** + * Sets DEFAULT CER diameter messages to be used over created client-sessions. + * + * @param applicationId Application-Id for the Auth-Application-Id AVP. + */ + void setClientCER(const anna::U32 &applicationId) noexcept(false); + + /** + * Sets DWR for diameter keep-alive over client-sessions + * * @param dwr Device-Watchdog-Request message (encoded) for the client-sessions keep-alive. */ - void setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) noexcept(false); + void setClientDWR(const anna::DataBlock & dwr) noexcept(false); /** - * Sets CER and DWR diameter messages to be used over created client-sessions. If empty string is provided for CER and/or DWR, default version will be configured. - * Its recommended to set this global configuration although it is possible to configure each client-session separately. + * Sets DWR for diameter keep-alive over client-sessions * - * @param cer Capabilities-Exchange-Request xml message path file for the client-sessions bind. If empty string is provided (default), a default version for CER will be encoded. - * @param dwr Device-Watchdog-Request xml message path file for the client-sessions keep-alive. If empty string is provided (default), a default version for DWR will be encoded. + * @param cerPathFile Device-Watchdog-Request xml message path file for the client-sessions keep-alive. + * If empty provided, a DEFAULT DWR will be built. */ - void setClientCERandDWR(const std::string & cer = "", const std::string & dwr = "") noexcept(false); + void setClientDWR(const std::string & dwrPathFile = "") noexcept(false); /** * Sets the watchdog period (DWR) for client-sessions. @@ -492,71 +512,6 @@ public: */ virtual anna::xml::Node* asXML(anna::xml::Node* parent) const ; - - /** - When there is not bound server session over the engine, this virtual method will be invoked. - Applications must decide to do any other tasks at this idle/isolated situation. - Default implementation do nothing. - */ - virtual void availabilityLostForLocalServers(Engine *) const {;} - - /** - When there is any bound server session over the engine, this virtual method will be invoked. - Applications must decide to do be ready for incoming traffic. - Default implementation do nothing. - */ - virtual void availabilityRecoveredForLocalServers(Engine *) const {;} - - /** - When there is not bound entity over the engine, this virtual method will be invoked. - Many applications must change communicator status to Unavailable when no engines are available. - Default implementation do nothing. - */ - virtual void availabilityLostForEntities(Engine *) const {;} - - /** - When there is any bound entity over the engine, this virtual method will be invoked. - Many applications must recover communicator status to Available when any engine are available. - Default implementation do nothing. - */ - virtual void availabilityRecoveredForEntities(Engine *) const {;} - - /** - When there is not bound server-session over the local server, this virtual method will be invoked. - Default implementation do nothing. - */ - virtual void availabilityLost(LocalServer *) const {;} - - /** - When there is any bound server-session over the local server, this virtual method will be invoked. - Default implementation do nothing. - */ - virtual void availabilityRecovered(LocalServer *) const {;} - - /** - When there is not bound server over the entity, this virtual method will be invoked. - Default implementation do nothing. - */ - virtual void availabilityLost(Entity *) const {;} - - /** - When there is any bound server over the entity, this virtual method will be invoked. - Default implementation do nothing. - */ - virtual void availabilityRecovered(Entity *) const {;} - - /** - When there is not bound client-session over the server, this virtual method will be invoked. - Default implementation do nothing. - */ - virtual void availabilityLost(Server *) const {;} - - /** - When there is any bound client-session over the server, this virtual method will be invoked. - Default implementation do nothing. - */ - virtual void availabilityRecovered(Server *) const {;} - /** When a subyacent client session is going to be bound, this method is invoked before. Default implementation do nothing. @@ -573,7 +528,7 @@ public: * @param dpa DPA datablock passed as reference * @param dpr Corresponding DPR received (sequence values must be taken into account in order to build DPA) */ - virtual void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) ; + virtual void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) const; /** * Sets optional CEA from file, when default is not enough @@ -582,6 +537,13 @@ public: */ void setCEA(const std::string &ceaPathfile) { a_ceaPathfile = ceaPathfile; } + /** + * Gets optional CEA from file, when default is not enough + * + * @return Path file for the CEA xml message provided + */ + const std::string & getCEA() const { return a_ceaPathfile; } + /** * Class user should implement this method in order to define Capabilities-Exchange-Answer for received CER over server socket. * Origin-Host and Origin-Realm are configured at comm::Engine with hostname and FQDN (Fully Qualified Domain Name). @@ -611,7 +573,7 @@ public: * @param cea CEA datablock passed as reference. Empty cea implies to discard CER received. * @param cer Corresponding CER received (sequence values must be taken into account in order to build CEA) */ - virtual void readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) ; + virtual void readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) const; /** * Class user should implement this method in order to define Device-Watchdog-Answer for received DWR over server socket. @@ -622,7 +584,7 @@ public: * @param dwa DWA datablock passed as reference * @param dwr Corresponding DWR received (sequence values must be taken into account in order to build DWA) */ - virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) ; + virtual void readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) const; /** * DRA basics: CER information is gathered on every server session managed by the diameter comm engine. You could send the message to a @@ -661,7 +623,7 @@ protected: @param baseProtocolDictionary This will be used internally when calling \@readCEA, \@readDPA and \@readDWA on servers, and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL, but you must be sure that neither of the former situations are going to happen or an exception will be - thrown (using setClientCERandDWR with DataBlock arguments, expects externally encoded messages and could help). + thrown (using setClientCER and setClientDWR with DataBlock arguments, expects externally encoded messages and could help). It is recommended to set a base protocol dictionary loading 'source/diameter/stack/setups' dictionaries (for example 'avps_ietf.xml' plus 'commands_baseProtocol.xml'), or using the dictionary creation API. The dictionary could also be an application stack, the only condition is containing the resources to build base protocol messages. @@ -734,14 +696,12 @@ private: // ClientSessions messages: - anna::DataBlock a_cer; - anna::DataBlock a_dwr; + anna::DataBlock a_client_cer; + anna::DataBlock a_client_dwr; anna::Millisecond a_watchdogPeriod; -// // ServerSessions messages: + // ServerSessions messages: no need for DWA and DPA templates, they are built on the fly (enough information). std::string a_ceaPathfile; // path file to optional CEA (diameter local server configuration) -// anna::DataBlock a_cea; -// anna::DataBlock a_dwa; // Client connectivity anna::Millisecond a_maxConnectionDelay; @@ -766,7 +726,7 @@ private: // Integrity: void checkEntityCollision(const socket_v &) noexcept(false); - void assertBaseProtocolHealth() noexcept(false); // checks the dictionary + void assertBaseProtocolHealth() const noexcept(false); // checks the dictionary ////////////////////////// diff --git a/include/anna/diameter.comm/Entity.hpp b/include/anna/diameter.comm/Entity.hpp index b8ade9b..351b3e0 100644 --- a/include/anna/diameter.comm/Entity.hpp +++ b/include/anna/diameter.comm/Entity.hpp @@ -475,16 +475,18 @@ protected: Handler for diameter server (server) responses \param response Answer container object for corresponding diameter request + \param myNode Own origin host */ - virtual void eventResponse(const Response& response) noexcept(false) = 0; + virtual void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; /** Handler for diameter server (server) requests \param clientSession ClientSession from which request has been received \param request Diameter request message received + \param myNode Own origin host */ - virtual void eventRequest(ClientSession* clientSession, const anna::DataBlock &request) noexcept(false) = 0; + virtual void eventRequest(ClientSession* clientSession, const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; //virtual void eventRequest(ClientSession* clientSession, const Message& request) noexcept(false) = 0; /** @@ -492,16 +494,18 @@ protected: \param clientSession ClientSession from which request has been received \param response Answer data block object without context match + \param myNode Own origin host */ - virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response) noexcept(false) = 0; + virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; /** Handler for diameter session Disconnect-Peer-Answer messages \param clientSession ClientSession from which request has been received \param response Answer data block object without context match + \param myNode Own origin host */ - virtual void eventDPA(ClientSession *clientSession, const anna::DataBlock& response) noexcept(false) = 0; + virtual void eventDPA(ClientSession *clientSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; diff --git a/include/anna/diameter.comm/LocalServer.hpp b/include/anna/diameter.comm/LocalServer.hpp index ba1d494..6a63a7c 100644 --- a/include/anna/diameter.comm/LocalServer.hpp +++ b/include/anna/diameter.comm/LocalServer.hpp @@ -43,10 +43,10 @@ namespace diameter { namespace comm { -class Engine; class Response; class ServerSocket; class Message; +class Engine; /** @@ -65,7 +65,7 @@ class LocalServer { bool a_lock; // Engine - Engine *a_engine; + Engine *a_engine; // only for refresh availability // Statistics MessageStatistics a_messageStatistics; @@ -186,12 +186,6 @@ public: // getters - /** - * Gets the diameter::comm::Engine - * @return Diameter::comm::Engine - */ - Engine *getEngine() const { return a_engine; } - /** * Gets the local server key * @return LocalServer key @@ -380,16 +374,18 @@ protected: Handler for diameter client responses \param response Answer container object for corresponding diameter request + \param myNode Own origin host */ - virtual void eventResponse(const Response& response) noexcept(false) = 0; + virtual void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; /** Handler for diameter client requests \param serverSession ServerSession from which request has been received \param request Request data block object for corresponding diameter reception + \param myNode Own origin host */ - virtual void eventRequest(ServerSession* serverSession, const anna::DataBlock& request) noexcept(false) = 0; + virtual void eventRequest(ServerSession* serverSession, const anna::DataBlock& request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; //void eventRequest(ServerSession* serverSession, const Message& request) noexcept(false); /** @@ -397,16 +393,18 @@ protected: \param serverSession ServerSession from which request has been received \param response Answer data block object without context match + \param myNode Own origin host */ - virtual void eventUnknownResponse(ServerSession* serverSession, const anna::DataBlock& response) noexcept(false) = 0; + virtual void eventUnknownResponse(ServerSession* serverSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; /** Handler for diameter client Disconnect-Peer-Answer messages \param serverSession ServerSession from which request has been received \param response Answer data block object without context match + \param myNode Own origin host */ - virtual void eventDPA(ServerSession* serverSession, const anna::DataBlock& response) noexcept(false) = 0; + virtual void eventDPA(ServerSession* serverSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; friend class anna::diameter::comm::Timer; diff --git a/include/anna/diameter.comm/OriginHost.hpp b/include/anna/diameter.comm/OriginHost.hpp index 55f729d..30562ca 100644 --- a/include/anna/diameter.comm/OriginHost.hpp +++ b/include/anna/diameter.comm/OriginHost.hpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace anna { @@ -65,6 +66,8 @@ class OriginHost { int a_otaRequest; int a_burstPopCounter; + anna::diameter::codec::MessagesDeque a_reactingAnswers; + public: OriginHost(anna::diameter::comm::Engine* commEngine, unsigned int applicationId); ~OriginHost() {;} @@ -117,6 +120,8 @@ public: anna::xml::Node* asXML(anna::xml::Node* parent) const ; std::string asXMLString() const ; + + anna::diameter::codec::MessagesDeque *getReactingAnswers() { return (anna::diameter::codec::MessagesDeque*)&a_reactingAnswers; } }; } diff --git a/include/anna/diameter.comm/OriginHostManager.hpp b/include/anna/diameter.comm/OriginHostManager.hpp index 82c0979..9051052 100644 --- a/include/anna/diameter.comm/OriginHostManager.hpp +++ b/include/anna/diameter.comm/OriginHostManager.hpp @@ -13,6 +13,8 @@ // Project #include #include +#include // U32 + // Standard #include @@ -45,6 +47,8 @@ class OriginHostManager : public anna::Singleton { private: origin_hosts_t a_origin_hosts; + std::map a_remote_to_own_origin_hosts{}; + // private constructor OriginHostManager() {}; @@ -77,6 +81,15 @@ public: */ void registerOriginHost(const std::string &name, OriginHost* originHost) ; + /** + * Registers the relation between Origin Host for incoming request and + * own origin host. + * + * @param remoteName origin host name for the received CER + * @param ownName Own origin host name + */ + void registerRemoteOriginHost(const std::string &remoteName, const std::string &ownName); + /** * Get the associated origin host node for a provided name. * @@ -86,6 +99,28 @@ public: */ OriginHost *getOriginHost(const std::string &name) const ; + /** + * Get the associated origin host name for a provided remote origin host name. + * This relation was established on CER reception. + * + * @param name remote origin host name + * + * @return own origin host, NULL if not found + */ + OriginHost * getOriginHostForRemoteOriginHost(const std::string &name) const; + + /** + * Get the associated origin host node for a specific application id + * No indexed map by application id, so this search is sequential, but + * performance is not required as this is used when receiving CER. + * + * @applicationId application id to search + * + * @return Found origin host node, NULL if not found + */ + OriginHost *getOriginHost(const anna::U32 &applicationId) const; + + /** Class XML representation. \param parent XML node over which we will put instance information. diff --git a/include/anna/diameter.comm/Server.hpp b/include/anna/diameter.comm/Server.hpp index 711fdcd..514ce39 100644 --- a/include/anna/diameter.comm/Server.hpp +++ b/include/anna/diameter.comm/Server.hpp @@ -45,6 +45,7 @@ class Entity; class ClientSession; class Response; class Message; +class OriginHost; /** @@ -297,7 +298,7 @@ protected: \param response Answer container object for corresponding diameter request */ - virtual void eventResponse(const Response & response) noexcept(false); + virtual void eventResponse(const Response & response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter server (client-session) requests @@ -305,8 +306,7 @@ protected: \param clientSession ClientSession from which request has been received \param request Diameter request message received */ - virtual void eventRequest(ClientSession *clientSession, const anna::DataBlock &request) noexcept(false); - //virtual void eventRequest(ClientSession *clientSession, const Message & request) noexcept(false); + virtual void eventRequest(ClientSession *clientSession, const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter server (client-session) responses out of context @@ -314,7 +314,7 @@ protected: \param clientSession ClientSession from which request has been received \param response Answer data block object without context match */ - virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response) noexcept(false); + virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter server (client-session) Disconnect-Peer-Answer messages @@ -322,7 +322,7 @@ protected: \param clientSession ClientSession from which request has been received \param response Answer data block object without context match */ - virtual void eventDPA(ClientSession *clientSession, const anna::DataBlock& response) noexcept(false); + virtual void eventDPA(ClientSession *clientSession, const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); diff --git a/include/anna/diameter.comm/ServerSession.hpp b/include/anna/diameter.comm/ServerSession.hpp index 937cbf9..64997c4 100644 --- a/include/anna/diameter.comm/ServerSession.hpp +++ b/include/anna/diameter.comm/ServerSession.hpp @@ -14,6 +14,7 @@ #include #include +#include // U32 #include #include @@ -43,6 +44,7 @@ namespace comm { class LocalServer; +class OriginHost; /** @@ -104,19 +106,6 @@ public: */ anna::comm::ClientSocket *getClientSocket() { return a_clientSocket; } -// /** -// Sets deprecated state to this server session -// */ -// void setDeprecated(bool deprecated = true) { a_deprecated = deprecated; } - -// /** -// * Sets CEA and DWA diameter messages to be used over created server-sessions -// * -// * @param cea Capabilities-Exchange-Answer message (encoded) for the server-sessions bind. -// * @param dwa Device-Watchdog-Answer message (encoded) for the server-sessions keep-alive. -// */ -// void setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) noexcept(false); - /* virtual */const Response* send(const Message* message) noexcept(false); /* virtual */bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) noexcept(false); // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA) @@ -151,9 +140,6 @@ private: // Client Socket anna::comm::ClientSocket *a_clientSocket; - // Auxiliary messages: - Message a_cer, a_dwr; - /* virtual */void expire(anna::timex::Engine *timeController) noexcept(false); // Activity: @@ -180,30 +166,34 @@ private: Handler for diameter client responses \param response Answer container object for corresponding diameter request + \param myNode Own origin host */ - void eventResponse(const Response& response) noexcept(false); + void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter client requests \param request Request data block object for corresponding diameter reception + \param myNode Own origin host */ - void eventRequest(const anna::DataBlock& request) noexcept(false); + void eventRequest(const anna::DataBlock& request, const anna::diameter::comm::OriginHost *myNode) noexcept(false); //void eventRequest(const Message& request) noexcept(false); /** Handler for diameter client responses out of context \param response Answer data block object without context match + \param myNode Own origin host */ - void eventUnknownResponse(const anna::DataBlock& response) noexcept(false); + void eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); /** Handler for diameter client Disconnect-Peer-Answer messages \param response Answer data block object without context match + \param myNode Own origin host */ - void eventDPA(const anna::DataBlock& response) noexcept(false); + void eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false); @@ -214,8 +204,11 @@ private: /* virtual */void finalize() ; /* virtual */void expireResponse(Response*) ; - void sendCEA() noexcept(false); - void sendDWA() noexcept(false); + + anna::U32 getAuthApplicationIdFromCER(const anna::DataBlock &cer, bool &found) const; + + void sendCEA(const Engine*, const anna::DataBlock &cerDataBlock) noexcept(false); + void sendDWA(const Engine*, const anna::DataBlock &dwrDataBlock) noexcept(false); friend class anna::diameter::comm::Timer; diff --git a/include/anna/diameter.comm/Session.hpp b/include/anna/diameter.comm/Session.hpp index 6507229..de7e569 100644 --- a/include/anna/diameter.comm/Session.hpp +++ b/include/anna/diameter.comm/Session.hpp @@ -45,6 +45,7 @@ namespace comm { class Timer; class Engine; class Response; +class OriginHost; @@ -265,9 +266,6 @@ public: protected: - // Auxiliary messages: - Message a_dpr; - // Internal, traces, etc. const char *a_className; @@ -275,7 +273,6 @@ protected: int a_socketId; // multiple connection functionality State::_v a_state; OnDisconnect::_v a_onDisconnect; - Engine *a_engine; anna::diameter::comm::Timer *a_actionTimer; // Sequencing @@ -339,15 +336,17 @@ protected: Handler for diameter session responses \param response Answer data block object for corresponding diameter request + \param myNode Own origin host */ - virtual void eventResponse(const Response& response) noexcept(false) = 0; + virtual void eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; /** Handler for diameter session requests \param request Request container object for corresponding diameter reception + \param myNode Own origin host */ - virtual void eventRequest(const anna::DataBlock& request) noexcept(false) = 0; + virtual void eventRequest(const anna::DataBlock& request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; //void eventRequest(const Message& request) noexcept(false); @@ -355,15 +354,17 @@ protected: Handler for diameter session responses out of context \param response Answer data block object without context match + \param myNode Own origin host */ - virtual void eventUnknownResponse(const anna::DataBlock& response) noexcept(false) = 0; + virtual void eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; /** Handler for diameter session Disconnect-Peer-Answer messages \param response Answer data block object without context match + \param myNode Own origin host */ - virtual void eventDPA(const anna::DataBlock& response) noexcept(false) = 0; + virtual void eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) = 0; @@ -389,7 +390,7 @@ protected: virtual void expireResponse(Response*) ; - void sendDPA() noexcept(false); + void sendDPA(const Engine *commEngine, const anna::DataBlock &dprDataBlock) noexcept(false); void activateActionTimer(const anna::diameter::comm::Timer::Type::_v type) ; void cancelActionTimer() ; void activateTimer() ; // Session timer @@ -409,7 +410,6 @@ protected: friend class anna::diameter::comm::Timer; - friend class Engine; friend class Response; }; diff --git a/source/diameter.comm/ClientSession.cpp b/source/diameter.comm/ClientSession.cpp index fa4a9c3..9db3ca7 100644 --- a/source/diameter.comm/ClientSession.cpp +++ b/source/diameter.comm/ClientSession.cpp @@ -125,25 +125,6 @@ void ClientSession::bind() noexcept(false) { } -void ClientSession::setCERandDWR(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); - } - - 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); - } - - // La verificacion ya se hace implicitamente antes - // if ((a_cer.isEmpty()) || (a_dwr.isEmpty())) { - // LOGDEBUG (anna::Logger::debug ("Must define valid CER and DWR messages before use bind !", ANNA_FILE_LOCATION)); - // return; - // } - a_cer.setBody(cer); - a_dwr.setBody(dwr); -} - - const Response* ClientSession::send(const Message* message) noexcept(false) { LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION)); @@ -458,24 +439,24 @@ void ClientSession::eventRequestRetransmission(Message *request) { a_parent->eventRequestRetransmission(this, request); } -void ClientSession::eventResponse(const Response& response) noexcept(false) { +void ClientSession::eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventResponse(response); + a_parent->eventResponse(response, myNode); } -void ClientSession::eventRequest(const anna::DataBlock &request) noexcept(false) { +void ClientSession::eventRequest(const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventRequest(this, request); + a_parent->eventRequest(this, request, myNode); } -void ClientSession::eventUnknownResponse(const anna::DataBlock& response) noexcept(false) { +void ClientSession::eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventUnknownResponse(this, response); + a_parent->eventUnknownResponse(this, response, myNode); } -void ClientSession::eventDPA(const anna::DataBlock& response) noexcept(false) { +void ClientSession::eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventDPA(this, response); + a_parent->eventDPA(this, response, myNode); } @@ -542,11 +523,10 @@ noexcept(false) { oamModule.count(OamModule::Counter::DPRReceived); if(a_state == State::Bound) { - a_dpr.setBody(db); setState(State::Disconnecting); LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter server)", ANNA_FILE_LOCATION)); - if(getOTARequests() == 0) sendDPA(); + if(getOTARequests() == 0) sendDPA(a_engine, db); return; // DPR won't be informed because virtual readDPA is available for this } @@ -556,7 +536,7 @@ noexcept(false) { // application message counters ApplicationMessageOamModule::instantiate().count(cid.first, -1 /* no result code */, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsClient); - eventRequest(db); + eventRequest(db, nullptr /* client classes have a valid engine usage to distinguish, and get origin host from */); } catch(anna::RuntimeException& ex) { ex.trace(); } @@ -661,7 +641,7 @@ noexcept(false) { // application message counters ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsClient); - eventUnknownResponse(db); + eventUnknownResponse(db, nullptr /* client classes have a valid engine usage to distinguish, and get origin host from */); string msg(asString()); msg += anna::functions::asString(" | Response received from entity, for non registered context (HopByHop: %u)", hopByHop); throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); @@ -711,7 +691,7 @@ noexcept(false) { if(cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer) ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsClient); - eventResponse(*response); + eventResponse(*response, nullptr /* client classes have a valid engine usage to distinguish, and get origin host from */); } catch(anna::RuntimeException& ex) { ex.trace(); } @@ -719,7 +699,7 @@ noexcept(false) { else { // DPA // unbind is automatically performed, anyway we can inform to the application just in case some additional // procedure could be issued: - eventDPA(db); + eventDPA(db, nullptr /* client classes have a valid engine usage to distinguish, and get origin host from */); } response_erase(response); diff --git a/source/diameter.comm/Engine.cpp b/source/diameter.comm/Engine.cpp index 94c7d2d..f860a15 100644 --- a/source/diameter.comm/Engine.cpp +++ b/source/diameter.comm/Engine.cpp @@ -52,8 +52,8 @@ comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtoco 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), @@ -71,7 +71,7 @@ comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtoco } -void comm::Engine::assertBaseProtocolHealth() noexcept(false) { +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 ... @@ -84,21 +84,72 @@ void comm::Engine::releaseServer(Server *server) { a_serversRecycler.release(ser comm::ClientSession* comm::Engine::allocateClientSession() { return a_clientSessionsRecycler.create(); } void comm::Engine::releaseClientSession(ClientSession *clientSession) { a_clientSessionsRecycler.release(clientSession); } - -void comm::Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) noexcept(false) { +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 comm::Engine::setClientCER(const std::string & cerPathfile) noexcept(false) { + + // Check for base protocol codec engine health: + assertBaseProtocolHealth(); + + 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::setClientCERandDWR(const std::string & cer, const std::string & dwr) noexcept(false) { +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(); @@ -115,67 +166,23 @@ void comm::Engine::setClientCERandDWR(const std::string & cer, const std::string // * [ 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; - } - - 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|" - 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 - // ::= < 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); - } + 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: - setClientCERandDWR(diameterCER.code(), diameterDWR.code()); + setClientCER(diameterCER.code()); } void comm::Engine::setWatchdogPeriod(const anna::Millisecond & wp) noexcept(false) { @@ -263,13 +270,14 @@ noexcept(false) { // 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); @@ -286,6 +294,7 @@ noexcept(false) { ); // // 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; } @@ -314,9 +323,9 @@ noexcept(false) { result->a_parent = entity; result->a_socket = socket; result->setMaxClientSessions(a_numberOfClientSessionsPerServer /* engine */); - result->a_engine = this; result->initializeStatisticResources(); + result->a_engine = this; for(int k = 0; k < a_numberOfClientSessionsPerServer; k++) result->addClientSession(k); @@ -344,11 +353,11 @@ noexcept(false) { 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 setClientCERandDWR()", 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; @@ -936,8 +945,6 @@ void comm::Engine::availabilityLostForEntities() { OamModule &oamModule = OamModule::instantiate(); oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForEntities); - // Virtual - availabilityLostForEntities(this); } @@ -955,8 +962,6 @@ void comm::Engine::availabilityRecoveredForEntities() { OamModule &oamModule = OamModule::instantiate(); oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverEntitiesForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForEntities); - // Virtual - availabilityRecoveredForEntities(this); } @@ -974,8 +979,6 @@ void comm::Engine::availabilityLostForLocalServers() { OamModule &oamModule = OamModule::instantiate(); oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::LostAvailabilityOverEngineForLocalServers); - // Virtual - availabilityLostForLocalServers(this); } @@ -993,8 +996,6 @@ void comm::Engine::availabilityRecoveredForLocalServers() { OamModule &oamModule = OamModule::instantiate(); oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServersForEngineWithClassName__s__, getClassName()); oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEngineForLocalServers); - // Virtual - availabilityRecoveredForLocalServers(this); } @@ -1051,7 +1052,7 @@ bool comm::Engine::refreshAvailabilityForLocalServers() { } -void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) { +void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) const { // Check for base protocol codec engine health: try { @@ -1107,16 +1108,16 @@ void comm::Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) { } -void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock &cer) { +void comm::Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock &cer) const { // Check for base protocol codec engine health: assertBaseProtocolHealth(); - if (a_ceaPathfile != "") { + if (getCEA() != "") { anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine()); try { - diameterCEA.loadXMLFile(a_ceaPathfile); + diameterCEA.loadXMLFile(getCEA()); diameterCEA.setHopByHop(anna::diameter::codec::functions::getHopByHop(cer)); diameterCEA.setEndToEnd(anna::diameter::codec::functions::getEndToEnd(cer)); cea = diameterCEA.code(); @@ -1201,7 +1202,7 @@ void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_d std::string destinationRealm, destinationHost; codec::Message codecMsg(getBaseProtocolCodecEngine()); try { - codecMsg.decode(ss->a_cer); + 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(); } @@ -1255,7 +1256,7 @@ void comm::Engine::manageDrDhServerSession(ServerSession *ss, bool register_or_d } } -void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) { +void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) const { // Check for base protocol codec engine health: assertBaseProtocolHealth(); @@ -1277,9 +1278,9 @@ void comm::Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) { // 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(); diff --git a/source/diameter.comm/Entity.cpp b/source/diameter.comm/Entity.cpp index d48b139..eb4893c 100644 --- a/source/diameter.comm/Entity.cpp +++ b/source/diameter.comm/Entity.cpp @@ -442,7 +442,6 @@ void Entity::availabilityLost() { oamModule.count(OamModule::Counter::LostAvailabilityOverEntity); } - a_engine->availabilityLost(this); a_engine->refreshAvailabilityForEntities(); } @@ -467,7 +466,6 @@ void Entity::availabilityRecovered() { oamModule.count(OamModule::Counter::RecoveredAvailabilityOverEntity); } - a_engine->availabilityRecovered(this); a_engine->refreshAvailabilityForEntities(); } diff --git a/source/diameter.comm/LocalServer.cpp b/source/diameter.comm/LocalServer.cpp index a445245..703dc66 100644 --- a/source/diameter.comm/LocalServer.cpp +++ b/source/diameter.comm/LocalServer.cpp @@ -7,10 +7,10 @@ #include -#include #include #include #include +#include #include #include #include @@ -38,7 +38,6 @@ LocalServer::LocalServer() : a_maxConnections(-1), a_currentConnections(0), a_allowedInactivityTime(ServerSession::DefaultAllowedInactivityTime), - a_engine(NULL), a_serverSocket(NULL), a_category(0), a_lock(false), @@ -49,10 +48,6 @@ LocalServer::LocalServer() : void LocalServer::initializeStatisticResources() { std::string accName = "local server '"; accName += anna::functions::socketLiteralAsString(a_key.first, a_key.second); - accName += "' on origin-realm '"; - accName += a_engine ? a_engine->getOriginRealmName() : "unknown"; // it should be known (createServer) - accName += "' and origin-host '"; - accName += a_engine ? a_engine->getOriginHostName() : "unknown"; // it should be known (createServer) accName += "'"; a_messageStatistics.initialize(accName); } @@ -98,7 +93,6 @@ void LocalServer::availabilityLost() { OamModule &oamModule = OamModule::instantiate(); oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServerDefinedAs__s__, socket.c_str()); oamModule.count(OamModule::Counter::LostAvailabilityOverLocalServer); - a_engine->availabilityLost(this); a_engine->refreshAvailabilityForLocalServers(); } @@ -116,7 +110,6 @@ void LocalServer::availabilityRecovered() { OamModule &oamModule = OamModule::instantiate(); oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServerDefinedAs__s__, socket.c_str()); oamModule.count(OamModule::Counter::RecoveredAvailabilityOverLocalServer); - a_engine->availabilityRecovered(this); a_engine->refreshAvailabilityForLocalServers(); } @@ -275,7 +268,6 @@ ServerSession *LocalServer::createServerSession(const anna::comm::ClientSocket & result->a_parent = this; result->a_socketId = key; // de momento... result->initializeSequences(); // despues de asignar el LocalServer y el socketId (sequences are seed-based by mean exclusive hash) - result->a_engine = a_engine; a_serverSessions.insert(serverSession_value_type(key, result)); newConnection(); a_deliveryIterator = serverSession_begin(); @@ -552,7 +544,9 @@ void LocalServer::eventRequestRetransmission(const ServerSession* serverSession, std::string LocalServer::asString() const { std::string result("diameter::comm::LocalServer { "); - result += "Description: "; + result += "Key: "; + result += anna::functions::socketLiteralAsString(getKey().first, getKey().second); + result += " | Description: "; result += (a_description != "") ? a_description : "undefined"; result += " | Available (any server session bound): "; result += a_available ? "yes" : "no"; diff --git a/source/diameter.comm/MessageStatistics.cpp b/source/diameter.comm/MessageStatistics.cpp index 8a87291..00861a8 100644 --- a/source/diameter.comm/MessageStatistics.cpp +++ b/source/diameter.comm/MessageStatistics.cpp @@ -19,7 +19,12 @@ void anna::diameter::comm::MessageStatistics::initialize(const std::string &name) noexcept(false) { - a_accumulator = anna::statistics::Engine::instantiate().createAccumulator(name); + + // Avoid exception if already created (happens for 2 origin hosts with same local server) + a_accumulator = anna::statistics::Engine::instantiate().getAccumulator(name); + + if (!a_accumulator) + a_accumulator = anna::statistics::Engine::instantiate().createAccumulator(name); } diff --git a/source/diameter.comm/OriginHost.cpp b/source/diameter.comm/OriginHost.cpp index 42f1ab3..a518292 100644 --- a/source/diameter.comm/OriginHost.cpp +++ b/source/diameter.comm/OriginHost.cpp @@ -71,6 +71,7 @@ void OriginHost::createDiameterServer(const std::string &serverRepresentation, i anna::functions::getAddressAndPortFromSocketLiteral(serverRepresentation, address, port); std::string serverDescription = "Launcher diameter local server for "; serverDescription += getName(); a_commEngine->setCEA(ceaPathfile); + a_diameterServer = (anna::diameter::comm::LocalServer*)(a_commEngine->createLocalServer(address, port, sessions)); // we could set sessions = 0, and after application run(), use setMaxConnections(real sessions) // over the local server in order to start it. diff --git a/source/diameter.comm/OriginHostManager.cpp b/source/diameter.comm/OriginHostManager.cpp index ff929bf..d5482c1 100644 --- a/source/diameter.comm/OriginHostManager.cpp +++ b/source/diameter.comm/OriginHostManager.cpp @@ -28,6 +28,10 @@ void OriginHostManager::registerOriginHost(const std::string &name, OriginHost* a_origin_hosts[name] = originHost; } +void OriginHostManager::registerRemoteOriginHost(const std::string &remoteName, const std::string &ownName) { + a_remote_to_own_origin_hosts[remoteName] = ownName; +} + anna::xml::Node* OriginHostManager::asXML(anna::xml::Node* parent) const { anna::xml::Node* result = parent->createChild("OriginHostManager"); @@ -39,3 +43,25 @@ anna::xml::Node* OriginHostManager::asXML(anna::xml::Node* parent) const return result; } + +OriginHost *OriginHostManager::getOriginHost(const anna::U32 &applicationId) const { + + OriginHost *result{}; + + for (auto it: a_origin_hosts) { + result = it.second; + if (result->getApplicationId() == applicationId) return result; + } + + return NULL; +} + +OriginHost *OriginHostManager::getOriginHostForRemoteOriginHost(const std::string &name) const { + auto it = a_remote_to_own_origin_hosts.find(name); + + if (it != a_remote_to_own_origin_hosts.end()) + return getOriginHost(it->second); + + return NULL; +} + diff --git a/source/diameter.comm/Server.cpp b/source/diameter.comm/Server.cpp index 4721b10..9cbeb74 100644 --- a/source/diameter.comm/Server.cpp +++ b/source/diameter.comm/Server.cpp @@ -321,24 +321,24 @@ void Server::eventRequestRetransmission(const ClientSession* clientSession, Mess a_parent->eventRequestRetransmission(clientSession, request); } -void Server::eventResponse(const Response& response) noexcept(false) { +void Server::eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father entity: - a_parent->eventResponse(response); + a_parent->eventResponse(response, myNode); } -void Server::eventRequest(ClientSession *clientSession, const anna::DataBlock & request) noexcept(false) { +void Server::eventRequest(ClientSession *clientSession, const anna::DataBlock & request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father entity: - a_parent->eventRequest(clientSession, request); + a_parent->eventRequest(clientSession, request, myNode); } -void Server::eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock & response) noexcept(false) { +void Server::eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock & response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father entity: - a_parent->eventUnknownResponse(clientSession, response); + a_parent->eventUnknownResponse(clientSession, response, myNode); } -void Server::eventDPA(ClientSession *clientSession, const anna::DataBlock & response) noexcept(false) { +void Server::eventDPA(ClientSession *clientSession, const anna::DataBlock & response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father entity: - a_parent->eventDPA(clientSession, response); + a_parent->eventDPA(clientSession, response, myNode); } @@ -355,7 +355,6 @@ void Server::availabilityLost() { OamModule &oamModule = OamModule::instantiate(); oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverServerDefinedAs__s__, socket.c_str()); oamModule.count(OamModule::Counter::LostAvailabilityOverServer); - a_engine->availabilityLost(this); a_parent->refreshAvailability(); } @@ -373,7 +372,6 @@ void Server::availabilityRecovered() { OamModule &oamModule = OamModule::instantiate(); oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverServerDefinedAs__s__, socket.c_str()); oamModule.count(OamModule::Counter::RecoveredAvailabilityOverServer); - a_engine->availabilityRecovered(this); a_parent->refreshAvailability(); } diff --git a/source/diameter.comm/ServerSession.cpp b/source/diameter.comm/ServerSession.cpp index b88da8d..ab7ca11 100644 --- a/source/diameter.comm/ServerSession.cpp +++ b/source/diameter.comm/ServerSession.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -53,9 +55,7 @@ const anna::Millisecond ServerSession::DefaultAllowedInactivityTime(90000); // I ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"), - a_receiverFactory(this), - a_cer(ClassCode::Bind), - a_dwr(ClassCode::ApplicationMessage) // not actually needed; Message is application type by default + a_receiverFactory(this) { initialize(); } void ServerSession::initialize() { @@ -211,22 +211,6 @@ const Response* ServerSession::send(const Message* message) noexcept(false) { updateOutgoingActivityTime(); // OAM countSendings(cid, aid, true /* send ok */); - // Trace non-application messages: - LOGDEBUG( - - if( (cid == helpers::base::COMMANDID__Device_Watchdog_Request) || - (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { - anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); - try { - anna::diameter::codec::Message msg(a_engine->getBaseProtocolCodecEngine()); msg.decode(message->getBody()); /* decode to be traced */ - } - catch(anna::RuntimeException &ex) { - std::string msg = ex.getText(); - msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing"; - anna::Logger::debug(msg, ANNA_FILE_LOCATION); - } - } - ); // Restore sequences: if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix @@ -323,24 +307,54 @@ void ServerSession::eventRequestRetransmission(Message *request) { a_parent->eventRequestRetransmission(this, request); } -void ServerSession::eventResponse(const Response& response) noexcept(false) { +void ServerSession::eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventResponse(response); + a_parent->eventResponse(response, myNode); } -void ServerSession::eventRequest(const anna::DataBlock &request) noexcept(false) { +void ServerSession::eventRequest(const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventRequest(this, request); + a_parent->eventRequest(this, request, myNode); } -void ServerSession::eventUnknownResponse(const anna::DataBlock& response) noexcept(false) { +void ServerSession::eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventUnknownResponse(this, response); + a_parent->eventUnknownResponse(this, response, myNode); } -void ServerSession::eventDPA(const anna::DataBlock& response) noexcept(false) { +void ServerSession::eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) { // Inform father server: - a_parent->eventDPA(this, response); + a_parent->eventDPA(this, response, myNode); +} + + +anna::U32 ServerSession::getAuthApplicationIdFromCER(const anna::DataBlock &cer, bool &found) const { + + anna::U32 result{}; + found = true; + + anna::diameter::codec::Message codecMsg; // codec engine to pre-assigned, but will be inferred from ApplicationId during decoding: + try { codecMsg.decode(cer); } catch(anna::RuntimeException &ex) { ex.trace(); found = false; return result; } + + // Look at first level: + try { + result = codecMsg.getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->getValue(); + } + catch(anna::RuntimeException &ex) { + found = false; + } + + // Look within Vendor-Specific-Application-Id: + if (!found) { + try { + result = codecMsg.getAvp(helpers::base::AVPID__Vendor_Specific_Application_Id)->getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->getValue(); + } + catch(anna::RuntimeException &ex) { + found = false; + } + } + + return result; } //------------------------------------------------------------------------------------------ @@ -349,6 +363,8 @@ void ServerSession::eventDPA(const anna::DataBlock& response) noexcept(false) { void ServerSession::receive(const anna::comm::Message& message) noexcept(false) { LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION)); + + // Activity: updateIncomingActivityTime(); activateTimer(); @@ -360,18 +376,6 @@ noexcept(false) { std::string msg = "Received diameter message: "; msg += anna::diameter::functions::commandIdAsPairString(cid); anna::Logger::debug(msg, ANNA_FILE_LOCATION); - - if( (cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || - (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) { - try { - anna::diameter::codec::Message dmsg(a_engine->getBaseProtocolCodecEngine()); dmsg.decode(db); /* decode to be traced */ - } - catch(anna::RuntimeException &ex) { - std::string msg = ex.getText(); - msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing"; - anna::Logger::debug(msg, ANNA_FILE_LOCATION); - } - } ); // Main counters: OamModule &oamModule = OamModule::instantiate(); @@ -380,6 +384,16 @@ noexcept(false) { // Statistic (size) a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize(), cid); // only on reception (application could manage sent sizes) + // OriginHostManager (to register remote origin host in order to associate with specific comm engine): + anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate(); + + // Extract OriginHost from datablock (db): + std::string remoteOriginHost = anna::diameter::helpers::base::functions::getOriginHost(db); + LOGDEBUG(anna::Logger::debug(anna::functions::asString("REMOTE ORIGIN HOST FOR THE MESSAGE RECEIVED: %s", remoteOriginHost.c_str()), ANNA_FILE_LOCATION)); + + // Now, get the corresponding own origin host for it; in case of CER received, this will be unkonwn: + const anna::diameter::comm::OriginHost *originHost = ohm.getOriginHostForRemoteOriginHost(remoteOriginHost); + if(isRequest) { // Si recibo un request, el message solo tiene fiable el DataBlock. Como por defecto se construye como ApplicationMessage, // el unico caso que no cuadraria seria la recepcion de un CER. Lo que hacemos es NO PROGRESAR NUNCA un CER (*). @@ -390,17 +404,35 @@ noexcept(false) { // Received CER if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) { + + // For CERs, we need to extract the Auth-Application-Id: + bool found; + anna::U32 authApplicationId = getAuthApplicationIdFromCER(db, found); + + // Now, sequential search in OriginHostManager for that id: + anna::diameter::comm::OriginHost *originHost = ohm.getOriginHost(authApplicationId); + + if (!originHost) { + LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION with received CER. TODO: send CEA with that result code", ANNA_FILE_LOCATION)); + unbind(true /* always immediate */); + return; + } + + // Map origin host of received CER, to own OriginHost pointer. This will be used in future: DWR, DPR, normal messages + ohm.registerRemoteOriginHost(remoteOriginHost, originHost->getName()); + + + // OAM oamModule.count(OamModule::Counter::CERReceived); if(a_state == State::Bound) { LOGWARNING(anna::Logger::warning("Received another CER over already bound connection. Anyway, will be replied with CEA", ANNA_FILE_LOCATION)); } - a_cer.setBody(db); // Basic DRA: - getParent()->getEngine()->manageDrDhServerSession(this, true /* register */); + originHost->getCommEngine()->manageDrDhServerSession(this, true /* register */); - sendCEA(); + sendCEA(originHost->getCommEngine(), db); //activateTimer(); // Ya se invoca al inicio de este metodo ::receive //bool changes = a_parent->refreshAvailability(); return; // (*) @@ -408,20 +440,23 @@ noexcept(false) { // Received DWR else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) { oamModule.count(OamModule::Counter::DWRReceived); - a_dwr.setBody(db); - sendDWA(); + + if (!originHost) return; // TODO, responding DWA with result code error + + sendDWA(originHost->getCommEngine(), db); return; // (**) } // Received DPR else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) { oamModule.count(OamModule::Counter::DPRReceived); + if (!originHost) return; // TODO, responding DPA with result code error + if(a_state == State::Bound) { - a_dpr.setBody(db); setState(State::Disconnecting); LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter client)", ANNA_FILE_LOCATION)); // Ignore pending on server sessions: - /*if (getOTARequests() == 0) */sendDPA(); + /*if (getOTARequests() == 0) */sendDPA(originHost->getCommEngine(), db); return; // DPR won't be informed because virtual readDPA is available for this } } @@ -430,7 +465,9 @@ noexcept(false) { // application message counters ApplicationMessageOamModule::instantiate().count(cid.first, -1 /* no result code */, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsServer); - eventRequest(db); + if (!originHost) return; // TODO, responding DWA with result code error + + eventRequest(db, originHost); } catch(anna::RuntimeException& ex) { ex.trace(); } @@ -464,7 +501,8 @@ noexcept(false) { } } - eventDPA(db); + if (originHost) + eventDPA(db, originHost); } else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { // non usual (server should not send DWR's) oamModule.count(OamModule::Counter::DWAReceived); @@ -483,7 +521,8 @@ noexcept(false) { // application message counters ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsServer); - eventUnknownResponse(db); + if (originHost) + eventUnknownResponse(db, originHost); string msg(asString()); msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop); @@ -534,7 +573,8 @@ noexcept(false) { // application message counters ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsServer); - eventResponse(*response); + if (originHost) + eventResponse(*response, originHost); } catch(anna::RuntimeException& ex) { ex.trace(); @@ -584,11 +624,12 @@ void ServerSession::finalize() { -void ServerSession::sendCEA() +void ServerSession::sendCEA(const Engine *commEngine, const anna::DataBlock &cerDataBlock) noexcept(false) { LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendCEA", ANNA_FILE_LOCATION)); + anna::DataBlock cea(true); - a_engine->readCEA(cea, a_cer.getBody()); // Asume that CEA is valid ... + commEngine->readCEA(cea, cerDataBlock); // Asume that CEA is valid ... // If one peer sends a CER message to another Peer and receiver does not have support for // // 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION @@ -635,11 +676,11 @@ noexcept(false) { } } -void ServerSession::sendDWA() +void ServerSession::sendDWA(const Engine *commEngine, const anna::DataBlock &dwrDataBlock) noexcept(false) { LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWA", ANNA_FILE_LOCATION)); anna::DataBlock dwa(true); - a_engine->readDWA(dwa, a_dwr.getBody()); // Asume that DWA is valid ... + commEngine->readDWA(dwa, dwrDataBlock); // Asume that DWA is valid ... if(dwa.isEmpty()) throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote client never will validate this connection health", ANNA_FILE_LOCATION); diff --git a/source/diameter.comm/Session.cpp b/source/diameter.comm/Session.cpp index 4fb5ab4..d80175f 100644 --- a/source/diameter.comm/Session.cpp +++ b/source/diameter.comm/Session.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -53,10 +55,8 @@ const int Session::DefaultPort(3868); Session::Session(const char *className, const char *timerName) : anna::timex::Timer(timerName, (anna::Millisecond)0) /* not assigned */, a_className(className), a_timeController(NULL), - a_engine(NULL), a_notifyOrphansOnExpiration(true), - a_actionTimer(NULL), - a_dpr(ClassCode::ApplicationMessage) { // realmente no es necesario, los Message son por defecto de aplicacion + a_actionTimer(NULL) { initialize(); } @@ -114,11 +114,11 @@ void Session::initializeSequences() { a_nextEndToEnd = ((::time(NULL) & 0xFFF) << 20) + (rand() & 0xFFFFF); } -void Session::sendDPA() +void Session::sendDPA(const Engine *commEngine, const anna::DataBlock &dprDataBlock) noexcept(false) { LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "sendDPA", ANNA_FILE_LOCATION)); anna::DataBlock dpa(true); - a_engine->readDPA(dpa, a_dpr.getBody()); // Asume that DPA is valid ... + commEngine->readDPA(dpa, dprDataBlock); // Asume that DPA is valid ... if(dpa.isEmpty()) { LOGWARNING(anna::Logger::warning("This diameter agent defines an empty DPA message. Remote disconnection DPR will be ignored going to the Bound state", ANNA_FILE_LOCATION)); @@ -252,9 +252,17 @@ void Session::expireResponse(diameter::comm::Response* response) doUnbind = true; // (*) + // Get origin host corresponding to the message: + anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate(); + + // Extract OriginHost from datablock (db): + std::string originHostName = anna::diameter::helpers::base::functions::getOriginHost(response->getRequest()->getBody()); + LOGDEBUG(anna::Logger::debug(anna::functions::asString("ORIGIN HOST FOR THE MESSAGE WHICH WAS EXPIRED: %s", originHostName.c_str()), ANNA_FILE_LOCATION)); + anna::diameter::comm::OriginHost *originHost = ohm.getOriginHost(originHostName); + try { response->setMessage(NULL); - eventResponse(*response); + eventResponse(*response, originHost); } catch(anna::RuntimeException& ex) { ex.trace(); } @@ -338,7 +346,9 @@ void Session::finalize() { try { response->setMessage(NULL); - eventResponse(*response); + eventResponse(*response, nullptr); // upstream, we need to check second argument to know if comes from here. + // If originHost is NULL, and we are client, we could access through engine: a_engine->getOriginHostName(), and then ohm.getOriginHost(name). BUT CLIENTS DO NOTHING WITH THIS ARGUMENT. + // If server, we must return there: add protection for second argument. } catch(anna::RuntimeException& ex) { ex.trace(); } @@ -370,7 +380,10 @@ void Session::response_erase(Response* response) Response::release(response); if(a_state == State::Disconnecting) // only OnDisconnect::WaitPendings arrives here (the other disconnect suddently) - if(getOTARequests() == 0) sendDPA(); + if(getOTARequests() == 0) { + // TODO: decode response->getRequest(), which is a comm message, so we get Origin-Host, and then, from OriginHostManager, we get the commEngine to provide: + //sendDPA(commEngine, dprDataBlock); + } if(a_state == State::Closing) // only OnDisconnect::WaitPendings arrives here (the other disconnect suddently) if(getOTARequests() == 0) unbind(); -- 2.20.1