From e80e62a5cf9aacad1a9551c68c432147ef98cd29 Mon Sep 17 00:00:00 2001 From: Eduardo Ramos Testillano Date: Sun, 27 Sep 2015 23:45:37 +0200 Subject: [PATCH] Hard refactoring. CodecEngine is associated to a unique stack. --- .gitignore | 1 + example/diameter/batchConverter/main.cpp | 47 +- example/diameter/launcher/Launcher.cpp | 570 ++++++++++-------- example/diameter/launcher/Launcher.hpp | 28 +- .../diameter/launcher/MyDiameterEntity.cpp | 12 +- .../diameter/launcher/MyDiameterEntity.hpp | 3 - example/diameter/launcher/MyLocalServer.cpp | 35 +- example/diameter/launcher/MyLocalServer.hpp | 3 - .../diameter/launcher/ProgrammedAnswers.cpp | 146 +++-- .../diameter/launcher/ProgrammedAnswers.hpp | 3 - example/diameter/launcher/RealmNode.cpp | 30 +- example/diameter/launcher/RealmNode.hpp | 7 +- example/diameter/launcher/main.cpp | 5 +- .../resources/scripts/operation_tps.sh | 2 +- .../resources/services_examples/balancer.xml | 4 +- .../resources/services_examples/client.xml | 2 +- .../resources/services_examples/dummy.xml | 2 +- .../services_examples/multi-client.xml | 8 +- .../resources/services_examples/server.xml | 2 +- .../resources/services_examples/services.dtd | 17 +- .../diameter/launcher/testing/TestCase.cpp | 13 +- .../diameter/launcher/testing/TestCase.hpp | 5 +- .../launcher/testing/TestCondition.cpp | 60 +- .../launcher/testing/TestCondition.hpp | 20 +- .../diameter/launcher/testing/TestManager.cpp | 23 +- .../diameter/launcher/testing/TestManager.hpp | 6 +- .../diameter/launcher/testing/TestStep.cpp | 67 +- .../diameter/launcher/testing/TestStep.hpp | 48 +- example/diameter/tme/main.cpp | 9 +- include/anna/diameter/codec/Avp.hpp | 34 +- include/anna/diameter/codec/Engine.hpp | 2 +- include/anna/diameter/codec/EngineImpl.hpp | 96 +-- include/anna/diameter/codec/EngineManager.hpp | 131 ++++ include/anna/diameter/codec/Message.hpp | 116 ++-- include/anna/diameter/codec/functions.hpp | 281 +++++++-- include/anna/diameter/codec/tme/Avp.hpp | 21 +- .../codec/tme/{Engine.hpp => Engine.hpp__} | 0 include/anna/diameter/codec/tme/Message.hpp | 24 +- include/anna/xml/DTDFile.hpp | 6 +- include/anna/xml/DTDMemory.hpp | 6 +- source/diameter.comm/Engine.cpp | 3 +- source/diameter/codec/Avp.cpp | 38 +- source/diameter/codec/EngineImpl.cpp | 97 +-- source/diameter/codec/EngineManager.cpp | 28 + source/diameter/codec/Message.cpp | 170 +++--- source/diameter/codec/functions.cpp | 131 ++-- source/diameter/codec/tme/Avp.cpp | 50 +- source/diameter/codec/tme/Message.cpp | 20 +- source/xml/DTDFile.cpp | 2 +- source/xml/DTDMemory.cpp | 7 +- 50 files changed, 1401 insertions(+), 1040 deletions(-) create mode 100644 include/anna/diameter/codec/EngineManager.hpp rename include/anna/diameter/codec/tme/{Engine.hpp => Engine.hpp__} (100%) create mode 100644 source/diameter/codec/EngineManager.cpp diff --git a/.gitignore b/.gitignore index 5f06328..5507480 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ docs/doxygen/man *.old .cproject .project +/Debug/ diff --git a/example/diameter/batchConverter/main.cpp b/example/diameter/batchConverter/main.cpp index 7232973..5ccf1c8 100644 --- a/example/diameter/batchConverter/main.cpp +++ b/example/diameter/batchConverter/main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include //#include // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException); @@ -30,8 +31,7 @@ using namespace anna; using namespace anna::diameter; -anna::diameter::codec::Message *G_codecMsg; -anna::diameter::codec::Engine *G_codecEngine; +anna::diameter::codec::Message G_codecMsg; bool getDataBlockFromHexFile(const std::string &pathfile, anna::DataBlock &db) throw() { // Get hex string @@ -70,9 +70,7 @@ void _exit(const std::string &message, int resultCode = 1) { // Decodes a diameter message coming from a datablock void decodeDataBlock(const anna::DataBlock &db/*, unsigned int & detectedApplicationId*/) throw() { try { - //detectedApplicationId = anna::diameter::codec::functions::getApplicationId(db); - //G_codecEngine->setDictionary(detectedApplicationId); we enabled this feature in the codec engine: selectStackWithApplicationId(true); - G_codecMsg->decode(db); + G_codecMsg.decode(db); } catch(RuntimeException &ex) { _exit(ex.asString()); } @@ -122,12 +120,13 @@ int main(int argc, char **argv) { bool processHex = xmlOnly ? false:true; Logger::setLevel(debug ? Logger::Debug:Logger::Warning); Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000)); - G_codecEngine = new anna::diameter::codec::Engine("MyCodecEngine"); - G_codecMsg = G_codecEngine->createMessage(); anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate(); + anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate(); + anna::diameter::codec::Engine *ce; + unsigned int appid = 0; + // Register stacks: - bool multistack = false; try { anna::Tokenizer stacksTok; stacksTok.apply(stacks, "#"); @@ -141,26 +140,25 @@ int main(int argc, char **argv) { if(stackTok.size() == 1) { if(stacksTok.size() != 1) throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION); - - anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* no matter */, stack); // the stack is the dictionary - G_codecEngine->setDictionary(d); + anna::diameter::stack::Dictionary *d = stackEngine.createDictionary(appid, stack); // the stack is the dictionary + ce = new anna::diameter::codec::Engine("CodecEngineForUniqueStackId_0", d); + em.registerCodecEngine(0, ce); break; } if(stackTok.size() != 2) throw anna::RuntimeException("Each stack must be in the form ','", ANNA_FILE_LOCATION); - multistack = true; stack_it = stackTok.begin(); unsigned int stackId = atoll(anna::Tokenizer::data(stack_it)); stack_it++; std::string file = anna::Tokenizer::data(stack_it); - anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(stackId, file); + anna::diameter::stack::Dictionary *d = stackEngine.createDictionary(stackId, file); + std::string codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", stackId); + ce = new anna::diameter::codec::Engine(codecEngineName.c_str(), d); + em.registerCodecEngine(stackId, ce); } - // Auto stack selection based on Application-ID: - if (multistack) G_codecEngine->selectStackWithApplicationId(true); - std::cout << "Stacks provided: " << std::endl; std::cout << anna::functions::tab(stackEngine.asString(false /* light */)); std::cout << std::endl; @@ -173,10 +171,13 @@ int main(int argc, char **argv) { } // Validation kindness - G_codecEngine->setFixMode(anna::diameter::codec::EngineImpl::FixMode::Never); // we will encode "as is" (because --no-validation is assumed as user desire) - G_codecEngine->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports - if(no_validation) G_codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never); - if(ignore_flags) G_codecEngine->ignoreFlagsOnValidation(true); + for (anna::diameter::codec::appid_codec_engines_it it = em.begin(); it != em.end(); it++) { + ce = it->second; + ce->setFixMode(anna::diameter::codec::EngineImpl::FixMode::Never); // we will encode "as is" (because --no-validation is assumed as user desire) + ce->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports + if(no_validation) ce->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never); + if(ignore_flags) ce->ignoreFlagsOnValidation(true); + } // Auxiliary variables: anna::DataBlock db_aux(true); @@ -205,7 +206,7 @@ int main(int argc, char **argv) { // Write conversion: std::string outputFile = entry + ".as.xml"; std::ofstream out(outputFile.c_str(), std::ifstream::out); - out << G_codecMsg->asXMLString(); + out << G_codecMsg.asXMLString(); out.close(); anyHexConverted = true; @@ -220,10 +221,10 @@ int main(int argc, char **argv) { LOGDEBUG(anna::Logger::debug(entry + " is being converted to hex", ANNA_FILE_LOCATION)); // Load file: - G_codecMsg->loadXML(entry); + G_codecMsg.loadXML(entry); // Write conversion: - std::string hexString = anna::functions::asHexString(G_codecMsg->code()); + std::string hexString = anna::functions::asHexString(G_codecMsg.code()); std::string outputFile = entry + ".as.hex"; std::ofstream out(outputFile.c_str(), std::ifstream::out); out.write(hexString.c_str(), hexString.size()); diff --git a/example/diameter/launcher/Launcher.cpp b/example/diameter/launcher/Launcher.cpp index 8f3cacd..f7921e7 100644 --- a/example/diameter/launcher/Launcher.cpp +++ b/example/diameter/launcher/Launcher.cpp @@ -15,7 +15,9 @@ // Project #include #include +#include #include +#include #include #include #include @@ -35,7 +37,6 @@ #define SIGUSR2_TASKS_OUTPUT_FILENAME "./sigusr2.out" - const char *ServicesDTD = "\ \n\ \n\ @@ -43,22 +44,27 @@ const char *ServicesDTD = "\ \n\ \n\ \n\ -\n\ +\n\ \n\ \n\ \n\ -\n\ +\n\ "; - result += "\n "; + result += "\n "; result += "\n"; result += "\n"; result += "\nServer configuration:"; @@ -837,7 +905,7 @@ std::string Launcher::help() const throw() { result += "\n "; result += "\n"; result += "\n "; - result += "\n "; + result += "\n "; result += "\n"; result += "\n"; result += "\nIf you act as a proxy or a translation agent, you need to combine both former setups, and probably"; @@ -854,8 +922,8 @@ std::string Launcher::help() const throw() { result += "\n "; result += "\n"; result += "\n "; - result += "\n "; - result += "\n "; + result += "\n "; + result += "\n "; result += "\n"; result += "\n"; result += "\n"; @@ -875,11 +943,24 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\nhelp This help."; result += "\n"; - result += "\n---------------------------------------------------------------------------------------- Node selection"; - result += "\n"; - result += "\nnode[|] Select current working node by mean the registered name."; - result += "\n All the subsequent operations will be referred to this node."; - result += "\n Without argument, the current node information is retrieved."; + result += "\n--------------------------------------------------------------------------------------- Node management"; + result += "\n"; + result += "\nnode[|] Selects a context working node by mean a registered name."; + result += "\n All the subsequent operations will be forced to work with"; + result += "\n this node, which makes possible some rare scenarios like"; + result += "\n sending unexpected messages on remote peers. This is also"; + result += "\n useful for some operations in order to restrict the scope"; + result += "\n of action (statistics, communication visibility, etc.)."; + result += "\n Empty parameter will show the current configuration."; + result += "\n"; + result += "\nnode_auto Returns to the default behaviour (smart node selection)."; + result += "\n Depending on the operation, this could imply a global"; + result += "\n action scope, affecting to all the registered realms."; + result += "\n This should be the normal configuration. Take into"; + result += "\n account that if you fix the working node, this could"; + result += "\n affect to things like test programming: communication"; + result += "\n resources will override those which would be inferred"; + result += "\n from programmed messages Origin-Realm avps."; result += "\n"; result += "\n------------------------------------------------------------------------------------ Parsing operations"; result += "\n"; @@ -904,8 +985,10 @@ std::string Launcher::help() const throw() { result += "\n default '/var/tmp/anna.context.' will be used."; result += "\ncollect Reset statistics and counters to start a new test stage of"; result += "\n performance measurement. Context data can be written at"; - result += "\n '/var/tmp/anna.context.' by mean 'kill -10 '"; + result += "\n '/var/tmp/anna.context.' by mean 'kill -10 '."; result += "\n or sending operation 'context|[target file]'."; + result += "\n This operation applies over all the registered realm nodes"; + result += "\n except if one specific working node has been set."; result += "\nforceCountersRecord Forces dump to file the current counters of the process."; result += "\n"; result += "\n[|
:][|socket id]"; @@ -924,20 +1007,18 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\nsendxml2e| Sends xml source file (pathfile) through configured entity."; result += "\nsendxml2c| Sends xml source file (pathfile) to client."; - result += "\nsendxml| Same as 'sendxml2e'."; result += "\nanswerxml2e[|source_file] Answer xml source file (pathfile) for incoming request with same code from entity."; result += "\n The answer is stored in a FIFO queue for a specific message code, then there are"; result += "\n as many queues as different message codes have been programmed."; result += "\nanswerxml2c[|source_file] Answer xml source file (pathfile) for incoming request with same code from client."; result += "\n The answer is stored in a FIFO queue for a specific message code, then there are"; result += "\n as many queues as different message codes have been programmed."; - result += "\nanswerxml[|source_file] Same as 'answerxml2c'."; - result += "\nanswerxml(2e/2c) List programmed answers (to entity/client) if no parameter provided."; - result += "\nanswerxml(2e/2c)|dump Write programmed answers (to entity/client) to file 'programmed_answer..',"; + result += "\nanswerxml<2e/2c> List programmed answers (to entity/client) if no parameter provided."; + result += "\nanswerxml<2e/2c>|dump Write programmed answers (to entity/client) to file 'programmed_answer..',"; result += "\n where 'sequence' is the order of the answer in each FIFO code-queue of programmed answers."; - result += "\nanswerxml(2e/2c)|clear Clear programmed answers (to entity/client)."; - result += "\nanswerxml(2e/2c)|exhaust Disable the corresponding queue rotation, which is the default behaviour."; - result += "\nanswerxml(2e/2c)|rotate Enable the corresponding queue rotation, useful in performance tests."; + result += "\nanswerxml<2e/2c>|clear Clear programmed answers (to entity/client)."; + result += "\nanswerxml<2e/2c>|exhaust Disable the corresponding queue rotation, which is the default behaviour."; + result += "\nanswerxml<2e/2c>|rotate Enable the corresponding queue rotation, useful in performance tests."; result += "\n Rotation consists in add again to the queue, each element retrieved for answering."; result += "\n"; result += "\nSend operations are available using hexadecimal content (hex formatted files) which also allow to test"; @@ -945,13 +1026,12 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\nsendhex2e| Sends hex source file (pathfile) through configured entity."; result += "\nsendhex2c| Sends hex source file (pathfile) to client."; - result += "\nsendhex| Same as 'sendhex2e'."; result += "\n"; result += "\nAnswer programming in hexadecimal is not really neccessary (you could use send primitives) and also"; result += "\n is intended to be used with decoded messages in order to replace things like hop by hop, end to end,"; result += "\n subscriber id, session id, etc. Anyway you could use 'decode' operation and then program the xml created."; result += "\n"; - result += "\nIf a request is received, answer map (built with 'answerxml<[2c] or 2e>' operations) will be"; + result += "\nIf a request is received, answer map (built with 'answerxml<2e/2c>' operations) will be"; result += "\n checked to find a corresponding programmed answer to be replied(*). If no ocurrence is found,"; result += "\n or answer message was received, the message is forwarded to the other side (entity or client),"; result += "\n or nothing but trace when no peer at that side is configured. Answer to client have sense when"; @@ -964,7 +1044,7 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n(*) sequence values (hop-by-hop and end-to-end), Session-Id and Subscription-Id avps, are mirrored"; result += "\n to the peer which sent the request. If user wants to test a specific answer without changing it,"; - result += "\n use sendxml/sendhex operations better than programming."; + result += "\n use sendxml<2e/2c>/sendhex<2e/2c> operations better than programming."; result += "\n"; result += "\nBalance ('--balance' command line parameter) could be used to forward server socket receptions through"; result += "\n entity servers by mean a round-robin algorithm. Both diameter server socket and entity targets should"; @@ -992,6 +1072,12 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n------------------------------------------------------------------------------------------- Burst tests"; result += "\n"; + result += "\nIn order to simplify user experience, burst category operations are only allowed in single realm node"; + result += "\n configuration. Indeed, you could send messages with incorrect Origin-Realm, and no warning is shown."; + result += "\nAll the operations are performed through the unique realm: if you need to use more interfaces, you may"; + result += "\n launch different ADML instances. Is nonsense to allow burst in a multi-realm configured ADML, because"; + result += "\n this feature is not able to coordinate the messages."; + result += "\n"; result += "\nburst|[|parameter] Used for performance testing, we first program diameter requests"; result += "\n messages in order to launch them from client side to the configured"; result += "\n diameter entity. We could start the burst with an initial load"; @@ -1030,7 +1116,9 @@ std::string Launcher::help() const throw() { result += "\n Adds a new step to the test case with provided identifier. If provided identifier"; result += "\n is not registered yet, a new test case will be created with that value and the"; result += "\n step will be added as the first. For a specific 'id', the steps are stored in"; - result += "\n order as they are programmed"; + result += "\n order as they are programmed. Check possible runtime exceptions when adding a"; + result += "\n new step because those which fail, will be ignored/skipped during test case"; + result += "\n programming giving an incomplete sequence invalid for the testing purpose."; result += "\n"; result += "\n : integer number, normally monotonically increased for each test case. Some external"; result += "\n script/procedure shall clone a test case template in order to build a collection"; @@ -1104,14 +1192,14 @@ std::string Launcher::help() const throw() { result += "\n a real unexpected message)."; // TODO(***) -// result += "\n The way to identify the test case, is through registered Session-Id values for"; -// result += "\n programmed requests. But this depends on the type of node. Acting as clients,"; -// result += "\n requests received have Session-Id values which are already registered with"; -// result += "\n one test case, causing an error if not found. Acting as servers, requests are"; -// result += "\n received over a diameter local server from a client which are generating that"; -// result += "\n Session-Id values. Then we know nothing about such values. The procedure in"; -// result += "\n this case is find out a test case not-started containing a condition which"; -// result += "\n comply with the incoming message, and reactivates it."; + // result += "\n The way to identify the test case, is through registered Session-Id values for"; + // result += "\n programmed requests. But this depends on the type of node. Acting as clients,"; + // result += "\n requests received have Session-Id values which are already registered with"; + // result += "\n one test case, causing an error if not found. Acting as servers, requests are"; + // result += "\n received over a diameter local server from a client which are generating that"; + // result += "\n Session-Id values. Then we know nothing about such values. The procedure in"; + // result += "\n this case is find out a test case not-started containing a condition which"; + // result += "\n comply with the incoming message, and reactivates it."; // The other solution: register Session-Id values for answers send to client from a local diameter server. result += "\n How to answer: a wait condition for a request will store the incoming message"; @@ -1126,12 +1214,10 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n Condition format:"; result += "\n"; - result += "\n [code]|[bitR]|[ResultCode]|[sessionId]|[hopByHop]|[msisdn]|[imsi]|[serviceContextId]"; + result += "\n [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]"; result += "\n"; result += "\n code: integer number"; result += "\n bitR: 1 (request), 0 (answer)"; - result += "\n ResultCode: integer number"; - result += "\n sessionId: string"; result += "\n hopByHop: integer number or request send step reference: #"; result += "\n"; result += "\n Using the hash reference, you would indicate a specific wait condition"; @@ -1140,6 +1226,9 @@ std::string Launcher::help() const throw() { result += "\n This 'hop-by-hop' variant eases the wait condition for answers in the"; result += "\n safest way."; result += "\n"; + result += "\n applicationId: integer number"; + result += "\n sessionId: string"; + result += "\n resultCode: integer number"; result += "\n msisdn: string"; result += "\n imsi: string"; result += "\n serviceContextId: string"; @@ -1167,14 +1256,14 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n test|1|timeout|5000 (step 1: whole time requirement is 5 seconds)"; result += "\n test|1|sendxml2e|CCR-I.xml (step 2: imagine this xml uses the Session-Id 'SGx')"; - result += "\n test|1|waitfe|272|0|2001|SGx (step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS)"; + result += "\n test|1|waitfe|272|0|||SGx|2001 (step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS)"; result += "\n test|1|sendxml2e|AAR-flows.xml (step 4: imagine this xml uses the Session-Id 'SRx')"; - result += "\n test|1|waitfe|265|0|2001|SRx (step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS)"; - result += "\n test|1|waitfe|258|1||SGx (step 6: waits the RAR (install policies) from the PCRF server)"; + result += "\n test|1|waitfe|265|0|||SRx|2001 (step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS)"; + result += "\n test|1|waitfe|258|1|||SGx (step 6: waits the RAR (install policies) from the PCRF server)"; result += "\n test|1|sendxml2e|RAA-install.xml|6 (step 7: sends the response for the RAR)"; result += "\n test|1|sendxml2e|CCR-T.xml (step 8: termination of the Gx session, imagine this xml puts hop-by-hop 'H1')"; - result += "\n test|1|waitfe|272|0|2001|SGx|H1 (step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1')"; - result += "\n test|1|waitfe|258|1||SGx (step 10: waits the RAR (remove policies) from the PCRF server)"; + result += "\n test|1|waitfe|272|0|H1||SGx|2001 (step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1')"; + result += "\n test|1|waitfe|258|1|||SGx (step 10: waits the RAR (remove policies) from the PCRF server)"; result += "\n test|1|sendxml2e|RAA-remove.xml|10 (step 11: sends the response for the RAR)"; result += "\n"; result += "\n Notes: We added an additional condition in step 9: the hop-by-hop. When we program the corresponding"; @@ -1196,9 +1285,9 @@ std::string Launcher::help() const throw() { result += "\n"; result += "\n Other simplifications: the steps 3, 5 and 9 can be replaced by"; result += "\n"; - result += "\n test|1|waitfe||0|||#2"; - result += "\n test|1|waitfe||0|||#4"; - result += "\n test|1|waitfe||0|||#8"; + result += "\n test|1|waitfe||0|#2"; + result += "\n test|1|waitfe||0|#4"; + result += "\n test|1|waitfe||0|#8"; result += "\n"; result += "\n which means that hop-by-hop must be retrieved from steps 2, 4 and 8 respectively,"; result += "\n and the expected message shall be an answer. Normally you will add other conditions,"; @@ -1304,18 +1393,19 @@ std::string Launcher::help() const throw() { void Launcher::eventOperation(const std::string &operation, std::string &response_content) throw(anna::RuntimeException) { LOGMETHOD(anna::TraceMethod tm("Launcher", "eventOperation", ANNA_FILE_LOCATION)); if (operation == "") return; // ignore - - CommandLine& cl(anna::CommandLine::instantiate()); - TestManager &testManager = TestManager::instantiate(); LOGDEBUG(anna::Logger::debug(operation, ANNA_FILE_LOCATION)); // Default response: response_content = "Operation processed with exception (see traces): "; response_content += operation; - - std::string opt_response_content = ""; // aditional response content anna::DataBlock db_aux(true); + anna::diameter::codec::Message codecMsg; // auxiliary codec message + + // Singletons: + CommandLine& cl(anna::CommandLine::instantiate()); + TestManager &testManager = TestManager::instantiate(); + /////////////////////////////////////////////////////////////////// // Simple operations without arguments: @@ -1350,7 +1440,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons // Get the operation type and parameters: Tokenizer::const_iterator tok_iter = params.begin(); std::string opType = Tokenizer::data(tok_iter); - std::string param1, param2, param3, param4, param5, param6, param7, param8, param9, param10; + std::string param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11; if(numParams >= 1) { tok_iter++; param1 = Tokenizer::data(tok_iter); } if(numParams >= 2) { tok_iter++; param2 = Tokenizer::data(tok_iter); } if(numParams >= 3) { tok_iter++; param3 = Tokenizer::data(tok_iter); } @@ -1362,6 +1452,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(numParams >= 8) { tok_iter++; param8 = Tokenizer::data(tok_iter); } if(numParams >= 9) { tok_iter++; param9 = Tokenizer::data(tok_iter); } if(numParams >= 10) { tok_iter++; param10 = Tokenizer::data(tok_iter); } + if(numParams >= 11) { tok_iter++; param11 = Tokenizer::data(tok_iter); } // Remove '' artificial token to ease further checkings: if (param1 == "") param1 = ""; if (param2 == "") param2 = ""; @@ -1373,6 +1464,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if (param8 == "") param8 = ""; if (param9 == "") param9 = ""; if (param10 == "") param10 = ""; + if (param11 == "") param11 = ""; // No operation has more than 2 arguments except 'test' ... if(opType != "test" && numParams > 2) @@ -1383,10 +1475,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons bool wrongBody = false; if((opType == "node") && (numParams > 1)) wrongBody = true; + if((opType == "node_auto") && (numParams > 0)) wrongBody = true; if(((opType == "code") || (opType == "decode")) && (numParams != 2)) wrongBody = true; - if(((opType == "sendxml") || (opType == "sendxml2e") || (opType == "sendhex") || (opType == "sendhex2e")) && (numParams != 1)) wrongBody = true; + if(((opType == "sendxml2e") || (opType == "sendhex2e")) && (numParams != 1)) wrongBody = true; if((opType == "burst") && (numParams < 1)) wrongBody = true; @@ -1427,19 +1520,31 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons // Realm switch: if(opType == "node") { if (param1 != "") { - if (setWorkingNode(param1)) response_content = anna::functions::asString("Current node is now '%s'", param1.c_str()); + if (setWorkingNode(param1)) response_content = anna::functions::asString("Forced node is now '%s'", param1.c_str()); } else { - response_content = getWorkingNode()->asXMLString(); + if (a_workingNode) { + response_content = "Working node is forced to be: \n\n"; + response_content += a_workingNode->asXMLString(); + } + else { + response_content = "Working node is automatic"; + } } return; } + if(opType == "node_auto") { + a_workingNode = NULL; + response_content = "Working node has been set to automatic"; + return; + } - // Diameter endpoints: - MyDiameterEntity *entity = getWorkingNode()->getEntity(); - MyDiameterEngine *commEngine = getWorkingNode()->getMyDiameterEngine(); - MyLocalServer *localServer = getWorkingNode()->getDiameterServer(); - anna::diameter::codec::Message codecMsg(getCodecEngine()); + // Operated realm from possible forced-working node: + a_operatedRealm = a_workingNode ? a_workingNode /* priority */: NULL /* auto */; + // Use later: + // If any message is managed: updateOperatedRealmNodeWithMessage(codecMessage) + // To operate, use the exception-protected methods which never will return NULL: + // getOperatedRealm(), getOperatedEntity(), getOperatedServer(), getOperatedEngine() if(opType == "code") { @@ -1463,7 +1568,6 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons outfile.write(xmlString.c_str(), xmlString.size()); outfile.close(); } else if((opType == "hide") || (opType == "show") || (opType == "hidden") || (opType == "shown")) { - if(!entity) throw anna::RuntimeException("No entity configured to send messages", ANNA_FILE_LOCATION); if(param1 != "") { if(param2 != "") { @@ -1471,65 +1575,68 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons key += "|"; key += param2; - if(opType == "hide") commEngine->findClientSession(key)->hide(); + if(opType == "hide") getOperatedEngine()->findClientSession(key)->hide(); - if(opType == "show") commEngine->findClientSession(key)->show(); + if(opType == "show") getOperatedEngine()->findClientSession(key)->show(); - if(opType == "hidden") opt_response_content = commEngine->findClientSession(key)->hidden() ? "true" : "false"; + if(opType == "hidden") opt_response_content = getOperatedEngine()->findClientSession(key)->hidden() ? "true" : "false"; - if(opType == "shown") opt_response_content = commEngine->findClientSession(key)->shown() ? "true" : "false"; + if(opType == "shown") opt_response_content = getOperatedEngine()->findClientSession(key)->shown() ? "true" : "false"; } else { std::string address; int port; anna::functions::getAddressAndPortFromSocketLiteral(param1, address, port); - if(opType == "hide") commEngine->findServer(address, port)->hide(); + if(opType == "hide") getOperatedEngine()->findServer(address, port)->hide(); - if(opType == "show") commEngine->findServer(address, port)->show(); + if(opType == "show") getOperatedEngine()->findServer(address, port)->show(); - if(opType == "hidden") opt_response_content = commEngine->findServer(address, port)->hidden() ? "true" : "false"; + if(opType == "hidden") opt_response_content = getOperatedEngine()->findServer(address, port)->hidden() ? "true" : "false"; - if(opType == "shown") opt_response_content = commEngine->findServer(address, port)->shown() ? "true" : "false"; + if(opType == "shown") opt_response_content = getOperatedEngine()->findServer(address, port)->shown() ? "true" : "false"; } } else { - if(opType == "hide") entity->hide(); + if(opType == "hide") getOperatedEntity()->hide(); - if(opType == "show") entity->show(); + if(opType == "show") getOperatedEntity()->show(); - if(opType == "hidden") opt_response_content = entity->hidden() ? "true" : "false"; + if(opType == "hidden") opt_response_content = getOperatedEntity()->hidden() ? "true" : "false"; - if(opType == "shown") opt_response_content = entity->shown() ? "true" : "false"; + if(opType == "shown") opt_response_content = getOperatedEntity()->shown() ? "true" : "false"; } - } else if((opType == "sendxml") || (opType == "sendxml2e") || (opType == "sendhex") || (opType == "sendhex2e")) { - if(!entity) throw anna::RuntimeException("No entity configured to send the message", ANNA_FILE_LOCATION); - anna::diameter::comm::Message *msg = getWorkingNode()->createCommMessage(); + } else if((opType == "sendxml2e") || (opType == "sendhex2e")) { + anna::diameter::comm::Message *msg; - if((opType == "sendxml") || (opType == "sendxml2e")) { + if(opType == "sendxml2e") { codecMsg.loadXML(param1); + updateOperatedRealmNodeWithMessage(codecMsg); + msg = getOperatedRealm()->createCommMessage(); msg->clearBody(); try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher) - msg->setBody(codecMsg.code()); } else { // Get DataBlock from file with hex content: if(!getDataBlockFromHexFile(param1, db_aux)) throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION); - + msg = getOperatedRealm()->createCommMessage(); msg->setBody(db_aux); + try { if(getOperatedRealm()->logEnabled()) codecMsg.decode(db_aux); } catch(anna::RuntimeException &ex) { ex.trace(); } } - bool success = entity->send(msg, cl.exists("balance")); - getWorkingNode()->releaseCommMessage(msg); + bool success = getOperatedEntity()->send(msg, cl.exists("balance")); + getOperatedRealm()->releaseCommMessage(msg); // Detailed log: - if(getWorkingNode()->logEnabled()) { - anna::diameter::comm::Server *usedServer = entity->getLastUsedResource(); + if(getOperatedRealm()->logEnabled()) { + anna::diameter::comm::Server *usedServer = getOperatedEntity()->getLastUsedResource(); anna::diameter::comm::ClientSession *usedClientSession = usedServer ? usedServer->getLastUsedResource() : NULL; std::string detail = usedClientSession ? usedClientSession->asString() : ""; // shouldn't happen - getWorkingNode()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail); + getOperatedRealm()->writeLogFile(codecMsg, (success ? "sent2e" : "send2eError"), detail); } } else if((opType == "burst")) { - if(!entity) throw anna::RuntimeException("No entity configured to use burst feature", ANNA_FILE_LOCATION); + + if (!uniqueRealm()) + throw anna::RuntimeException("Burst category operations are only allowed in single realm node configuration. This is only to simplify user experience.", ANNA_FILE_LOCATION); // burst|clear clears all loaded burst messages. // burst|load| loads the next diameter message into launcher burst. @@ -1546,17 +1653,16 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(param1 == "clear") { opt_response_content = "removed "; - opt_response_content += anna::functions::asString(getWorkingNode()->clearBurst()); + opt_response_content += anna::functions::asString(getOperatedRealm()->clearBurst()); opt_response_content += " elements"; } else if(param1 == "load") { if(param2 == "") throw anna::RuntimeException("Missing xml path file for burst load operation", ANNA_FILE_LOCATION); codecMsg.loadXML(param2); - if(codecMsg.isAnswer()) throw anna::RuntimeException("Cannot load diameter answers for burst feature", ANNA_FILE_LOCATION); try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue loading (see validation mode configured in launcher) - int position = getWorkingNode()->loadBurstMessage(codecMsg.code()); + int position = getOperatedRealm()->loadBurstMessage(codecMsg.code()); opt_response_content = "loaded '"; opt_response_content += param2; opt_response_content += "' file into burst list position "; @@ -1565,7 +1671,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") throw anna::RuntimeException("Missing initial load for burst start operation", ANNA_FILE_LOCATION); int initialLoad = atoi(param2.c_str()); - int processed = getWorkingNode()->startBurst(initialLoad); + int processed = getOperatedRealm()->startBurst(initialLoad); if(processed > 0) { opt_response_content = "initial load completed for "; @@ -1574,7 +1680,7 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons } else if(param1 == "push") { if(param2 == "") throw anna::RuntimeException("Missing load amount for burst push operation", ANNA_FILE_LOCATION); - int pushed = getWorkingNode()->pushBurst(atoi(param2.c_str())); + int pushed = getOperatedRealm()->pushBurst(atoi(param2.c_str())); if(pushed > 0) { opt_response_content = "pushed "; @@ -1584,14 +1690,14 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") throw anna::RuntimeException("Missing amount for burst pop operation", ANNA_FILE_LOCATION); int releaseLoad = atoi(param2.c_str()); - int popped = getWorkingNode()->popBurst(releaseLoad); + int popped = getOperatedRealm()->popBurst(releaseLoad); if(popped > 0) { opt_response_content = "burst popped for "; opt_response_content += anna::functions::entriesAsString(popped, "message"); } } else if(param1 == "stop") { - int left = getWorkingNode()->stopBurst(); + int left = getOperatedRealm()->stopBurst(); if(left != -1) { opt_response_content += anna::functions::entriesAsString(left, "message"); @@ -1601,12 +1707,12 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(param2 == "") param2 = "yes"; bool repeat = (param2 == "yes"); - getWorkingNode()->repeatBurst(repeat); + getOperatedRealm()->repeatBurst(repeat); opt_response_content += (repeat ? "repeat enabled" : "repeat disabled"); } else if(param1 == "send") { if(param2 == "") throw anna::RuntimeException("Missing amount for burst send operation", ANNA_FILE_LOCATION); - int sent = getWorkingNode()->sendBurst(atoi(param2.c_str())); + int sent = getOperatedRealm()->sendBurst(atoi(param2.c_str())); if(sent > 0) { opt_response_content = "sent "; @@ -1615,11 +1721,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons } else if(param1 == "goto") { if(param2 == "") throw anna::RuntimeException("Missing order position for burst goto operation", ANNA_FILE_LOCATION); - opt_response_content = getWorkingNode()->gotoBurst(atoi(param2.c_str())); + opt_response_content = getOperatedRealm()->gotoBurst(atoi(param2.c_str())); } else if(param1 == "look") { int order = ((param2 != "") ? atoi(param2.c_str()) : -1); opt_response_content = "\n\n"; - opt_response_content += getWorkingNode()->lookBurst(order); + opt_response_content += getOperatedRealm()->lookBurst(order); } else { throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). See help", ANNA_FILE_LOCATION); } @@ -1778,13 +1884,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(id < 0) throw anna::RuntimeException("Invalid test case identifier: must be a non-negative number", ANNA_FILE_LOCATION); - // PARAM: 1 2 3 4 5 6 7 8 9 10 + // PARAM: 1 2 3 4 5 6 7 8 9 10 11 // test|| // timeout| // sendxml2e| [|] // sendxml2c| [|] // delay| [msecs] - // wait|[code]|[bitR]|[ResultCode]|[sessionId]|[hopByHop]|[msisdn]|[imsi]|[serviceContextId] + // wait|[code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId] // wait-answer| // wait-regexp| if(param2 == "") throw anna::RuntimeException("Missing command for test id operation", ANNA_FILE_LOCATION); @@ -1809,16 +1915,13 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons else { if (param4 == "") LOGWARNING(anna::Logger::warning("Step number has not been provided. Take into account that this answer message will be sent 'as is' and sequence information could be wrong at the remote peer", ANNA_FILE_LOCATION)); } + updateOperatedRealmNodeWithMessage(codecMsg); int stepNumber = ((param4 != "") ? atoi(param4.c_str()):-1); - std::string originRealm = codecMsg.getAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->getValue(); - RealmNode *realm = getRealmNode(originRealm); - if (!realm) - throw anna::RuntimeException("Cannot identify the realm node for the manager message. Check the Origin-Realm avp value (use the realm node name)", ANNA_FILE_LOCATION); if (param2 == "sendxml2e") - testManager.getTestCase(id)->addSendxml2e(codecMsg.code(), realm, stepNumber); // creates / reuses + testManager.getTestCase(id)->addSendxml2e(codecMsg.code(), getOperatedRealm(), stepNumber); // creates / reuses else - testManager.getTestCase(id)->addSendxml2c(codecMsg.code(), realm, stepNumber); // creates / reuses + testManager.getTestCase(id)->addSendxml2c(codecMsg.code(), getOperatedRealm(), stepNumber); // creates / reuses } else if (param2 == "delay") { if (numParams > 3) @@ -1828,11 +1931,11 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons testManager.getTestCase(id)->addDelay(delay); // creates / reuses } else if ((param2 == "waitfe")||(param2 == "waitfc")) { - if (numParams > 10) + if (numParams > 11) throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION); - if (param3 != "" || param4 != "" || param5 != "" || param6 != "" || param7 != "" || param8 != "" || param9 != "" || param10 != "") { + if (param3 != "" || param4 != "" || param5 != "" || param6 != "" || param7 != "" || param8 != "" || param9 != "" || param10 != "" || param11 != "") { bool fromEntity = (param2.substr(4,2) == "fe"); - testManager.getTestCase(id)->addWait(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10); + testManager.getTestCase(id)->addWait(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10, param11); } else { throw anna::RuntimeException(anna::functions::asString("Missing condition for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION); @@ -1861,11 +1964,12 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons } } else if((opType == "sendxml2c") || (opType == "sendhex2c")) { - if(!localServer) throw anna::RuntimeException("No local server configured to send the message", ANNA_FILE_LOCATION); - anna::diameter::comm::Message *msg = getWorkingNode()->createCommMessage(); + anna::diameter::comm::Message *msg; if(opType == "sendxml2c") { codecMsg.loadXML(param1); + updateOperatedRealmNodeWithMessage(codecMsg); + msg = getOperatedRealm()->createCommMessage(); msg->clearBody(); try { codecMsg.valid(); } catch(anna::RuntimeException &ex) { ex.trace(); } // at least we need to see validation errors although it will continue sending (see validation mode configured in launcher) @@ -1874,18 +1978,18 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons // Get DataBlock from file with hex content: if(!getDataBlockFromHexFile(param1, db_aux)) throw anna::RuntimeException("Error reading hex file provided", ANNA_FILE_LOCATION); - + msg = getOperatedRealm()->createCommMessage(); msg->setBody(db_aux); } - bool success = localServer->send(msg); - getWorkingNode()->releaseCommMessage(msg); + bool success = getOperatedServer()->send(msg); + getOperatedRealm()->releaseCommMessage(msg); // Detailed log: - if(getWorkingNode()->logEnabled()) { - anna::diameter::comm::ServerSession *usedServerSession = localServer->getLastUsedResource(); + if(getOperatedRealm()->logEnabled()) { + anna::diameter::comm::ServerSession *usedServerSession = getOperatedServer()->getLastUsedResource(); std::string detail = usedServerSession ? usedServerSession->asString() : ""; // shouldn't happen - getWorkingNode()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail); + getOperatedRealm()->writeLogFile(codecMsg, (success ? "sent2c" : "send2cError"), detail); } } else if(opType == "loadxml") { codecMsg.loadXML(param1); @@ -1893,69 +1997,58 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons return; } else if(opType == "diameterServerSessions") { int diameterServerSessions = atoi(param1.c_str()); + getOperatedServer()->setMaxConnections(diameterServerSessions); - if(localServer) - localServer->setMaxConnections(diameterServerSessions); - else - LOGWARNING(anna::Logger::warning("To update the number of sessions, you must configure the process diameter local server: you could also launch it with no sessions (disabled)", ANNA_FILE_LOCATION)); - - } else if((opType == "answerxml") || (opType == "answerxml2c")) { - if(!localServer) - throw anna::RuntimeException("Operation not applicable (no own diameter server has been configured)", ANNA_FILE_LOCATION); - + } else if(opType == "answerxml2c") { if(param1 == "") { // programmed answers FIFO's to stdout - response_content = localServer->getReactingAnswers()->asString("ANSWERS TO CLIENT"); + response_content = getOperatedServer()->getReactingAnswers()->asString("ANSWERS TO CLIENT"); return; } else if (param1 == "rotate") { - localServer->getReactingAnswers()->rotate(true); + getOperatedServer()->getReactingAnswers()->rotate(true); } else if (param1 == "exhaust") { - localServer->getReactingAnswers()->rotate(false); + getOperatedServer()->getReactingAnswers()->rotate(false); } else if (param1 == "clear") { - localServer->getReactingAnswers()->clear(); + getOperatedServer()->getReactingAnswers()->clear(); } else if (param1 == "dump") { - localServer->getReactingAnswers()->dump(); + getOperatedServer()->getReactingAnswers()->dump(); } else { - anna::diameter::codec::Message *message = getCodecEngine()->createMessage(param1); - LOGDEBUG - ( - anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION); - ); + codecMsg.loadXML(param1); + updateOperatedRealmNodeWithMessage(codecMsg); + anna::diameter::codec::Message *message = getOperatedRealm()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils + LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION)); if(message->isRequest()) throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); 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)); - localServer->getReactingAnswers()->addMessage(code, message); + getOperatedServer()->getReactingAnswers()->addMessage(code, message); } } else if(opType == "answerxml2e") { - if(!entity) - throw anna::RuntimeException("Operation not applicable (no diameter entity has been configured)", ANNA_FILE_LOCATION); if(param1 == "") { // programmed answers FIFO's to stdout - response_content = entity->getReactingAnswers()->asString("ANSWERS TO ENTITY"); + response_content = getOperatedEntity()->getReactingAnswers()->asString("ANSWERS TO ENTITY"); return; } else if (param1 == "rotate") { - entity->getReactingAnswers()->rotate(true); + getOperatedEntity()->getReactingAnswers()->rotate(true); } else if (param1 == "exhaust") { - entity->getReactingAnswers()->rotate(false); + getOperatedEntity()->getReactingAnswers()->rotate(false); } else if (param1 == "clear") { - entity->getReactingAnswers()->clear(); + getOperatedEntity()->getReactingAnswers()->clear(); } else if (param1 == "dump") { - entity->getReactingAnswers()->dump(); + getOperatedEntity()->getReactingAnswers()->dump(); } else { - anna::diameter::codec::Message *message = getCodecEngine()->createMessage(param1); - LOGDEBUG - ( - anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION); - ); + codecMsg.loadXML(param1); + updateOperatedRealmNodeWithMessage(codecMsg); + anna::diameter::codec::Message *message = getOperatedRealm()->getCodecEngine()->createMessage(param1); // loads xml again, lesser of two evils + LOGDEBUG(anna::Logger::debug(message->asXMLString(), ANNA_FILE_LOCATION)); if(message->isRequest()) throw anna::RuntimeException("Cannot program diameter requests. Answer type must be provided", ANNA_FILE_LOCATION); 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)); - entity->getReactingAnswers()->addMessage(code, message); + getOperatedEntity()->getReactingAnswers()->addMessage(code, message); } } else { throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION); @@ -1977,7 +2070,6 @@ throw() { result->createAttribute("StartTime", a_start_time.asString()); result->createAttribute("SecondsLifeTime", anna::time::functions::lapsedMilliseconds() / 1000); // Diameter: - getCodecEngine()->asXML(result); for (realm_nodes_it it = a_nodes.begin(); it != a_nodes.end(); it++) { it->second->asXML(result); } diff --git a/example/diameter/launcher/Launcher.hpp b/example/diameter/launcher/Launcher.hpp index 9ac09af..3ce4a20 100644 --- a/example/diameter/launcher/Launcher.hpp +++ b/example/diameter/launcher/Launcher.hpp @@ -18,6 +18,7 @@ #include #include #include +#include // Process #include @@ -42,6 +43,10 @@ namespace anna { } class TestManager; +class RealmNode; +class MyDiameterEntity; +class MyLocalServer; +class MyDiameterEngine; // RealmNode resources class RealmNode; @@ -57,8 +62,6 @@ class Launcher : public anna::comm::Application { // Core engines: MyCommunicator *a_communicator; - anna::diameter::codec::Engine *a_codecEngine; - anna::diameter::stack::Dictionary *a_baseProtocolDictionary; anna::timex::Engine* a_timeEngine; MyCounterRecorder *a_counterRecorder; anna::Millisecond a_admlMinResolution; @@ -67,6 +70,7 @@ class Launcher : public anna::comm::Application { // Nodes deployment: realm_nodes_t a_nodes; RealmNode *a_workingNode; + RealmNode *a_operatedRealm; // auxiliary for eventOperation // comm resources: anna::comm::ServerSocket* a_httpServerSocket; // HTTP @@ -80,17 +84,23 @@ class Launcher : public anna::comm::Application { public: Launcher(); + //~Launcher(); TODO void loadServices(const std::string & xmlPathFile, bool eventOperation = false) throw(anna::RuntimeException); void startServices() throw(anna::RuntimeException); - anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; } - //anna::diameter::stack::Dictionary *getBaseProtocolDictionary() const throw() { return a_baseProtocolDictionary; } - RealmNode *getWorkingNode() const throw(anna::RuntimeException); // management operations working node - bool setWorkingNode(const std::string &name) throw(); // we could update ignoreFlagsOnValidation/integrationAndDebugging over the global codec engine - // but finally, that configuration issues will be global to the process. - - RealmNode *getRealmNode(const std::string &realmName) const throw(); + bool setWorkingNode(const std::string &name) throw(); + RealmNode *getRealmNode(const std::string &realmName) const throw(anna::RuntimeException); + RealmNode *getRealmNode(const anna::diameter::codec::Message &message) const throw(anna::RuntimeException); + bool uniqueRealm() const throw() { return (a_nodes.size() == 1); } + + // Operated realm for communication resources smart assignment //////////////////////////////////////////////////////////// + void updateOperatedRealmNodeWithMessage(const anna::diameter::codec::Message &message) throw(anna::RuntimeException); + RealmNode *getOperatedRealm() const throw(anna::RuntimeException); + MyDiameterEntity *getOperatedEntity() const throw(anna::RuntimeException); + MyLocalServer *getOperatedServer() const throw(anna::RuntimeException); + MyDiameterEngine *getOperatedEngine() const throw(anna::RuntimeException); + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MyCommunicator *getCommunicator() throw() { return a_communicator; } diff --git a/example/diameter/launcher/MyDiameterEntity.cpp b/example/diameter/launcher/MyDiameterEntity.cpp index 50a9663..6c1244b 100644 --- a/example/diameter/launcher/MyDiameterEntity.cpp +++ b/example/diameter/launcher/MyDiameterEntity.cpp @@ -101,9 +101,6 @@ throw(anna::RuntimeException) { Launcher& my_app = static_cast (anna::app::functions::getApp()); RealmNode * my_node = my_app.getRealmNode(getEngine()->getRealm()); - // Testing: - TestManager::instantiate().receiveMessage(message, clientSession); - // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); LOGDEBUG @@ -177,6 +174,9 @@ throw(anna::RuntimeException) { ex.trace(); } } + + // Testing: + TestManager::instantiate().receiveMessage(message, my_node, clientSession); } void MyDiameterEntity::eventResponse(const anna::diameter::comm::Response &response) @@ -195,9 +195,6 @@ throw(anna::RuntimeException) { bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable); bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success); - // Testing: - TestManager::instantiate().receiveMessage(*message, clientSession); - // CommandId: anna::diameter::CommandId request_cid = request->getCommandId(); LOGDEBUG @@ -272,6 +269,9 @@ throw(anna::RuntimeException) { // Triggering burst: if(isOK || contextExpired) my_node->sendBurstMessage(); + + // Testing: + TestManager::instantiate().receiveMessage(*message, my_node, clientSession); } void MyDiameterEntity::eventUnknownResponse(anna::diameter::comm::ClientSession *clientSession, const anna::DataBlock &message) diff --git a/example/diameter/launcher/MyDiameterEntity.hpp b/example/diameter/launcher/MyDiameterEntity.hpp index 9476883..73494b5 100644 --- a/example/diameter/launcher/MyDiameterEntity.hpp +++ b/example/diameter/launcher/MyDiameterEntity.hpp @@ -25,7 +25,6 @@ namespace anna { class MyDiameterEntity : public anna::diameter::comm::Entity { - anna::diameter::codec::Engine * a_codecEngine; // for automatic answers (failed-avp), write logs, etc. bool a_balance; // Balance over entity servers instead of doing standard behaviour (first primary, secondary if fails, etc.). Default: false. std::string a_sessionBasedModelsType; @@ -41,13 +40,11 @@ class MyDiameterEntity : public anna::diameter::comm::Entity { public: MyDiameterEntity() { - a_codecEngine = NULL; a_balance = false; a_sessionBasedModelsType = "SessionIdLowPart"; } ProgrammedAnswers a_reactingAnswers; - void setCodecEngine(anna::diameter::codec::Engine *codecEngine) throw() { a_codecEngine = codecEngine; a_reactingAnswers.setCodecEngine(codecEngine); } ProgrammedAnswers *getReactingAnswers() throw() { return (ProgrammedAnswers *)&a_reactingAnswers; } // Additional configuration parameters: diff --git a/example/diameter/launcher/MyLocalServer.cpp b/example/diameter/launcher/MyLocalServer.cpp index 8127d84..110efdc 100644 --- a/example/diameter/launcher/MyLocalServer.cpp +++ b/example/diameter/launcher/MyLocalServer.cpp @@ -30,9 +30,7 @@ throw(anna::RuntimeException) { // Performance stats: Launcher& my_app = static_cast (anna::app::functions::getApp()); RealmNode * my_node = my_app.getRealmNode(getEngine()->getRealm()); - - // Testing: - TestManager::instantiate().receiveMessage(message, serverSession); + anna::diameter::codec::Engine *codecEngine = my_node->getCodecEngine(); // CommandId: anna::diameter::CommandId cid = anna::diameter::codec::functions::getCommandId(message); @@ -71,14 +69,18 @@ throw(anna::RuntimeException) { my_node->writeLogFile(message, (success ? "fwd2e" : "fwd2eError"), detail); // forwarded } + + // Testing: + TestManager::instantiate().receiveMessage(message, my_node, serverSession); + return; } // Error analisys: bool analysisOK = true; // by default anna::diameter::codec::Message *answer_message = NULL; - anna::diameter::codec::Message codecMsg(a_codecEngine); - anna::diameter::codec::Message codecAnsMsg(a_codecEngine); + anna::diameter::codec::Message codecMsg; + anna::diameter::codec::Message codecAnsMsg; CommandLine& cl(anna::CommandLine::instantiate()); if(!cl.exists("ignoreErrors")) { // Error analysis @@ -98,13 +100,19 @@ throw(anna::RuntimeException) { answer_message = programmed_answer; // Prepare answer: my_app.getCommunicator()->prepareAnswer(answer_message, message); - } else return; // nothing done + } else { + + // Testing: + TestManager::instantiate().receiveMessage(message, my_node, serverSession); + + return; // nothing done + } } - anna::diameter::codec::Engine::ValidationMode::_v backupVM = a_codecEngine->getValidationMode(); + anna::diameter::codec::Engine::ValidationMode::_v backupVM = codecEngine->getValidationMode(); if(!analysisOK) - a_codecEngine->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Never); + codecEngine->setValidationMode(anna::diameter::codec::Engine::ValidationMode::Never); anna::diameter::comm::Message *msg; try { @@ -122,10 +130,13 @@ throw(anna::RuntimeException) { my_node->releaseCommMessage(msg); // Restore validation mode - a_codecEngine->setValidationMode(backupVM); + codecEngine->setValidationMode(backupVM); // Pop front the reacting answer: if(analysisOK && programmed) a_reactingAnswers.nextMessage(code); + + // Testing: + TestManager::instantiate().receiveMessage(message, my_node, serverSession); } void MyLocalServer::eventResponse(const anna::diameter::comm::Response &response) @@ -144,9 +155,6 @@ throw(anna::RuntimeException) { bool isUnavailable = (result == anna::diameter::comm::Response::ResultCode::DiameterUnavailable); bool isOK = (result == anna::diameter::comm::Response::ResultCode::Success); - // Testing: - TestManager::instantiate().receiveMessage(*message, serverSession); - // CommandId: anna::diameter::CommandId request_cid = request->getCommandId(); LOGDEBUG @@ -219,6 +227,9 @@ throw(anna::RuntimeException) { my_node->releaseCommMessage(request); } } + + // Testing: + TestManager::instantiate().receiveMessage(*message, my_node, serverSession); } void MyLocalServer::eventUnknownResponse(anna::diameter::comm::ServerSession *serverSession, const anna::DataBlock &message) diff --git a/example/diameter/launcher/MyLocalServer.hpp b/example/diameter/launcher/MyLocalServer.hpp index da4ed97..831e15b 100644 --- a/example/diameter/launcher/MyLocalServer.hpp +++ b/example/diameter/launcher/MyLocalServer.hpp @@ -25,8 +25,6 @@ namespace anna { class MyLocalServer : public anna::diameter::comm::LocalServer { - anna::diameter::codec::Engine * a_codecEngine; // for automatic answers (failed-avp), write logs, etc. - void eventResponse(const anna::diameter::comm::Response&) throw(anna::RuntimeException); void eventRequest(anna::diameter::comm::ServerSession *, const anna::DataBlock&) throw(anna::RuntimeException); void eventUnknownResponse(anna::diameter::comm::ServerSession *, const anna::DataBlock&) throw(anna::RuntimeException); @@ -35,7 +33,6 @@ class MyLocalServer : public anna::diameter::comm::LocalServer { public: ProgrammedAnswers a_reactingAnswers; - void setCodecEngine(anna::diameter::codec::Engine *codecEngine) throw() { a_codecEngine = codecEngine; a_reactingAnswers.setCodecEngine(codecEngine); } ProgrammedAnswers *getReactingAnswers() throw() { return (ProgrammedAnswers *)&a_reactingAnswers; } }; diff --git a/example/diameter/launcher/ProgrammedAnswers.cpp b/example/diameter/launcher/ProgrammedAnswers.cpp index 9356dac..3f64a35 100644 --- a/example/diameter/launcher/ProgrammedAnswers.cpp +++ b/example/diameter/launcher/ProgrammedAnswers.cpp @@ -5,110 +5,126 @@ // See project site at http://redmine.teslayout.com/projects/anna-suite // // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // - // Standard #include #include // Project +#include #include +#include // Process #include -void ProgrammedAnswers::clear () throw() { - for (reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) { - a_codecEngine->releaseMessage(*(it->second->begin())); - delete(it->second); +void ProgrammedAnswers::clear() throw () { + try { + anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate(); + for (reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) { + anna::diameter::codec::Message *message = *(it->second->begin()); + em.getCodecEngine(message->getApplicationId())->releaseMessage(message); + delete (it->second); + } + a_deques.clear(); + } + catch (anna::RuntimeException &ex) { + ex.trace(); } - a_deques.clear(); } -void ProgrammedAnswers::dump () throw() { +void ProgrammedAnswers::dump() throw () { std::string outfilename, xmlString; - for(reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) { - int sequence = 1; - for(codec_messages_deque_const_iterator itm = it->second->begin(); itm != it->second->end(); itm++) { - // programmed_answer.. - outfilename = "programmed_answer."; - outfilename += anna::functions::asString(it->first); - outfilename += "."; - outfilename += anna::functions::asString(sequence++); - outfilename += ".xml"; - std::ofstream outfile(outfilename.c_str(), std::ifstream::out); - xmlString = (*itm)->asXMLString(); - outfile.write(xmlString.c_str(), xmlString.size()); - outfile.close(); - } + for (reacting_answers_const_iterator it = a_deques.begin(); + it != a_deques.end(); it++) { + int sequence = 1; + for (codec_messages_deque_const_iterator itm = it->second->begin(); + itm != it->second->end(); itm++) { + // programmed_answer.. + outfilename = "programmed_answer."; + outfilename += anna::functions::asString(it->first); + outfilename += "."; + outfilename += anna::functions::asString(sequence++); + outfilename += ".xml"; + std::ofstream outfile(outfilename.c_str(), std::ifstream::out); + xmlString = (*itm)->asXMLString(); + outfile.write(xmlString.c_str(), xmlString.size()); + outfile.close(); + } } } -void ProgrammedAnswers::addMessage(int code, anna::diameter::codec::Message *message) throw() { - if (!message) return; // just in case - message->setEngine(a_codecEngine); // just in case +void ProgrammedAnswers::addMessage(int code, anna::diameter::codec::Message *message) throw () { + if (!message) + return; // just in case reacting_answers_const_iterator it = a_deques.find(code); if (it != a_deques.end()) { - it->second->push_back(message); - } - else { - codec_messages_deque *deque = new codec_messages_deque; - a_deques[code] = deque; - deque->push_back(message); + it->second->push_back(message); + } else { + codec_messages_deque *deque = new codec_messages_deque; + a_deques[code] = deque; + deque->push_back(message); } } -anna::diameter::codec::Message* ProgrammedAnswers::getMessage(int code) const throw() { //get the front message (begin()), returns NULL if deque is empty +anna::diameter::codec::Message* ProgrammedAnswers::getMessage(int code) const throw () { //get the front message (begin()), returns NULL if deque is empty anna::diameter::codec::Message *result = NULL; reacting_answers_const_iterator it = a_deques.find(code); if (it != a_deques.end()) { - if (!it->second->empty()) result = *(it->second->begin()); + if (!it->second->empty()) + result = *(it->second->begin()); } return result; } -void ProgrammedAnswers::nextMessage(int code) throw() { //pops the deque and release the message (when deque is not empty: deque::empty) - reacting_answers_const_iterator it = a_deques.find(code); - if (it != a_deques.end()) { - if (!it->second->empty()) { - if (a_rotate) { - addMessage(code, *(it->second->begin())); - } - else { - a_codecEngine->releaseMessage(*(it->second->begin())); - } - it->second->pop_front(); - } +void ProgrammedAnswers::nextMessage(int code) throw () { //pops the deque and release the message (when deque is not empty: deque::empty) + try { + reacting_answers_const_iterator it = a_deques.find(code); + if (it != a_deques.end()) { + if (!it->second->empty()) { + if (a_rotate) { + addMessage(code, *(it->second->begin())); + } else { + anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate(); + anna::diameter::codec::Message *message = *(it->second->begin()); + em.getCodecEngine(message->getApplicationId())->releaseMessage(message); + } + it->second->pop_front(); + } + } + } + catch (anna::RuntimeException &ex) { + ex.trace(); } } -std::string ProgrammedAnswers::asString(const char *queueName) const throw() { +std::string ProgrammedAnswers::asString(const char *queueName) const throw () { std::string result = ""; std::string aux = "FIFO QUEUE '"; aux += queueName; aux += "', Rotation "; - aux += a_rotate ? "enabled":"disabled"; + aux += a_rotate ? "enabled" : "disabled"; result += anna::functions::highlightJustify(aux); - result += "Codec engine: "; - result += a_codecEngine->getClassName(); - if(a_deques.size() != 0) { - for(reacting_answers_const_iterator it = a_deques.begin(); it != a_deques.end(); it++) { - if (it->second->size() != 0) { - aux = "Answer code "; - aux += anna::functions::asString(it->first); - result += anna::functions::highlightJustify(aux, anna::functions::TextHighlightMode::OverAndUnderline, - anna::functions::TextJustifyMode::Left, '-'); - for(codec_messages_deque_const_iterator itm = it->second->begin(); itm != it->second->end(); itm++) { - result += (*itm)->asXMLString(); - result += "\n"; - } - result += "\n"; - } - } - } - else { - result = "No ocurrences found\n\n"; + if (a_deques.size() != 0) { + for (reacting_answers_const_iterator it = a_deques.begin(); + it != a_deques.end(); it++) { + if (it->second->size() != 0) { + aux = "Answer code "; + aux += anna::functions::asString(it->first); + result += anna::functions::highlightJustify(aux, + anna::functions::TextHighlightMode::OverAndUnderline, + anna::functions::TextJustifyMode::Left, '-'); + for (codec_messages_deque_const_iterator itm = it->second->begin(); + itm != it->second->end(); itm++) { + result += (*itm)->asXMLString(); + result += "\n"; + } + result += "\n"; + } + } + } else { + result = "No ocurrences found\n\n"; } return result; } diff --git a/example/diameter/launcher/ProgrammedAnswers.hpp b/example/diameter/launcher/ProgrammedAnswers.hpp index a7cd897..00b9d4d 100644 --- a/example/diameter/launcher/ProgrammedAnswers.hpp +++ b/example/diameter/launcher/ProgrammedAnswers.hpp @@ -18,7 +18,6 @@ namespace anna { namespace diameter { namespace codec { class Message; - class Engine; } } } @@ -35,13 +34,11 @@ typedef std::map < int /* message code */, codec_messages_deque* >::const_iterat reacting_answers_container a_deques; bool a_rotate; - anna::diameter::codec::Engine *a_codecEngine; public: ProgrammedAnswers() { a_rotate = false; } ~ProgrammedAnswers() { clear(); } - void setCodecEngine(anna::diameter::codec::Engine *codecEngine) throw() { a_codecEngine = codecEngine; } bool rotate() const throw() { return a_rotate; } void rotate(bool r) throw() { a_rotate = r; } diff --git a/example/diameter/launcher/RealmNode.cpp b/example/diameter/launcher/RealmNode.cpp index d3a2b89..d227650 100644 --- a/example/diameter/launcher/RealmNode.cpp +++ b/example/diameter/launcher/RealmNode.cpp @@ -11,6 +11,8 @@ // Project #include +#include +#include #include #include #include @@ -19,6 +21,7 @@ #include #include + namespace anna { namespace diameter { namespace stack { @@ -27,12 +30,13 @@ namespace anna { } } -RealmNode::RealmNode(const std::string &originRealm, anna::diameter::codec::Engine *codecEngine, const anna::diameter::stack::Dictionary *baseProtocolDictionary) : - a_originRealm(originRealm), a_codecEngine(codecEngine) { +RealmNode::RealmNode(const std::string &originRealm, unsigned int applicationId, const anna::diameter::stack::Dictionary *baseProtocolDictionary) : + a_originRealm(originRealm), a_applicationId(applicationId) { std::string commEngineName = a_originRealm + "_DiameterCommEngine"; a_commEngine = new MyDiameterEngine(commEngineName.c_str(), baseProtocolDictionary); a_commEngine->setAutoBind(false); // allow to create client-sessions without binding them, in order to set timeouts. + a_codecEngine = anna::diameter::codec::EngineManager::instantiate().getCodecEngine(applicationId); a_logFile = ""; a_burstLogFile = ""; @@ -68,9 +72,6 @@ void RealmNode::createEntity(const std::string &entityRepresentation, const anna a_entity = (MyDiameterEntity*)(a_commEngine->createEntity(servers, entityDescription)); a_entity->setClassCodeTimeout(anna::diameter::comm::ClassCode::Bind, bindTimeout); a_entity->setClassCodeTimeout(anna::diameter::comm::ClassCode::ApplicationMessage, applicationTimeout); - - // Codec engine for reacting answers (failed-avp): - a_entity->setCodecEngine(getCodecEngine()); } void RealmNode::startDiameterServer(const std::string &serverRepresentation, int sessions, const anna::Millisecond &inactivityTimeout) throw(anna::RuntimeException) { @@ -86,9 +87,6 @@ void RealmNode::startDiameterServer(const std::string &serverRepresentation, int a_diameterServer->setDescription(serverDescription); a_diameterServer->setAllowedInactivityTime(inactivityTimeout); - - // Codec engine for reacting answers (failed-avp): - a_diameterServer->setCodecEngine(getCodecEngine()); } anna::diameter::comm::Message *RealmNode::createCommMessage() throw(anna::RuntimeException) { @@ -105,16 +103,13 @@ void RealmNode::releaseCommMessage(anna::diameter::comm::Message *msg) throw() { void RealmNode::writeLogFile(const anna::DataBlock & db, const std::string &logExtension, const std::string &detail) const throw() { -// if (!logEnabled()) return; - anna::diameter::codec::Message codecMsg(getCodecEngine()); + anna::diameter::codec::Message codecMsg; try { codecMsg.decode(db); } catch(anna::RuntimeException &ex) { ex.trace(); } writeLogFile(codecMsg, logExtension, detail); - } -// Si ya lo tengo decodificado: -void RealmNode::writeLogFile(const anna::diameter::codec::Message & decodedMessage, const std::string &logExtension, const std::string &detail) const throw() { -// if (!logEnabled()) return; +// Already decoded: +void RealmNode::writeLogFile(const anna::diameter::codec::Message &decodedMessage, const std::string &logExtension, const std::string &detail) const throw() { // Open target file: std::string targetFile = a_logFile; @@ -379,10 +374,8 @@ std::string RealmNode::lookBurst(int order) const throw() { std::map::const_iterator it = a_burstMessages.find(order - 1); if(it != a_burstMessages.end()) { - // Decode - anna::diameter::codec::Message codecMsg(getCodecEngine()); - try { codecMsg.decode((*it).second->getBody()); } catch(anna::RuntimeException &ex) { ex.trace(); } - result = codecMsg.asXMLString(); + anna::diameter::codec::Message codecMsg; + try { codecMsg.decode((*it).second->getBody()); result = codecMsg.asXMLString(); } catch(anna::RuntimeException &ex) { ex.trace(); } } return result; @@ -407,6 +400,7 @@ throw() { anna::xml::Node* result = parent->createChild("RealmNode"); result->createAttribute("OriginRealm", a_originRealm); + result->createAttribute("ApplicationId", a_applicationId); result->createAttribute("LogFile", a_logFile); result->createAttribute("SplitLog", a_splitLog ? "yes" : "no"); result->createAttribute("DetailedLog", a_detailedLog ? "yes" : "no"); diff --git a/example/diameter/launcher/RealmNode.hpp b/example/diameter/launcher/RealmNode.hpp index 774e858..7f239ca 100644 --- a/example/diameter/launcher/RealmNode.hpp +++ b/example/diameter/launcher/RealmNode.hpp @@ -53,6 +53,7 @@ class RealmNode { // main std::string a_originRealm; + unsigned int a_applicationId; // Timming anna::Millisecond a_allowedInactivityTime; @@ -76,12 +77,16 @@ class RealmNode { int a_burstPopCounter; public: - RealmNode(const std::string &originRealm, anna::diameter::codec::Engine *codecEngine, const anna::diameter::stack::Dictionary *baseProtocolDictionary); + RealmNode(const std::string &originRealm, unsigned int applicationId, const anna::diameter::stack::Dictionary *baseProtocolDictionary); ~RealmNode() {;} + const std::string &getName() const throw() { return a_originRealm; } + // Core resources: MyDiameterEngine* getMyDiameterEngine() const throw() { return a_commEngine; } + unsigned int getApplicationId() const throw() { return a_applicationId; } anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; } + void createEntity(const std::string &entityRepresentation, const anna::Millisecond &bindTimeout, const anna::Millisecond &applicationTimeout) throw(anna::RuntimeException); MyDiameterEntity *getEntity() const throw() { return a_entity; } void startDiameterServer(const std::string &serverRepresentation, int sessions, const anna::Millisecond &inactivityTimeout) throw(anna::RuntimeException); diff --git a/example/diameter/launcher/main.cpp b/example/diameter/launcher/main.cpp index 309a7ef..a0f4fb6 100644 --- a/example/diameter/launcher/main.cpp +++ b/example/diameter/launcher/main.cpp @@ -41,11 +41,8 @@ int main(int argc, const char** argv) { commandLine.add("httpServer", anna::CommandLine::Argument::Optional, "HTTP Management interface address (using i.e. curl tool) in '
:' format. For example: 10.20.30.40:8080"); commandLine.add("httpServerShared", anna::CommandLine::Argument::Optional, "Enables shared bind for HTTP Management interface address. It would be useful i.e. to allow a great amount of curl operations per second", false); - // Codec engine + // Automatic error answer commandLine.add("ignoreErrors", anna::CommandLine::Argument::Optional, "Local server skips requests errors analysis which would prepare automatic answers for them when a problem is found. If no answer is programmed and entity is configured, a failed request would be forwarded (delegates at the end point) even if this parameter is missing", false); - commandLine.add("ignoreFlags", anna::CommandLine::Argument::Optional, "Ignore flags on validation (at the moment only bits M & P from AVPs, because V bit is too important; no operation flags could be checked). Also force compact xml presentation ignoring flags during dictionary elements identification", false); - commandLine.add("integrationAndDebugging", anna::CommandLine::Argument::Optional, "Sets validation mode to 'Always' (default validates only after decoding), and validation depth to 'Complete' (default validates until 'FirstError')", false); - commandLine.add("fixMode", anna::CommandLine::Argument::Optional, "Sets message fix mode (unreconized values will assume default 'BeforeEncoding'). Allowed: 'BeforeEncoding', 'AfterDecoding', 'Always', 'Never'"); commandLine.initialize(argv, argc); commandLine.verify(); diff --git a/example/diameter/launcher/resources/scripts/operation_tps.sh b/example/diameter/launcher/resources/scripts/operation_tps.sh index 29f41eb..3c5d7ff 100755 --- a/example/diameter/launcher/resources/scripts/operation_tps.sh +++ b/example/diameter/launcher/resources/scripts/operation_tps.sh @@ -59,7 +59,7 @@ echo [[ "$1" = "" ]] && use [[ ! -f "$1" ]] && { echo "ERROR: file '$1' not found" ; echo; echo; exit ; } echo -operation="sendxml|$1" +operation="sendxml2e|$1" [[ "$2" = "2c" ]] && operation="sendxml2c|$1" curl -m 1 --data "$operation" $TRACE ${SERVER} diff --git a/example/diameter/launcher/resources/services_examples/balancer.xml b/example/diameter/launcher/resources/services_examples/balancer.xml index a7d3f30..d7bfbc6 100644 --- a/example/diameter/launcher/resources/services_examples/balancer.xml +++ b/example/diameter/launcher/resources/services_examples/balancer.xml @@ -3,7 +3,7 @@ - - + + diff --git a/example/diameter/launcher/resources/services_examples/client.xml b/example/diameter/launcher/resources/services_examples/client.xml index 4c5e019..dfbb943 100644 --- a/example/diameter/launcher/resources/services_examples/client.xml +++ b/example/diameter/launcher/resources/services_examples/client.xml @@ -3,6 +3,6 @@ - + diff --git a/example/diameter/launcher/resources/services_examples/dummy.xml b/example/diameter/launcher/resources/services_examples/dummy.xml index c09c529..f1602be 100644 --- a/example/diameter/launcher/resources/services_examples/dummy.xml +++ b/example/diameter/launcher/resources/services_examples/dummy.xml @@ -3,6 +3,6 @@ - + diff --git a/example/diameter/launcher/resources/services_examples/multi-client.xml b/example/diameter/launcher/resources/services_examples/multi-client.xml index a47db65..aa884eb 100644 --- a/example/diameter/launcher/resources/services_examples/multi-client.xml +++ b/example/diameter/launcher/resources/services_examples/multi-client.xml @@ -6,9 +6,9 @@ - - - - + + + + diff --git a/example/diameter/launcher/resources/services_examples/server.xml b/example/diameter/launcher/resources/services_examples/server.xml index e615c4a..c257afc 100644 --- a/example/diameter/launcher/resources/services_examples/server.xml +++ b/example/diameter/launcher/resources/services_examples/server.xml @@ -3,6 +3,6 @@ - + diff --git a/example/diameter/launcher/resources/services_examples/services.dtd b/example/diameter/launcher/resources/services_examples/services.dtd index 6dd31ed..1e40d28 100755 --- a/example/diameter/launcher/resources/services_examples/services.dtd +++ b/example/diameter/launcher/resources/services_examples/services.dtd @@ -4,22 +4,27 @@ - + - + - - - - - - @param xmlPathFile Complete path file to the xml document which represents the diameter message - @see fromXMLString - */ - void loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException); - + * Interpret a xml file in order to create a diameter message + * + * @see functions::messageXmlDocumentFromXmlFile + * @see fromXML + * + * @param xmlPathFile Complete path file to the xml document which represents the diameter message + */ + void loadXML(const std::string &xmlPathFile) throw(anna::RuntimeException); // getters diff --git a/include/anna/diameter/codec/functions.hpp b/include/anna/diameter/codec/functions.hpp index 44a8f15..9c4c5a8 100644 --- a/include/anna/diameter/codec/functions.hpp +++ b/include/anna/diameter/codec/functions.hpp @@ -10,10 +10,10 @@ #define anna_diameter_codec_functions_hpp -// Local +// Project #include - #include +#include // STL #include @@ -41,6 +41,81 @@ namespace diameter { namespace codec { +static const char *MessageDTD = "\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +"; + + + + // Used for alarms, tracing and Failed-AVP construction: typedef struct parent { @@ -82,75 +157,75 @@ struct functions { /** - * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context. - * - * @param start Must be a valid command start (point to the command version byte). - * @param version Diameter version. - * @param length Message length. - * @param flags Command flags. - * @param id Command identification (code, request). - * @param appId Application-ID. - * @param hbh Hop-by-Hop Identifier. - * @param ete End-to-End Identifier. - */ + * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context. + * + * @param start Must be a valid command start (point to the command version byte). + * @param version Diameter version. + * @param length Message length. + * @param flags Command flags. + * @param id Command identification (code, request). + * @param appId Application-ID. + * @param hbh Hop-by-Hop Identifier. + * @param ete End-to-End Identifier. + */ static void decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException); /** - * Decodes an AVP. This helper cannot check boundaries. start pointer must be a valid avp context. - * - * @param start Must be a valid avp start (point to the 32-bits avp code word). - * @param id Avp identification (code, vendorId). - * @param flags Avp flags byte. - * @param length Avp length (includes code, flags, length itself, vendorId if exists and data length). - * @param data Avp data part. - */ + * Decodes an AVP. This helper cannot check boundaries. start pointer must be a valid avp context. + * + * @param start Must be a valid avp start (point to the 32-bits avp code word). + * @param id Avp identification (code, vendorId). + * @param flags Avp flags byte. + * @param length Avp length (includes code, flags, length itself, vendorId if exists and data length). + * @param data Avp data part. + */ static void decodeAVP(const char *start, AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException); /** - * Gets the next AVP pointer reference starting from a first-avp data block. It could be the first avp within - * a command, or within an grouped avp. - * - * @param avpsDB AVP data block buffer pointer - * @param avpsLen AVP data block buffer length - * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word). - * - * @return Pointer to the next AVP found. NULL if no more. - */ + * Gets the next AVP pointer reference starting from a first-avp data block. It could be the first avp within + * a command, or within an grouped avp. + * + * @param avpsDB AVP data block buffer pointer + * @param avpsLen AVP data block buffer length + * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word). + * + * @return Pointer to the next AVP found. NULL if no more. + */ static const char * nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException); -// /** -// * Gets the next AVP pointer reference starting from a first-avp datablock. It could be the first avp within -// * a command, or within an grouped avp. -// * -// * @param avpsDB AVPs set as datablock -// * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word). -// * -// * @return Pointer to the next AVP found. NULL if no more. -// */ -// static const char * nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException); + // /** + // * Gets the next AVP pointer reference starting from a first-avp datablock. It could be the first avp within + // * a command, or within an grouped avp. + // * + // * @param avpsDB AVPs set as datablock + // * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word). + // * + // * @return Pointer to the next AVP found. NULL if no more. + // */ + // static const char * nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException); /** - * Gets the next AVP pointer reference within an AVPs set data block with a certain AVP identification. - * - * @param avpsDB AVP data block buffer pointer - * @param avpsLen AVP data block buffer length - * @param id Avp identification (code, vendorId). - * @param n Ocurrence number (first avp, second avp, etc.). 1 by default. - * - * @return Pointer to first AVP found with identification provided. NULL if not found. - */ + * Gets the next AVP pointer reference within an AVPs set data block with a certain AVP identification. + * + * @param avpsDB AVP data block buffer pointer + * @param avpsLen AVP data block buffer length + * @param id Avp identification (code, vendorId). + * @param n Ocurrence number (first avp, second avp, etc.). 1 by default. + * + * @return Pointer to first AVP found with identification provided. NULL if not found. + */ static const char *findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n = 1) throw(anna::RuntimeException); -// /** -// * Gets the next AVP pointer reference within an AVPs set datablock with a certain AVP identification. -// * -// * @param avpsDB AVPs set as datablock -// * @param id Avp identification (code, vendorId). -// * @param n Ocurrence number (first avp, second avp, etc.). 1 by default. -// * -// * @return Pointer to first AVP found with identification provided. NULL if not found. -// */ -// static const char * findAVP(const anna::DataBlock & avpsDB, const AvpId & id, int n = 1) throw(anna::RuntimeException); + // /** + // * Gets the next AVP pointer reference within an AVPs set datablock with a certain AVP identification. + // * + // * @param avpsDB AVPs set as datablock + // * @param id Avp identification (code, vendorId). + // * @param n Ocurrence number (first avp, second avp, etc.). 1 by default. + // * + // * @return Pointer to first AVP found with identification provided. NULL if not found. + // */ + // static const char * findAVP(const anna::DataBlock & avpsDB, const AvpId & id, int n = 1) throw(anna::RuntimeException); @@ -158,6 +233,94 @@ struct functions { static void setHopByHop(anna::DataBlock &, HopByHop) throw(anna::RuntimeException); static void setEndToEnd(anna::DataBlock &, EndToEnd) throw(anna::RuntimeException); static void setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate = true) throw(anna::RuntimeException); + + + /** + Interpret a xml file in order to create a memory xml document. + The xml file is based on this message DTD: + +
+     
+     
+
+     
+     
+
+     
+     
+     
+ + @param xmlDocument XML document allocated by the user of the function (anna::xml::DocumentMemory xmlDocument) + @param xmlPathFile Complete path file to the xml document which represents the diameter message + @see messageXmlDocumentFromXmlString + + @warning Whatever you will do with the xml document, will be only valid inside the scope of such xml document. + For example, you could load the document to be decoded over a codec Message by mean #Message::fromXML (using + the xml document #getRootNode) during document lifetime. After that, it could be destroyed. + */ + static void messageXmlDocumentFromXmlFile(anna::xml::DocumentFile &xmlDocument, const std::string & xmlPathFile) throw(anna::RuntimeException); + + /** + Interpret xml string representation in order to create a memory xml document. + DTD validation is used in the same way that #messageXmlDocumentFromXmlFile does. + + @param xmlDocument XML document allocated by the user of the function (anna::xml::DocumentMemory xmlDocument) + @param xmlString XML string representation of the diameter message + @see messageXmlDocumentFromXmlFile + + @warning Whatever you will do with the xml document, will be only valid inside the scope of such xml document. + For example, you could load the document to be decoded over a codec Message by mean #Message::fromXML (using + the xml document #getRootNode) during document lifetime. After that, it could be destroyed. + */ + static void messageXmlDocumentFromXmlString(anna::xml::DocumentFile &xmlDocument, const std::string &xmlString) throw(anna::RuntimeException); }; diff --git a/include/anna/diameter/codec/tme/Avp.hpp b/include/anna/diameter/codec/tme/Avp.hpp index b4a1917..0b25df7 100644 --- a/include/anna/diameter/codec/tme/Avp.hpp +++ b/include/anna/diameter/codec/tme/Avp.hpp @@ -41,11 +41,13 @@ class ISDNAddress; namespace codec { +class Engine; + namespace tme { class Avp; class Message; -class Engine; +//class Engine; using namespace helpers::tme::codectypes; @@ -70,24 +72,27 @@ class Avp : public anna::diameter::codec::Avp { virtual void allocationByFormat(const anna::diameter::stack::Format *stackFormat) throw(); virtual void clearByFormat() throw(); -protected: +//protected: - /** Codec Engine getter: avoids have to create base engine when using its child */ - virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException); +// /** Codec Engine getter: avoids have to create base engine when using its child */ +// virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException); public: /** * Default constructor + * @param engine Codec engine used */ - Avp(); + Avp(Engine *engine = NULL) : anna::diameter::codec::Avp(engine) {;} /** * Identified constructor - * @param id Avp identifier as pair (code,vendorID). + * @param id Avp identifier as pair (code,vendor-id). + * @param engine Codec engine used */ - Avp(AvpId id); + Avp(AvpId id, Engine *engine = NULL) : anna::diameter::codec::Avp(id, engine) {;} + /** * Destructor @@ -114,7 +119,7 @@ public: friend class Message; - friend class Engine; + friend class anna::diameter::codec::Engine; }; } diff --git a/include/anna/diameter/codec/tme/Engine.hpp b/include/anna/diameter/codec/tme/Engine.hpp__ similarity index 100% rename from include/anna/diameter/codec/tme/Engine.hpp rename to include/anna/diameter/codec/tme/Engine.hpp__ diff --git a/include/anna/diameter/codec/tme/Message.hpp b/include/anna/diameter/codec/tme/Message.hpp index 76524ee..500b252 100644 --- a/include/anna/diameter/codec/tme/Message.hpp +++ b/include/anna/diameter/codec/tme/Message.hpp @@ -28,7 +28,7 @@ namespace codec { namespace tme { class Avp; -class Engine; +//class Engine; /** * Diameter TME message generic container @@ -39,14 +39,32 @@ class Message : public anna::diameter::codec::Message { protected: - /** Codec Engine getter: avoids have to create base engine when using its child */ - virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException); +// /** Codec Engine getter: avoids have to create base engine when using its child */ +// virtual anna::diameter::codec::Engine * getEngine() const throw(anna::RuntimeException); /** * Initializes Message class information. * Any reimplementation must first invoke base class method. */ virtual void initialize() throw(); + +public: + + /** + * Default constructor + * @param engine Codec engine used + */ + Message(Engine *engine = NULL) : anna::diameter::codec::Message(engine) {;} + + /** + * Identified constructor + * @param id Command identifier as pair (code,request-indicator). + * @param engine Codec engine used + */ + Message(CommandId id, Engine *engine = NULL) : anna::diameter::codec::Message(id, engine) {;} + + + }; } diff --git a/include/anna/xml/DTDFile.hpp b/include/anna/xml/DTDFile.hpp index 0068ced..da1e5fd 100644 --- a/include/anna/xml/DTDFile.hpp +++ b/include/anna/xml/DTDFile.hpp @@ -20,10 +20,12 @@ namespace xml { */ class DTDFile : public DTD { public: + /** - Constructor. + Constructor + \param file File name */ - DTDFile() {;} + DTDFile(const char *file = NULL) { if (file) initialize(file); } private: _xmlDtd* parse(const char* fileName) const throw(RuntimeException); diff --git a/include/anna/xml/DTDMemory.hpp b/include/anna/xml/DTDMemory.hpp index b1c4b93..0a33ac5 100644 --- a/include/anna/xml/DTDMemory.hpp +++ b/include/anna/xml/DTDMemory.hpp @@ -23,10 +23,12 @@ namespace xml { */ class DTDMemory : public DTD { public: + /** - Constructor. + Constructor + \param dtd Dtd representation */ - DTDMemory(); + DTDMemory(const char *dtd = NULL); private: std::string a_filename; diff --git a/source/diameter.comm/Engine.cpp b/source/diameter.comm/Engine.cpp index 9bfaf60..489a093 100644 --- a/source/diameter.comm/Engine.cpp +++ b/source/diameter.comm/Engine.cpp @@ -60,14 +60,13 @@ comm::Engine::Engine(const char *className, const stack::Dictionary *baseProtoco a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod), a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/), a_numberOfClientSessionsPerServer(1), - a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str()) + a_baseProtocolCodecEngine((std::string("baseProtocolCodecEngine_for_") + std::string(className)).c_str(), baseProtocolDictionary) { anna::diameter::sccs::activate(); a_realm = anna::functions::getDomainname(); a_host = anna::functions::getHostname(); // Internal base protocol codec engine: - a_baseProtocolCodecEngine.setDictionary(baseProtocolDictionary); a_baseProtocolCodecEngine.setValidationMode(anna::diameter::codec::Engine::ValidationMode::Always); // default was: after decoding } diff --git a/source/diameter/codec/Avp.cpp b/source/diameter/codec/Avp.cpp index 79b04b0..89884be 100644 --- a/source/diameter/codec/Avp.cpp +++ b/source/diameter/codec/Avp.cpp @@ -59,7 +59,6 @@ Avp::Avp(Engine *engine) : a_engine(engine) { initialize(); } - //------------------------------------------------------------------------------ //------------------------------------------------------------------- Avp::Avp() //------------------------------------------------------------------------------ @@ -68,7 +67,6 @@ Avp::Avp(AvpId id, Engine *engine) : a_engine(engine) { setId(id); } - //------------------------------------------------------------------------------ //------------------------------------------------------------------ Avp::~Avp() //------------------------------------------------------------------------------ @@ -76,13 +74,24 @@ Avp::~Avp() { clear(); } +//------------------------------------------------------------------------------ +//------------------------------------------------------------- Avp::setEngine() +//------------------------------------------------------------------------------ +void Avp::setEngine(Engine *engine) throw() { + if (a_engine && engine != a_engine) { + LOGWARNING(anna::Logger::warning("Ignored: it is not a good practice to change the codec engine once assigned. Clear the avp first to set the engine again.", ANNA_FILE_LOCATION)); + return; + } + + a_engine = engine; +} //------------------------------------------------------------------------------ //------------------------------------------------------------- Avp::getEngine() //------------------------------------------------------------------------------ Engine * Avp::getEngine() const throw(anna::RuntimeException) { if(!a_engine) - throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION); + throw anna::RuntimeException("Invalid codec engine reference (NULL). Use setEngine() to set the corresponding codec engine", ANNA_FILE_LOCATION); return a_engine; } @@ -187,6 +196,17 @@ Avp * Avp::addAvp(avp_container &avps, int &insertionPositionForChilds, AvpId id } +//------------------------------------------------------------------------------ +//---------------------------------------------------------------- Avp::addAvp() +//------------------------------------------------------------------------------ +Avp * Avp::addAvp(Avp * avp) throw(anna::RuntimeException) { + if(!avp) return NULL; + if (avp->getEngine() != getEngine()) return NULL; + addChild(avp); + return avp; +} + + //------------------------------------------------------------------------------ //------------------------------------------------------------- Avp::removeAvp() //------------------------------------------------------------------------------ @@ -1227,7 +1247,17 @@ std::string Avp::getXMLdata(bool & isHex, const stack::Format *stackFormat) cons if(!stackFormat) { isHex = true; - return a_Unknown->asHexString(); // el asHexString del OctetString no puede lanzar una excepcion en realidad + // Tricky situation: if you change the dictionary dynamically, and a previous formatted avp + // becomes unknown (the change consists in remove Avps basically), then this would get a core + // dump: a_Unknown = NULL. We are not going to protect that situation because it represents a + // implementation fault, and there are many points which could have similar bad behaviour + // (those where we access directly the a_Unknown pointer). + // The best way to afford this is ... TODO: + // Freeze dictionary after use from any resource (avp, message), setting a flag which deny + // any modification in such dictionary. The best way to do this is on engine configuration + // for Avp o Message, where we could invoke something like getEngine()->getDictionary()->freeze() + + return a_Unknown->asHexString(); // asHexString for OctetString cannot launch exception } // Special case for Address: could launch exception if not printable diff --git a/source/diameter/codec/EngineImpl.cpp b/source/diameter/codec/EngineImpl.cpp index c25bec0..5fff449 100644 --- a/source/diameter/codec/EngineImpl.cpp +++ b/source/diameter/codec/EngineImpl.cpp @@ -23,115 +23,22 @@ #include - -namespace anna { -namespace diameter { -namespace codec { - -const char *MessageDTD = "\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -\n\ -"; - - -} -} -} - using namespace anna::diameter::codec; //------------------------------------------------------------------------------ //----------------------------------------------------- EngineImpl::EngineImpl() //------------------------------------------------------------------------------ -EngineImpl::EngineImpl(const char* className) : +EngineImpl::EngineImpl(const char* className, const stack::Dictionary * dictionary) : anna::Component(className), - a_dictionary(NULL), + a_dictionary(dictionary), a_validationDepth(ValidationDepth::FirstError), a_validationMode(ValidationMode::AfterDecoding), a_singleFailedAVP(true), a_ignoreFlags(false), - a_selectStackWithApplicationId(false), a_fixMode(FixMode::BeforeEncoding) { anna::diameter::sccs::activate(); anna::xml::functions::initialize(); - a_dtd.initialize(MessageDTD); -} - - -//------------------------------------------------------------------------------ -//-------------------------------------------------- EngineImpl::setDictionary() -//------------------------------------------------------------------------------ -const anna::diameter::stack::Dictionary *EngineImpl::setDictionary(unsigned int stackId) throw() { - a_dictionary = (stack::Engine::instantiate()).getDictionary(stackId); - return a_dictionary; } diff --git a/source/diameter/codec/EngineManager.cpp b/source/diameter/codec/EngineManager.cpp new file mode 100644 index 0000000..68add2b --- /dev/null +++ b/source/diameter/codec/EngineManager.cpp @@ -0,0 +1,28 @@ +// ANNA - Anna is Not Nothingness Anymore // +// // +// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo // +// // +// See project site at http://redmine.teslayout.com/projects/anna-suite // +// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE // + + +// Project +#include +#include +#include +#include + +using namespace anna::diameter::codec; + +Engine *EngineManager::getCodecEngine(const ApplicationId &appid) const throw() { + appid_codec_engines_it it = a_appid_codec_engines.find(appid); + if (it != a_appid_codec_engines.end()) + return it->second; + + return NULL; +} + +void EngineManager::registerCodecEngine(const ApplicationId &appid, Engine* engine) throw() { + if (!engine) return; // nothing done + a_appid_codec_engines[appid] = engine; +} diff --git a/source/diameter/codec/Message.cpp b/source/diameter/codec/Message.cpp index 35db129..b5d87f6 100644 --- a/source/diameter/codec/Message.cpp +++ b/source/diameter/codec/Message.cpp @@ -16,6 +16,7 @@ #include // REQUIRED_WORDS #include #include +#include #include #include #include @@ -78,12 +79,26 @@ Message::~Message() { } +//------------------------------------------------------------------------------ +//--------------------------------------------------------- Message::setEngine() +//------------------------------------------------------------------------------ +void Message::setEngine(Engine *engine) throw() { + + if (a_engine && engine != a_engine) { + LOGWARNING(anna::Logger::warning("Ignored: it is not a good practice to change the codec engine once assigned. Clear the message first to set the engine again.", ANNA_FILE_LOCATION)); + return; + } + + a_engine = engine; +} + + //------------------------------------------------------------------------------ //--------------------------------------------------------- Message::getEngine() //------------------------------------------------------------------------------ Engine * Message::getEngine() const throw(anna::RuntimeException) { if(!a_engine) - throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION); + throw anna::RuntimeException("Invalid codec engine reference (NULL). Use setEngine() to set the corresponding codec engine", ANNA_FILE_LOCATION); return a_engine; @@ -208,11 +223,17 @@ void Message::setId(const char *name) throw(anna::RuntimeException) { void Message::setApplicationId(U32 aid) throw(anna::RuntimeException) { a_applicationId = aid; - // Default behaviour: - if (!getEngine()->hasSelectStackWithApplicationId()) return; + // Automatic engine configuration: + if (a_engine) return; - // Adapts for Application-ID stack identifier: - getEngine()->setDictionary(aid); + // Codec engine manager (a multithreaded application, normally does not achieve this point, because + // messages are prepared for each interface with the corresponding codec engine) + anna::diameter::codec::EngineManager &em = anna::diameter::codec::EngineManager::instantiate(); + if (em.selectFromApplicationId()) { + Engine *monostackEngine = em.getMonoStackCodecEngine(); + if (monostackEngine) { a_engine = monostackEngine; return; } + a_engine = em.getCodecEngine(aid); + } } @@ -224,6 +245,17 @@ Avp * Message::addAvp(const char *name) throw(anna::RuntimeException) { } +//------------------------------------------------------------------------------ +//------------------------------------------------------------ Message::addAvp() +//------------------------------------------------------------------------------ +Avp * Message::addAvp(Avp * avp) throw() { + if(!avp) return NULL; + if (avp->getEngine() != getEngine()) return NULL; + addChild(avp); + return avp; +} + + //------------------------------------------------------------------------------ //--------------------------------------------------------- Message::removeAvp() //------------------------------------------------------------------------------ @@ -268,10 +300,10 @@ U24 Message::getLength() const throw() { void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna::RuntimeException) { // Trace LOGDEBUG( - anna::xml::Node root("Message::decode"); - std::string trace = "DataBlock to decode:\n"; - trace += db.asString(); - anna::Logger::debug(trace, ANNA_FILE_LOCATION); + anna::xml::Node root("Message::decode"); + std::string trace = "DataBlock to decode:\n"; + trace += db.asString(); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); clear(); // EXCEPTION MANAGEMENT IN THIS METHOD @@ -372,8 +404,8 @@ void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna:: } catch(anna::RuntimeException &ex) { getEngine()->releaseAvp(avp); LOGWARNING( - anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION); - anna::Logger::warning("Although a decoding error was found, validation could be checked because message could be enough for the application", ANNA_FILE_LOCATION); + anna::Logger::warning(ex.getText(), ANNA_FILE_LOCATION); + anna::Logger::warning("Although a decoding error was found, validation could be checked because message could be enough for the application", ANNA_FILE_LOCATION); ); break; } @@ -389,9 +421,9 @@ void Message::decode(const anna::DataBlock &db, Message *ptrAnswer) throw(anna:: // Trace LOGDEBUG( - std::string trace = "Message decoded:\n"; - trace += asXMLString(); - anna::Logger::debug(trace, ANNA_FILE_LOCATION); + std::string trace = "Message decoded:\n"; + trace += asXMLString(); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); // Post-Validation Engine::ValidationMode::_v vmode = getEngine()->getValidationMode(); @@ -453,19 +485,19 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron if(isRequest()) return; -// RFC 6733: -// -// 7.5. Failed-AVP AVP -// -// The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides -// debugging information in cases where a request is rejected or not -// fully processed due to erroneous information in a specific AVP. The -// value of the Result-Code AVP will provide information on the reason -// for the Failed-AVP AVP. A Diameter answer message SHOULD contain an -// instance of the Failed-AVP AVP that corresponds to the error -// indicated by the Result-Code AVP. For practical purposes, this -// Failed-AVP would typically refer to the first AVP processing error -// that a Diameter node encounters. + // RFC 6733: + // + // 7.5. Failed-AVP AVP + // + // The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides + // debugging information in cases where a request is rejected or not + // fully processed due to erroneous information in a specific AVP. The + // value of the Result-Code AVP will provide information on the reason + // for the Failed-AVP AVP. A Diameter answer message SHOULD contain an + // instance of the Failed-AVP AVP that corresponds to the error + // indicated by the Result-Code AVP. For practical purposes, this + // Failed-AVP would typically refer to the first AVP processing error + // that a Diameter node encounters. // Although the Failed-AVP definition has cardinality 1* and Failed-AVP itself is defined in // most of the command codes as *[Failed-AVP], i think this is not a deliberate ambiguity. @@ -485,17 +517,17 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron Avp *leaf = theFailedAvp; LOGDEBUG( - std::string msg = "Adding to Failed-AVP, the wrong avp "; - msg += wrongName ? wrongName : (anna::diameter::functions::avpIdAsPairString(wrong)); - msg += " found inside "; - msg += parent.asString(); + std::string msg = "Adding to Failed-AVP, the wrong avp "; + msg += wrongName ? wrongName : (anna::diameter::functions::avpIdAsPairString(wrong)); + msg += " found inside "; + msg += parent.asString(); - anna::Logger::debug(msg, ANNA_FILE_LOCATION); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); std::vector::const_iterator it; for(it = parent.AvpsId.begin(); it != parent.AvpsId.end(); it++) - leaf = leaf->addAvp(*it); + leaf = leaf->addAvp(*it); leaf->addAvp(wrong); } @@ -504,7 +536,7 @@ void Message::setFailedAvp(const parent_t &parent, AvpId wrong, const char *wron //------------------------------------------------------------------------------ //----------------------------------------------- Message::setStandardToAnswer() //------------------------------------------------------------------------------ -void Message::setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode) throw() { +void Message::setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode) throw(anna::RuntimeException) { if(!request.getId().second) return; // Message header: @@ -513,7 +545,7 @@ void Message::setStandardToAnswer(const Message &request, const std::string &ori const Avp *reqSessionId = request.getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore); if(reqSessionId) - if(!getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore)) + if(!getAvp(helpers::base::AVPID__Session_Id, 1, anna::Exception::Mode::Ignore)) addAvp(helpers::base::AVPID__Session_Id)->getUTF8String()->setValue(reqSessionId->getUTF8String()->getValue()); // Origin-Host & Realm @@ -533,9 +565,9 @@ void Message::setStandardToAnswer(const Message &request, const std::string &ori // Fix: fix(); LOGDEBUG( - std::string msg = "Completed answer:\n"; - msg += asXMLString(); - anna::Logger::debug(msg, ANNA_FILE_LOCATION); + std::string msg = "Completed answer:\n"; + msg += asXMLString(); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); } @@ -648,9 +680,9 @@ const anna::DataBlock & Message::code() throw(anna::RuntimeException) { // Trace LOGDEBUG( - std::string trace = "Message to code:\n"; - trace += asXMLString(); - anna::Logger::debug(trace, ANNA_FILE_LOCATION); + std::string trace = "Message to code:\n"; + trace += asXMLString(); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); // Memory allocation U24 length = getLength(); @@ -704,29 +736,24 @@ const anna::DataBlock & Message::code() throw(anna::RuntimeException) { // Trace LOGDEBUG( - std::string trace = "DataBlock encoded:\n"; - trace += a_forCode.asString(); -// trace += "\nAs continuous hexadecimal string:\n"; -// trace += anna::functions::asHexString(a_forCode); - anna::Logger::debug(trace, ANNA_FILE_LOCATION); + std::string trace = "DataBlock encoded:\n"; + trace += a_forCode.asString(); + // trace += "\nAs continuous hexadecimal string:\n"; + // trace += anna::functions::asHexString(a_forCode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); ); return a_forCode; } - //------------------------------------------------------------------------------ -//----------------------------------------------------- Message::fromXMLString() +//----------------------------------------------------------- Message::loadXML() //------------------------------------------------------------------------------ -void Message::fromXMLString(const std::string &xmlString) throw(anna::RuntimeException) { - LOGDEBUG(anna::Logger::debug("Reading diameter message from xml string representation", ANNA_FILE_LOCATION)); - anna::xml::DocumentMemory xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) - const anna::xml::Node *rootNode; - xmlDocument.initialize(xmlString.c_str()); - rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd - LOGDEBUG(anna::Logger::debug("Read OK from XML string representation", ANNA_FILE_LOCATION)); - fromXML(rootNode); -} +void Message::loadXML(const std::string &xmlPathFile) throw(anna::RuntimeException) { + anna::xml::DocumentFile xmlDocument; + anna::diameter::codec::functions::messageXmlDocumentFromXmlFile(xmlDocument, xmlPathFile); + fromXML(xmlDocument.getRootNode()); +} //------------------------------------------------------------------------------ //----------------------------------------------------------- Message::fromXML() @@ -861,7 +888,7 @@ void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeExc msg += "': negative values are not allowed"; throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } - */ + */ } else u_aux = 0; setHopByHop(u_aux); @@ -876,7 +903,7 @@ void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeExc msg += "': negative values are not allowed"; throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } - */ + */ } else u_aux = 0; setEndToEnd(u_aux); @@ -905,31 +932,6 @@ void Message::fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeExc } -//------------------------------------------------------------------------------ -//----------------------------------------------------------- Message::loadXML() -//------------------------------------------------------------------------------ -void Message::loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException) { - LOGDEBUG( - std::string trace = "Loading diameter message from file '"; - trace += xmlPathFile; - trace += "'"; - anna::Logger::debug(trace, ANNA_FILE_LOCATION); - ); - anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy) - const anna::xml::Node *rootNode; - xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error - rootNode = xmlDocument.parse(getEngine()->getDTD()); // Parsing: fail here if xml violates dtd - LOGDEBUG( - std::string trace = "Loaded XML file ("; - trace += xmlPathFile; - trace += "):\n"; - trace += anna::xml::Compiler().apply(rootNode); - anna::Logger::debug(trace, ANNA_FILE_LOCATION); - ); - fromXML(rootNode); -} - - //------------------------------------------------------------------------------ //------------------------------------------------------------- Message::asXML() //------------------------------------------------------------------------------ diff --git a/source/diameter/codec/functions.cpp b/source/diameter/codec/functions.cpp index 8c5d350..93ee8e3 100644 --- a/source/diameter/codec/functions.cpp +++ b/source/diameter/codec/functions.cpp @@ -22,41 +22,47 @@ #include -using namespace anna::diameter::codec; - +namespace anna { +namespace diameter { +namespace codec { +// Preloaded MemoryDTD for function helpers: +anna::xml::DTDMemory MessageDTDMemory(MessageDTD); +} +} +} // Parent struct helper ///////////////////////////////////////////////////////////////////////////// -void parent::setMessage(const anna::diameter::CommandId & mid, const char *mname) throw() { +void anna::diameter::codec::parent::setMessage(const anna::diameter::CommandId & mid, const char *mname) throw() { MessageId = mid; if (mname) { MessageName = mname; } else { - MessageName = "Message"; + MessageName = "Message"; MessageName += anna::diameter::functions::commandIdAsPairString(mid); } } -void parent::addAvp(const anna::diameter::AvpId & aid, const char *aname) throw() { +void anna::diameter::codec::parent::addAvp(const anna::diameter::AvpId & aid, const char *aname) throw() { AvpsId.push_back(aid); std::string name; if (aname) { - name = aname; + name = aname; } else { name = "Avp"; - name += anna::diameter::functions::avpIdAsPairString(aid); + name += anna::diameter::functions::avpIdAsPairString(aid); } AvpsName.push_back(name); } -std::string parent::asString() const throw() { // "->->...->" +std::string anna::diameter::codec::parent::asString() const throw() { // "->->...->" std::string result = MessageName; for (std::vector::const_iterator it = AvpsName.begin(); it != AvpsName.end(); it++) { - result += "->"; - result += (*it); + result += "->"; + result += (*it); } return result; @@ -64,90 +70,88 @@ std::string parent::asString() const throw() { // "->->.. ///////////////////////////////////////////////////////////////////////////////////////////////////// - - // getters -anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::CommandId anna::diameter::codec::functions::getCommandId(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * data = db.getData(); U8 flags = data[4]; U24 code = DECODE3BYTES_INDX_VALUETYPE(data, 5, U24); -// U24 code = (((U24)data[5] << 16) & 0xFF0000) + -// (((U24)data[6] << 8) & 0x00FF00) + -// (((U24)data[7]) & 0x0000FF); + // U24 code = (((U24)data[5] << 16) & 0xFF0000) + + // (((U24)data[6] << 8) & 0x00FF00) + + // (((U24)data[7]) & 0x0000FF); return (anna::diameter::CommandId(code, (flags & Message::RBitMask) != 0x00)); } -bool functions::requestBit(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool anna::diameter::codec::functions::requestBit(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); return (((db.getData())[4] & Message::RBitMask) != 0x00); } -bool functions::proxiableBit(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool anna::diameter::codec::functions::proxiableBit(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); return (((db.getData())[4] & Message::PBitMask) != 0x00); } -bool functions::errorBit(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool anna::diameter::codec::functions::errorBit(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); return (((db.getData())[4] & Message::EBitMask) != 0x00); } -bool functions::potentiallyReTransmittedMessageBit(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool anna::diameter::codec::functions::potentiallyReTransmittedMessageBit(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); return (((db.getData())[4] & Message::TBitMask) != 0x00); } -anna::diameter::ApplicationId functions::getApplicationId(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * appidPtr = db.getData() + 8; anna::diameter::ApplicationId result = DECODE4BYTES_INDX_VALUETYPE(appidPtr, 0, U32); -// anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) + -// (((U32)appidPtr[1] << 16) & 0x00FF0000) + -// (((U32)appidPtr[2] << 8) & 0x0000FF00) + -// (((U32)appidPtr[3]) & 0x000000FF); + // anna::diameter::ApplicationId result = (((U32)appidPtr[0] << 24) & 0xFF000000) + + // (((U32)appidPtr[1] << 16) & 0x00FF0000) + + // (((U32)appidPtr[2] << 8) & 0x0000FF00) + + // (((U32)appidPtr[3]) & 0x000000FF); return result; } -anna::diameter::HopByHop functions::getHopByHop(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::HopByHop anna::diameter::codec::functions::getHopByHop(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * hbhPtr = db.getData() + 12; anna::diameter::HopByHop result = DECODE4BYTES_INDX_VALUETYPE(hbhPtr, 0, U32); -// anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) + -// (((U32)hbhPtr[1] << 16) & 0x00FF0000) + -// (((U32)hbhPtr[2] << 8) & 0x0000FF00) + -// (((U32)hbhPtr[3]) & 0x000000FF); + // anna::diameter::HopByHop result = (((U32)hbhPtr[0] << 24) & 0xFF000000) + + // (((U32)hbhPtr[1] << 16) & 0x00FF0000) + + // (((U32)hbhPtr[2] << 8) & 0x0000FF00) + + // (((U32)hbhPtr[3]) & 0x000000FF); return result; } -anna::diameter::EndToEnd functions::getEndToEnd(const anna::DataBlock & db) throw(anna::RuntimeException) { +anna::diameter::EndToEnd anna::diameter::codec::functions::getEndToEnd(const anna::DataBlock & db) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); const char * etePtr = db.getData() + 16; anna::diameter::EndToEnd result = DECODE4BYTES_INDX_VALUETYPE(etePtr, 0, U32); -// anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) + -// (((U32)etePtr[1] << 16) & 0x00FF0000) + -// (((U32)etePtr[2] << 8) & 0x0000FF00) + -// (((U32)etePtr[3]) & 0x000000FF); + // anna::diameter::EndToEnd result = (((U32)etePtr[0] << 24) & 0xFF000000) + + // (((U32)etePtr[1] << 16) & 0x00FF0000) + + // (((U32)etePtr[2] << 8) & 0x0000FF00) + + // (((U32)etePtr[3]) & 0x000000FF); return result; } -void functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, diameter::CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException) { if(start == NULL) throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); @@ -181,7 +185,7 @@ void functions::decodeCommandHeader(const char *start, char & version, U24 & len ete = DECODE4BYTES_INDX_VALUETYPE(start, 16, U32); } -void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException) { if(start == NULL) throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); @@ -208,24 +212,24 @@ void functions::decodeAVP(const char *start, diameter::AvpId & id, char & flags, const char *dataPointer = (vendorSpecific ? (start + 12) : (start + 8)); // pointer to data part data.assign(dataPointer, dataLength); LOGLOCAL3( - std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s", - id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str()); - anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION); + std::string msg = anna::functions::asString("decodedAVP id (%d,%d), length %d, data length %d, data part 0x%s", + id.first, id.second, length, dataLength, anna::functions::asHexString(anna::DataBlock(dataPointer, dataLength)).c_str()); + anna::Logger::write(anna::Logger::Local3, msg, ANNA_FILE_LOCATION); ); } -const char * functions::nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException) { +const char * anna::diameter::codec::functions::nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException) { if(start == NULL) throw anna::RuntimeException("NULL provided start pointer", ANNA_FILE_LOCATION); if(avpsDB == NULL) throw anna::RuntimeException("NULL provided avpsDB pointer", ANNA_FILE_LOCATION); const char *result; -// LOGDEBUG( -// std::string msg("DataBlock provided to 'nextAVP'"); -// msg += avpsDB.asString(); -// anna::Logger::debug(msg, ANNA_FILE_LOCATION); -// ); + // LOGDEBUG( + // std::string msg("DataBlock provided to 'nextAVP'"); + // msg += avpsDB.asString(); + // anna::Logger::debug(msg, ANNA_FILE_LOCATION); + // ); //int avpLength = (start[5] << 16) + (start[6] << 8) + start[7]; // AVP Length int avpLength = DECODE3BYTES_INDX_VALUETYPE(start, 5, int); result = start + 4 * REQUIRED_WORDS(avpLength); @@ -242,7 +246,7 @@ const char * functions::nextAVP(const char *avpsDB, int avpsLen, const char *sta // return nextAVP(avpsDB.getData(), avpsDB.getSize(), start); //} -const char * functions::findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n) throw(anna::RuntimeException) { +const char * anna::diameter::codec::functions::findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n) throw(anna::RuntimeException) { const char *result = avpsDB; // first avp int positives = 0; // Decoded avp information: @@ -259,10 +263,10 @@ const char * functions::findAVP(const char *avpsDB, int avpsLen, const diameter: if(result == NULL) { // (*) LOGDEBUG( - std::string msg = "AVP "; - msg += anna::diameter::functions::avpIdAsPairString(id); - msg += " not found at DataBlock"; - anna::Logger::debug(msg, ANNA_FILE_LOCATION); + std::string msg = "AVP "; + msg += anna::diameter::functions::avpIdAsPairString(id); + msg += " not found at DataBlock"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); ); return NULL; } @@ -280,7 +284,7 @@ const char * functions::findAVP(const char *avpsDB, int avpsLen, const diameter: //} // modifiers -void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) { throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); } @@ -294,7 +298,7 @@ void functions::setHopByHop(anna::DataBlock & db, diameter::HopByHop hbh) throw( } -void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) { throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); } @@ -307,7 +311,7 @@ void functions::setEndToEnd(anna::DataBlock & db, diameter::EndToEnd ete) throw( memcpy((char *)(db.getData() + 16), source, 4); } -void functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate) throw(anna::RuntimeException) { +void anna::diameter::codec::functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate) throw(anna::RuntimeException) { if(db.getSize() < Message::HeaderLength) { throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); } @@ -318,4 +322,23 @@ void functions::setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db memcpy((char *)(db.getData() + 4), flags, 1); } +// XML parsers for diameter messages /////////////////////////////////////////////////////////////////////////// +void anna::diameter::codec::functions::messageXmlDocumentFromXmlFile(anna::xml::DocumentFile &xmlDocument, const std::string & xmlPathFile) throw(anna::RuntimeException) { + LOGDEBUG(anna::Logger::debug(anna::functions::asString("Parsing diameter message from xml file '%s' into xml document", xmlPathFile.c_str()), ANNA_FILE_LOCATION)); + xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error + const anna::xml::Node *rootNode = xmlDocument.parse(MessageDTDMemory); // Parsing: fail here if xml violates dtd + LOGDEBUG( + std::string trace = "Parsing OK from XML file '"; + trace += xmlPathFile; + trace += "':\n"; + trace += anna::xml::Compiler().apply(rootNode); + anna::Logger::debug(trace, ANNA_FILE_LOCATION); + ); +} +void anna::diameter::codec::functions::messageXmlDocumentFromXmlString(anna::xml::DocumentFile &xmlDocument, const std::string &xmlString) throw(anna::RuntimeException) { + LOGDEBUG(anna::Logger::debug("Parsing diameter message from xml string representation into xml document", ANNA_FILE_LOCATION)); + xmlDocument.initialize(xmlString.c_str()); + xmlDocument.parse(MessageDTDMemory); // Parsing: fail here if xml violates dtd + LOGDEBUG(anna::Logger::debug("Parsing OK from XML string representation", ANNA_FILE_LOCATION)); +} diff --git a/source/diameter/codec/tme/Avp.cpp b/source/diameter/codec/tme/Avp.cpp index f105670..6875c87 100644 --- a/source/diameter/codec/tme/Avp.cpp +++ b/source/diameter/codec/tme/Avp.cpp @@ -8,7 +8,7 @@ // Local #include -#include +//#include #include #include @@ -21,22 +21,20 @@ using namespace anna::diameter::codec::tme; -//------------------------------------------------------------------------------ -//------------------------------------------------------------------- Avp::Avp() -//------------------------------------------------------------------------------ -Avp::Avp() { - initialize(); -} - - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------- Avp::Avp() -//------------------------------------------------------------------------------ -Avp::Avp(AvpId id) { - initialize(); - setId(id); -} - +////------------------------------------------------------------------------------ +////------------------------------------------------------------------- Avp::Avp() +////------------------------------------------------------------------------------ +//Avp::Avp(Engine *engine) : anna::diameter::codec::Avp(engine) { +// initialize(); +//} +// +////------------------------------------------------------------------------------ +////------------------------------------------------------------------- Avp::Avp() +////------------------------------------------------------------------------------ +//Avp::Avp(AvpId id, Engine *engine)/* : anna::diameter::codec::Avp(id, engine)*/ { +// initialize(); +// setId(id); +//} //------------------------------------------------------------------------------ //------------------------------------------------------------------ Avp::~Avp() @@ -46,15 +44,15 @@ Avp::~Avp() { } -//------------------------------------------------------------------------------ -//------------------------------------------------------------- Avp::getEngine() -//------------------------------------------------------------------------------ -anna::diameter::codec::Engine * Avp::getEngine() const throw(anna::RuntimeException) { - if(!a_engine) - throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION); - - return a_engine; -} +////------------------------------------------------------------------------------ +////------------------------------------------------------------- Avp::getEngine() +////------------------------------------------------------------------------------ +//anna::diameter::codec::Engine * Avp::getEngine() const throw(anna::RuntimeException) { +// if(!a_engine) +// throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION); +// +// return a_engine; +//} //------------------------------------------------------------------------------ diff --git a/source/diameter/codec/tme/Message.cpp b/source/diameter/codec/tme/Message.cpp index 190a281..69872cd 100644 --- a/source/diameter/codec/tme/Message.cpp +++ b/source/diameter/codec/tme/Message.cpp @@ -8,22 +8,22 @@ // Local #include -#include +//#include #include using namespace anna::diameter::codec::tme; -//------------------------------------------------------------------------------ -//--------------------------------------------------------- Message::getEngine() -//------------------------------------------------------------------------------ -anna::diameter::codec::Engine * Message::getEngine() const throw(anna::RuntimeException) { - if(!a_engine) - throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION); - - return a_engine; -} +////------------------------------------------------------------------------------ +////--------------------------------------------------------- Message::getEngine() +////------------------------------------------------------------------------------ +//anna::diameter::codec::Engine * Message::getEngine() const throw(anna::RuntimeException) { +// if(!a_engine) +// throw anna::RuntimeException("Invalid codec engine reference (NULL)", ANNA_FILE_LOCATION); +// +// return a_engine; +//} //------------------------------------------------------------------------------ diff --git a/source/xml/DTDFile.cpp b/source/xml/DTDFile.cpp index 6cc20c3..cdddb0a 100644 --- a/source/xml/DTDFile.cpp +++ b/source/xml/DTDFile.cpp @@ -23,7 +23,7 @@ using namespace std; using namespace anna; using namespace anna::xml; -_xmlDtd* DTDFile::parse(const char* filename) const +_xmlDtd* DTDFile::parse(const char *filename) const throw(RuntimeException) { LOGMETHOD(TraceMethod tf("anna::xml::DTDFile", "parse", ANNA_FILE_LOCATION)); _xmlDtd* result; diff --git a/source/xml/DTDMemory.cpp b/source/xml/DTDMemory.cpp index 3721681..e685ada 100644 --- a/source/xml/DTDMemory.cpp +++ b/source/xml/DTDMemory.cpp @@ -24,16 +24,17 @@ using namespace std; using namespace anna; using namespace anna::xml; -DTDMemory::DTDMemory() { +DTDMemory::DTDMemory(const char *dtd) { a_filename = "/tmp/anna.xml."; a_filename += functions::asString((int) getpid()); a_filename += ".dtd"; + if (dtd) initialize(dtd); } //--------------------------------------------------------------------------------------------- // Aunque la libXML ofrece funciones para analizar una DTD a partir de un buffer de memoria -// hemos sido incapaces de hacerla funcionar correctamente. Así que nos vemos obligados -// a volcar el buffer en un archivo .. y una vez allí analizarlo con la función que analiza +// hemos sido incapaces de hacerla funcionar correctamente. As� que nos vemos obligados +// a volcar el buffer en un archivo .. y una vez all� analizarlo con la funci�n que analiza // la DTD a partir de un archivo. //--------------------------------------------------------------------------------------------- _xmlDtd* DTDMemory::parse(const char* content) const -- 2.20.1