From: Eduardo Ramos Testillano Date: Mon, 13 Jul 2015 02:34:30 +0000 (+0200) Subject: Base protocol codec for comm::Engine. Supported retransmissions X-Git-Tag: REFACTORING_TESTING_LIBRARY~126 X-Git-Url: https://git.teslayout.com/public/public/public/?a=commitdiff_plain;h=129af2a9a7c287843be5bd443c5b1ad9b08438a8;p=anna.git Base protocol codec for comm::Engine. Supported retransmissions --- diff --git a/example/diameter/launcher/DEPLOY_clientAndServer.sh b/example/diameter/launcher/DEPLOY_clientAndServer.sh new file mode 100755 index 0000000..c8bf3e6 --- /dev/null +++ b/example/diameter/launcher/DEPLOY_clientAndServer.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +############# +# VARIABLES # +############# +DEPLOY_SCR=`dirname $0`/DEPLOY.sh + +############# +# FUNCTIONS # +############# +usage() { + echo + echo "Usage: $0 " + echo + exit 1 +} + +############# +# EXECUTION # +############# +DIR=$1 +[ "$DIR" = "" ] && usage +[ -d $DIR ] && usage + +$DEPLOY_SCR b $DIR/client +$DEPLOY_SCR b $DIR/server + +cd $DIR/client +echo c | ./configure.sh + +cd - >/dev/null + +cd $DIR/server +echo s | ./configure.sh + +echo +echo "Done!" +echo + diff --git a/example/diameter/launcher/Launcher.cpp b/example/diameter/launcher/Launcher.cpp index 710ebfe..05422f4 100644 --- a/example/diameter/launcher/Launcher.cpp +++ b/example/diameter/launcher/Launcher.cpp @@ -58,7 +58,14 @@ void Launcher::releaseCommMessage(anna::diameter::comm::Message *msg) throw() { a_commMessages.release(msg); } -void Launcher::baseProtocolSetupAsClient(anna::diameter::codec::Engine *codecEngine) throw(anna::RuntimeException) { +void Launcher::baseProtocolSetupAsClient() throw(anna::RuntimeException) { + + anna::diameter::codec::Engine *codecEngine; + + codecEngine = getCodecEngine(); + // XXXXXXXXXXXXXXXXXXXX codecEngine = a_myDiameterEngine->getBaseProtocolCodecEngine(); + + // Build CER // ::= < Diameter Header: 257, REQ > // { Origin-Host } 264 diameterIdentity @@ -339,7 +346,7 @@ throw(anna::RuntimeException) { std::string dictionaryParameter = cl.getValue("dictionary"); lst.apply(dictionaryParameter, ","); - if(lst.size() >= 1) { // always true (at least one, because -dictionary is mandatory) + if(lst.size() >= 1) { // always true (at least one, because --dictionary is mandatory) anna::Tokenizer::const_iterator tok_min(lst.begin()); anna::Tokenizer::const_iterator tok_max(lst.end()); anna::Tokenizer::const_iterator tok_iter; @@ -517,6 +524,10 @@ throw(anna::RuntimeException) { getCodecEngine()->ignoreFlagsOnValidation(cl.exists("ignoreFlags")); // XXXXXXXXXXXXXXXXXXXXXXX + // Base protocol for internal use (CEA, DWA, DPA and tracing: + a_myDiameterEngine->setBaseProtocolCodecEngine(getCodecEngine()); + + // Diameter Server: if(cl.exists("diameterServer")) startDiameterServer(cl.exists("diameterServerSessions") ? cl.getIntegerValue("diameterServerSessions") : 1); @@ -566,7 +577,7 @@ throw(anna::RuntimeException) { int entityServerSessions = cl.exists("entityServerSessions") ? cl.getIntegerValue("entityServerSessions") : 1; if(entityServerSessions > 0) { - baseProtocolSetupAsClient(getCodecEngine()); // Same CER/CEA, DWR/DWA for all diameter servers XXXXXXXXXXXXXXXXXXXXXXXXX + baseProtocolSetupAsClient(); anna::socket_v servers = anna::functions::getSocketVectorFromString(cl.getValue("entity")); a_myDiameterEngine->setNumberOfClientSessionsPerServer(entityServerSessions); a_entity = (MyDiameterEntity*)(a_myDiameterEngine->createEntity(servers, "Launcher diameter entity")); @@ -1303,6 +1314,9 @@ void Launcher::eventOperation(const std::string &operation, std::string &respons if(!entity) throw anna::RuntimeException("No entity configured to send the message", ANNA_FILE_LOCATION); anna::diameter::comm::Message *msg = createCommMessage(); +//xxxxxxxxxxxxx + msg->setRetries(4); + msg->setOnExpiry(anna::diameter::comm::Message::OnExpiry::Retransmit); if((opType == "sendxml") || (opType == "sendxml2e")) { codecMsg.loadXML(param1); @@ -1635,10 +1649,12 @@ int MyDiameterEntity::readSocketId(const anna::diameter::comm::Message* message, if(sessionBasedModelsType == "SessionIdOptionalPart") return (atoi(optional.c_str()) % maxClientSessions); } - //case anna::diameter::helpers::dcca::ChargingContext::SMS: - //case anna::diameter::helpers::dcca::ChargingContext::MMS: - //default: - // return -1; // IEC model and Unknown traffic types + + case anna::diameter::helpers::dcca::ChargingContext::SMS: + case anna::diameter::helpers::dcca::ChargingContext::MMS: + case anna::diameter::helpers::dcca::ChargingContext::Unknown: + default: + return -1; } } catch(anna::RuntimeException &ex) { LOGDEBUG( diff --git a/example/diameter/launcher/Launcher.hpp b/example/diameter/launcher/Launcher.hpp index b1bf52a..d7e4bba 100644 --- a/example/diameter/launcher/Launcher.hpp +++ b/example/diameter/launcher/Launcher.hpp @@ -78,7 +78,7 @@ public: anna::diameter::codec::Engine *getCodecEngine() const throw() { return a_codecEngine; } // XXXXXXXXXXXXXXXXX El del nodo de trabajo MyCommunicator *getCommunicator() throw() { return a_communicator; } MyDiameterEngine* getMyDiameterEngine() const throw() { return (a_myDiameterEngine); } - void baseProtocolSetupAsClient(anna::diameter::codec::Engine *codecEngine) throw(anna::RuntimeException); + void baseProtocolSetupAsClient() throw(anna::RuntimeException); MyDiameterEntity *getEntity() throw() { return a_entity; } MyLocalServer* getDiameterLocalServer() throw() { return a_diameterLocalServer; } void eventOperation(const std::string &, std::string &) throw(anna::RuntimeException); diff --git a/example/diameter/launcher/MyDiameterEngine.hpp b/example/diameter/launcher/MyDiameterEngine.hpp index 4606edc..13aae6c 100644 --- a/example/diameter/launcher/MyDiameterEngine.hpp +++ b/example/diameter/launcher/MyDiameterEngine.hpp @@ -20,7 +20,7 @@ class MyDiameterEngine : public anna::diameter::comm::Engine { public: - MyDiameterEngine(const char *className = "MyDiameterEngine") : Engine(className) {;} + MyDiameterEngine(const char *className = "MyDiameterEngine") : Engine(className, NULL /* we will assign the base protocol codec engine later*/) {;} // Default implementation is enough // void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {;} // DPA is not replied diff --git a/example/diameter/launcher/MyDiameterEntity.cpp b/example/diameter/launcher/MyDiameterEntity.cpp index 702ec56..ae4a3db 100644 --- a/example/diameter/launcher/MyDiameterEntity.cpp +++ b/example/diameter/launcher/MyDiameterEntity.cpp @@ -78,7 +78,7 @@ throw(anna::RuntimeException) { if(localServer && (cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CER */) { try { anna::diameter::comm::Message *msg = my_app.createCommMessage(); - msg->updateEndToEnd(false); // end-to-end will be kept + msg->forwardEndToEnd(); // end-to-end will be kept msg->setBody(message); msg->setRequestClientSessionKey(clientSession->getKey()); bool success = localServer->send(msg); @@ -159,7 +159,7 @@ throw(anna::RuntimeException) { if(localServer && (request_cid != anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request) /* don't forward CEA */) { try { anna::diameter::comm::Message *msg = my_app.createCommMessage(); - msg->updateEndToEnd(false); // end-to-end will be kept + msg->forwardEndToEnd(); // end-to-end will be kept msg->setBody(*message); bool success = localServer->send(msg, request->getRequestServerSessionKey()); my_app.releaseCommMessage(msg); diff --git a/example/diameter/launcher/MyLocalServer.cpp b/example/diameter/launcher/MyLocalServer.cpp index 91e95f5..599917f 100644 --- a/example/diameter/launcher/MyLocalServer.cpp +++ b/example/diameter/launcher/MyLocalServer.cpp @@ -48,7 +48,7 @@ throw(anna::RuntimeException) { anna::diameter::comm::Entity *entity = my_app.getEntity(); if(!programmed && entity) { // forward condition (no programmed answer + entity available) anna::diameter::comm::Message *msg = my_app.createCommMessage(); - msg->updateEndToEnd(false); // end-to-end will be kept + msg->forwardEndToEnd(); // end-to-end will be kept msg->setBody(message); msg->setRequestServerSessionKey(serverSession->getKey()); bool success = entity->send(msg, cl.exists("balance")); @@ -179,7 +179,7 @@ throw(anna::RuntimeException) { try { anna::diameter::comm::Message *msg = my_app.createCommMessage(); - msg->updateEndToEnd(false); // end-to-end will be kept + msg->forwardEndToEnd(); // end-to-end will be kept msg->setBody(*message); // Metodo 1: diff --git a/include/anna/diameter.comm/ClientSession.hpp b/include/anna/diameter.comm/ClientSession.hpp index 93490cb..0b4b437 100644 --- a/include/anna/diameter.comm/ClientSession.hpp +++ b/include/anna/diameter.comm/ClientSession.hpp @@ -232,6 +232,13 @@ private: */ void eventPeerShutdown() throw(); + /** + Handler about a request retransmission over the session. + + \param request Message retransmitted + */ + void eventRequestRetransmission(Message *request) throw(); + /** Handler for diameter server (client-session) responses diff --git a/include/anna/diameter.comm/Engine.hpp b/include/anna/diameter.comm/Engine.hpp index d1c276e..609c459 100644 --- a/include/anna/diameter.comm/Engine.hpp +++ b/include/anna/diameter.comm/Engine.hpp @@ -94,6 +94,27 @@ class LocalServer; class Engine : public anna::app::Component { public: + /** + * Sets the base protocol codec engine used internally + * + * @param baseProtocolCodecEngine This will be used internally during invokation of @readCEA, @readDPA and @readDWA on servers, + * and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL but you must be + * sure that neither of the former situations are going to happen or an exception will be thrown. It is recommended to register + * a codec engine pointed to a base protocol stack (you can use the files 'avps_ietf.xml' and 'commands_baseProtocol.xml' + * located on ANNA suite project under 'source/diameter/stack/setups', or perhaps you can create your own dictionary from + * file or directly with the dictionay creation API. Even you can use a greater dictionary (application dictionary), the + * only condition is that must contain the resources to build base protocol messages. You could provide this in engine constructor, + * but don't forget it. + */ + void setBaseProtocolCodecEngine(codec::Engine *baseProtocolCodecEngine) throw() { a_baseProtocolCodecEngine = baseProtocolCodecEngine; } + + /** + * Gets the base protocol codec engine used internally + * + * @see setBaseProtocolCodecEngine + */ + codec::Engine * getBaseProtocolCodecEngine() const throw() { return a_baseProtocolCodecEngine; } + /** Diameter application node realm name (used to be the site domain name). @@ -613,9 +634,18 @@ public: protected: /** Constructor. + @param className Component class name + @param baseProtocolCodecEngine This will be used internally during invokation of @readCEA, @readDPA and @readDWA on servers, + and also used during base protocol messages tracing (if debug traces are enabled). You could provide NULL but you must be + sure that neither of the former situations are going to happen or an exception will be thrown. It is recommended to register + a codec engine pointed to a base protocol stack (you can use the files 'avps_ietf.xml' and 'commands_baseProtocol.xml' + located on ANNA suite project under 'source/diameter/stack/setups', or perhaps you can create your own dictionary from + file or directly with the dictionay creation API. Even you can use a greater dictionary (application dictionary), the + only condition is that must contain the resources to build base protocol messages. You could use @setBaseProtocolCodecEngine + to set this reference later; don't forget it. */ - Engine(const char *className); + Engine(const char *className, codec::Engine *baseProtocolCodecEngine); // INTERNAL CREATORS AND CLOSE METHODS @@ -668,6 +698,9 @@ protected: private: + // Internal use: tracing and readCEA/DPA/DWA + codec::Engine *a_baseProtocolCodecEngine; + std::string a_realm; std::string a_host; bool a_autoBind; diff --git a/include/anna/diameter.comm/Entity.hpp b/include/anna/diameter.comm/Entity.hpp index 2335d82..d0da8c5 100644 --- a/include/anna/diameter.comm/Entity.hpp +++ b/include/anna/diameter.comm/Entity.hpp @@ -216,7 +216,7 @@ public: // */ // OJO: en el caso estandard, no se prueban todas las sessiones de un servidor si tiene mas de una, luego la alarma -// generada en caso de error, presupone que las sessiones no usadas, también darían error, lo cual no tiene porque +// generada en caso de error, presupone que las sessiones no usadas, tambi�n dar�an error, lo cual no tiene porque // ser cierto. En condiciones normales, los servidores tienen una session, con lo que lo anterior es cierto y el // la practica es lo mas normal. @@ -421,6 +421,14 @@ protected: */ virtual void eventPeerShutdown(const ClientSession* clientSession) throw(); + /** + Handler about a request retransmission over the session. + Default implementation traces warning event + \param clientSession ClientSession from which retransmission happened + \param request Retransmitted request message + */ + virtual void eventRequestRetransmission(const ClientSession* clientSession, Message *request) throw(); + /** Handler for diameter server (server) responses diff --git a/include/anna/diameter.comm/LocalServer.hpp b/include/anna/diameter.comm/LocalServer.hpp index f8f0079..9d733d4 100644 --- a/include/anna/diameter.comm/LocalServer.hpp +++ b/include/anna/diameter.comm/LocalServer.hpp @@ -359,6 +359,14 @@ protected: */ virtual void eventPeerShutdown(const ServerSession* serverSession) throw(); + /** + Handler about a request retransmission over the server-session. + Default implementation traces warning event + \param serverSession ServerSession from which retransmission happened + \param request Retransmitted request message + */ + virtual void eventRequestRetransmission(const ServerSession* serverSession, Message *request) throw(); + /** Handler for diameter client responses diff --git a/include/anna/diameter.comm/Message.hpp b/include/anna/diameter.comm/Message.hpp index b5cb459..9fc265a 100644 --- a/include/anna/diameter.comm/Message.hpp +++ b/include/anna/diameter.comm/Message.hpp @@ -48,7 +48,7 @@ public: /** * Define las acciones a realizar en caso de que el temporizador de la petici�n expire. */ - struct OnExpiry { enum _v { Abandon, Ignore }; }; + struct OnExpiry { enum _v { Abandon, Ignore, Retransmit }; }; /** Constructor. @@ -112,19 +112,26 @@ public: // http://diameter-protocol.blogspot.com.es/2011/05/diameter-message-structure-and-message.html /** - * In general, diameter agents CANNOT modify the end-to-end value during sending the message to the peer. - * That 'true' value stands for intermediate agents and also for retransmissions (must keep end-to-end - * during 4 minutes even upon reboots). False is used for new request created from end points (originators) - * as diameter clients. + * In general, diameter nodes will sequence the End-To-End value when sending new requests. + * A 'false' value stands for intermediate agents (must keep end-to-end during 4 minutes even upon reboots). */ - bool updateEndToEnd() const throw() { return a_updateEndToEnd; } + bool endToEndSequenced() const throw() { return a_endToEndSequenced; } /** - * In general, diameter agents CANNOT modify the end-to-end value during sending the message to the peer. - * The appropiate behaviour must be configured before sending the message. By default, the diameter::comm - * message will sequence the end-to-end increasing the initial value created during session establishment. + * By default, the diameter::comm message will sequence the end-to-end increasing the initial value created + * during session establishment. Anyway you could change this behaviour with this method. + * + * @see sequenceEndToEnd + */ + void forwardEndToEnd() throw() { a_endToEndSequenced = false; } + + /** + * By default, the diameter::comm message will sequence the end-to-end increasing the initial value created + * during session establishment. Anyway you could set again this behaviour with this method. + * + * @see forwardEndToEnd */ - void updateEndToEnd(bool update) throw() { a_updateEndToEnd = update; } + void sequenceEndToEnd() throw() { a_endToEndSequenced = true; } // Statistics @@ -147,12 +154,12 @@ public: /** Initializes class information */ void initialize() throw() { - a_retries = 0; + a_retries = 1; a_requestServerSessionKey = -1; // means unknown/unset a_requestClientSessionKey = ""; // means unknown/unset a_requestHopByHop = 0; a_requestEndToEnd = 0; - a_updateEndToEnd = true; + a_endToEndSequenced = true; } @@ -176,7 +183,7 @@ private: std::string a_requestClientSessionKey; // idem for request which was received from servers HopByHop a_requestHopByHop; // application backup for hop-by-hop in order to restore on answer receive EndToEnd a_requestEndToEnd; // application backup for end-to-end in order to restore on answer receive - bool a_updateEndToEnd; // end-to-end will be updated + bool a_endToEndSequenced; // end-to-end will be sequenced by default (true) void send(ClientSession&) const throw(anna::RuntimeException); void send(ServerSession&) const throw(anna::RuntimeException); diff --git a/include/anna/diameter.comm/Server.hpp b/include/anna/diameter.comm/Server.hpp index f7c3831..15c29de 100644 --- a/include/anna/diameter.comm/Server.hpp +++ b/include/anna/diameter.comm/Server.hpp @@ -281,6 +281,13 @@ protected: */ virtual void eventPeerShutdown(const ClientSession*) throw(); + /** + Handler about a request retransmission over the session. + + \param request Message retransmitted + */ + virtual void eventRequestRetransmission(const ClientSession*, Message *request) throw(); + /** Handler for diameter server (client-session) responses diff --git a/include/anna/diameter.comm/ServerSession.hpp b/include/anna/diameter.comm/ServerSession.hpp index 5581a4b..5b30204 100644 --- a/include/anna/diameter.comm/ServerSession.hpp +++ b/include/anna/diameter.comm/ServerSession.hpp @@ -169,6 +169,13 @@ private: */ void eventPeerShutdown() throw(); + /** + Handler about a request retransmission over the session. + + \param request Message retransmitted + */ + void eventRequestRetransmission(Message *request) throw(); + /** Handler for diameter client responses diff --git a/include/anna/diameter.comm/Session.hpp b/include/anna/diameter.comm/Session.hpp index c1b9bbb..b23f8c0 100644 --- a/include/anna/diameter.comm/Session.hpp +++ b/include/anna/diameter.comm/Session.hpp @@ -87,16 +87,16 @@ public: // Cierre de iniciativa local: - // 1. Envio DPR al PCRF y me pongo en estado 'WaitingDPA'. En este estado no habrá keep-alive DWR/DWA. + // 1. Envio DPR al PCRF y me pongo en estado 'WaitingDPA'. En este estado no habr� keep-alive DWR/DWA. // 2. No dejo pasar nuevas peticiones (BLOCK-SEND). // 3. Cierro al recibir el DPA. // 4. Si expira el DPA, tambien cierro. WaitingDPA, /**< After requesting DPR to server, send is blocked over the session: when DPA arrives (or answer expires) the session is closed */ // Cierre de iniciativa remota: - // 1. Recibo DPR del PCRF y me pongo en estado 'Disconnecting'. En este estado no habrá keep-alive DWR/DWA. + // 1. Recibo DPR del PCRF y me pongo en estado 'Disconnecting'. En este estado no habr� keep-alive DWR/DWA. // 2. No dejo pasar nuevas peticiones (BLOCK-SEND). - // 3. Espero cursar las peticiones pendientes (a más tardar, será una expiracion Tx desde la recepcion del DPR). + // 3. Espero cursar las peticiones pendientes (a m�s tardar, ser� una expiracion Tx desde la recepcion del DPR). // 4. Envio DPA y activo un temporizador de cierre local (2*Tx) como proteccion (por si el servidor no cierra). Disconnecting, /**< After receiving DPR from server, send is blocked over the session: when no pending requests, DPA is sent to the server who will close connection */ @@ -190,7 +190,7 @@ public: // // En caso de enviar una peticion se activara automaticamente un temporizador. Si este llegara a caducar // se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido -// un error de temporización. La duracion del temporizador sera la establecida por +// un error de temporizaci�n. La duracion del temporizador sera la establecida por // diameter::comm::TimerManager::setTimeout o el valor defecto. // // \param message Mensaje a enviar al servidor diameter con el que estamos conectados. @@ -200,8 +200,8 @@ public: const Response* send(const Message& message) throw(anna::RuntimeException) { return send(&message); } // Desconecta del extremo remoto -// Se notifica la terminación de cada una de las peticiones pendientes invocando al método Session::eventResponse -// \warning Después de invocar a este método habría que volver a iniciar una sesion. +// Se notifica la terminaci�n de cada una de las peticiones pendientes invocando al m�todo Session::eventResponse +// \warning Despu�s de invocar a este m�todo habr�a que volver a iniciar una sesion. virtual bool unbind(bool forceDisconnect /* se usa en timer, para el actionTimer del tipo SessionUnbind, etc. */ = false) throw(anna::RuntimeException) = 0; // returns true if done at call time (no pendings or ignore pendings, except Disconnecting state by mean DPR/DPA) @@ -328,6 +328,13 @@ protected: */ virtual void eventPeerShutdown() throw() = 0; + /** + Handler about a request retransmission over the session. + + \param request Message retransmitted + */ + virtual void eventRequestRetransmission(Message *request) throw() = 0; + /** Handler for diameter session responses @@ -365,8 +372,8 @@ protected: */ virtual void receive(const anna::comm::Message& message) throw(anna::RuntimeException) = 0; //PROTOCOL ERRORS -//The errors at the protocol level are reported in response messages that contain the “E” bit and the error code in the AVP result-Code (various errors having been produced only the first one of them is reported). Examples of these errors are: -//An unrecognized AVP with the “M” bit is received. +//The errors at the protocol level are reported in response messages that contain the �E� bit and the error code in the AVP result-Code (various errors having been produced only the first one of them is reported). Examples of these errors are: +//An unrecognized AVP with the �M� bit is received. //An AVP is received with an unrecognized value (in the AVP failed-AVP indicates the attribute that the error caused). //An mandatory AVP is not received. //Length of operation incorrect. diff --git a/include/anna/diameter/app/dcca/Message.hpp b/include/anna/diameter/app/dcca/Message.hpp index a0455d2..006e23a 100644 --- a/include/anna/diameter/app/dcca/Message.hpp +++ b/include/anna/diameter/app/dcca/Message.hpp @@ -84,7 +84,7 @@ public: const anna::diameter::codec::Avp * sid; int pos = 1; - while(sid = getAvp(helpers::dcca::AVPID__Subscription_Id, pos++)) + while((sid = getAvp(helpers::dcca::AVPID__Subscription_Id, pos++))) if(subscriptionIdType == sid->getAvp(helpers::dcca::AVPID__Subscription_Id_Type)->getEnumerated()->getValue()) return sid->getAvp(helpers::dcca::AVPID__Subscription_Id_Data)->getUTF8String(); return NULL; @@ -230,7 +230,7 @@ public: const anna::diameter::codec::Avp * uei; int pos = 1; - while(uei = getAvp(helpers::dcca::AVPID__User_Equipment_Info, pos++)) + while((uei = getAvp(helpers::dcca::AVPID__User_Equipment_Info, pos++))) if(userEquipmentInfoType == uei->getAvp(helpers::dcca::AVPID__User_Equipment_Info_Type)->getEnumerated()->getValue()) return uei->getAvp(helpers::dcca::AVPID__User_Equipment_Info_Value)->getOctetString(); return NULL; diff --git a/include/anna/diameter/codec/EngineImpl.hpp b/include/anna/diameter/codec/EngineImpl.hpp index 753d15e..bb7c6f5 100644 --- a/include/anna/diameter/codec/EngineImpl.hpp +++ b/include/anna/diameter/codec/EngineImpl.hpp @@ -238,6 +238,7 @@ public: * * @warning do not activate in case of multithreaded applications. * @param enable Activates/deactivates the stack selection from the Application-Id value within the message header. + * False by default. */ void selectStackWithApplicationId (bool enable) throw() { a_selectStackWithApplicationId = enable; } @@ -247,7 +248,7 @@ public: Gets the currently configured behaviour regarding stack selection for multistack codec engines in mono thread applications. - @return True if selection is done with the Application-Id. False if no selection is performed (user responsibility). + @return True if selection is done with the Application-Id. False (default) if no selection is performed (user responsibility). */ bool hasSelectStackWithApplicationId (void) throw() { return a_selectStackWithApplicationId; } diff --git a/include/anna/diameter/codec/Message.hpp b/include/anna/diameter/codec/Message.hpp index 449a49a..6ec6e3a 100644 --- a/include/anna/diameter/codec/Message.hpp +++ b/include/anna/diameter/codec/Message.hpp @@ -272,7 +272,7 @@ public: @param aid Application-id. */ - void setApplicationId(U32 aid) throw(); + void setApplicationId(U32 aid) throw(anna::RuntimeException); /** Sets the message hop-by-hop diff --git a/include/anna/diameter/codec/functions.hpp b/include/anna/diameter/codec/functions.hpp index df544e0..770fcc1 100644 --- a/include/anna/diameter/codec/functions.hpp +++ b/include/anna/diameter/codec/functions.hpp @@ -68,13 +68,19 @@ struct functions { static HopByHop getHopByHop(const anna::DataBlock &) throw(anna::RuntimeException); static EndToEnd getEndToEnd(const anna::DataBlock &) throw(anna::RuntimeException); + static bool requestBit(const anna::DataBlock &) throw(anna::RuntimeException); + static bool proxiableBit(const anna::DataBlock &) throw(anna::RuntimeException); + static bool errorBit(const anna::DataBlock &) throw(anna::RuntimeException); + static bool potentiallyReTransmittedMessageBit(const anna::DataBlock &) throw(anna::RuntimeException); + static bool isRequest(const CommandId & cid) throw() { return (cid.second); } - static bool isRequest(const anna::DataBlock &) throw(anna::RuntimeException); + static bool isRequest(const anna::DataBlock & db) throw(anna::RuntimeException) { return requestBit(db); } static bool isAnswer(const CommandId & cid) throw() { return (!isRequest(cid)); } static bool isAnswer(const anna::DataBlock & db) throw(anna::RuntimeException) { return (!isRequest(db)); } + /** * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context. * @@ -127,6 +133,7 @@ struct functions { // modifiers 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); }; diff --git a/source/diameter.comm/ClientSession.cpp b/source/diameter.comm/ClientSession.cpp index 7974ae7..5a7ca94 100644 --- a/source/diameter.comm/ClientSession.cpp +++ b/source/diameter.comm/ClientSession.cpp @@ -41,6 +41,10 @@ #include // rand() #include +// XXXXXXXXXX +#include + + using namespace std; @@ -302,12 +306,18 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE countSendings(cid, aid, true /* send ok */); // Trace non-application messages: LOGDEBUG( - if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || (cid == helpers::base::COMMANDID__Device_Watchdog_Request) || - (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { - anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); - try { anna::diameter::codec::Message msg; msg.decode(message->getBody()); /* decode to be traced */ } catch(anna::RuntimeException&) {;} + (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { + anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); + try { + anna::diameter::codec::Message msg(a_engine->getBaseProtocolCodecEngine()); msg.decode(message->getBody()); /* decode to be traced */ + } + catch(anna::RuntimeException &ex) { + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + } } ); @@ -442,6 +452,11 @@ void ClientSession::eventPeerShutdown() throw() { a_parent->eventPeerShutdown(this); } +void ClientSession::eventRequestRetransmission(Message *request) throw() { + // Inform father server: + a_parent->eventRequestRetransmission(this, request); +} + void ClientSession::eventResponse(const Response& response) throw(anna::RuntimeException) { // Inform father server: a_parent->eventResponse(response); @@ -482,8 +497,17 @@ throw(anna::RuntimeException) { msg += anna::diameter::functions::commandIdAsPairString(cid); anna::Logger::debug(msg, ANNA_FILE_LOCATION); - if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) || (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) - try { anna::diameter::codec::Message dmsg; dmsg.decode(db); /* decode to be traced */ } catch(anna::RuntimeException&) {;} + if( (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) || + (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) { + try { + anna::diameter::codec::Message dmsg(a_engine->getBaseProtocolCodecEngine()); dmsg.decode(db); /* decode to be traced */ + } + catch(anna::RuntimeException &ex) { + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + } + } ); // Main counters: OamModule &oamModule = OamModule::instantiate(); diff --git a/source/diameter.comm/Engine.cpp b/source/diameter.comm/Engine.cpp index 53de6ac..4028991 100644 --- a/source/diameter.comm/Engine.cpp +++ b/source/diameter.comm/Engine.cpp @@ -37,8 +37,9 @@ using namespace std; using namespace anna::diameter::comm; -Engine::Engine(const char *className) : +Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) : anna::app::Component(className), + a_baseProtocolCodecEngine(baseProtocolCodecEngine), a_autoBind(true), a_availableForEntities(false), a_availableForLocalServers(false), @@ -939,10 +940,10 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() // [Error-Message].................................(281,0) // *[Failed-AVP]....................................(279,0) try { - anna::diameter::codec::Message diameterDPA; - anna::diameter::codec::Avp avpRC; - anna::diameter::codec::Avp avpOH; - anna::diameter::codec::Avp avpOR; + anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine()); // Message header diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer); diameterDPA.setVersion(1); @@ -967,7 +968,10 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() // Encode dpa = diameterDPA.code(); } catch(anna::RuntimeException &ex) { - ex.trace(); + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } } @@ -993,10 +997,10 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() // [Firmware-Revision].............................(267,0) // *[AVP]...........................................(0,0) try { - anna::diameter::codec::Message diameterCEA; - anna::diameter::codec::Avp avpRC; - anna::diameter::codec::Avp avpOH; - anna::diameter::codec::Avp avpOR; + anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine()); // Message header diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer); diameterCEA.setVersion(1); @@ -1030,7 +1034,10 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw() // Encode cea = diameterCEA.code(); } catch(anna::RuntimeException &ex) { - ex.trace(); + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } } @@ -1046,10 +1053,10 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() // *[Failed-AVP]....................................(279,0) // [Origin-State-Id]...............................(278,0) try { - anna::diameter::codec::Message diameterDWA; - anna::diameter::codec::Avp avpRC; - anna::diameter::codec::Avp avpOH; - anna::diameter::codec::Avp avpOR; + anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine()); + anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine()); // Message header diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer); diameterDWA.setVersion(1); @@ -1074,7 +1081,10 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw() // Encode dwa = diameterDWA.code(); } catch(anna::RuntimeException &ex) { - ex.trace(); + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)"; + anna::Logger::error(msg, ANNA_FILE_LOCATION); + //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION); } } diff --git a/source/diameter.comm/Entity.cpp b/source/diameter.comm/Entity.cpp index 67916c7..25a879c 100644 --- a/source/diameter.comm/Entity.cpp +++ b/source/diameter.comm/Entity.cpp @@ -320,6 +320,14 @@ void Entity::eventPeerShutdown(const ClientSession* clientSession) throw() { ); } +void Entity::eventRequestRetransmission(const ClientSession* clientSession, Message *request) throw() { + LOGWARNING( + std::string msg(clientSession->asString()); + msg += " | eventRequestRetransmission"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); +} + std::string Entity::asString() const throw() { std::string result("diameter::comm::Entity { "); std::string realm = a_engine->getRealm(); diff --git a/source/diameter.comm/LocalServer.cpp b/source/diameter.comm/LocalServer.cpp index 293cc83..985e4a8 100644 --- a/source/diameter.comm/LocalServer.cpp +++ b/source/diameter.comm/LocalServer.cpp @@ -277,7 +277,7 @@ ServerSession *LocalServer::createServerSession(const anna::comm::ClientSocket & result->setClientSocket((anna::comm::ClientSocket*)(&clientSocket)); result->a_parent = this; result->a_socketId = key; // de momento... - result->initializeSequences(); // después de asignar el LocalServer y el socketId (*) + result->initializeSequences(); // despu�s de asignar el LocalServer y el socketId (*) // (*) Las secuencias se basan en la semilla: srand(::time(NULL) + anna::functions::exclusiveHash(anna::functions::asString("%s:%d|%d", getAddress().c_str(), getPort(), a_socketId))); result->a_engine = a_engine; a_serverSessions.insert(serverSession_value_type(key, result)); @@ -329,7 +329,7 @@ throw(anna::RuntimeException) { // #9 0x000000000048d288 in anna::diameter::comm::ServerSession::finalize (this=0xc37a00) at comm.db/diameter.comm.ServerSession.cc:510 // #10 0x0000000000494e4f in anna::diameter::comm::ServerSessionReceiver::eventBreakLocalConnection (this=0xc119c0, clientSocket=@0xb0ea00) // SOLUCION: no borrar aqui, marcar como "deprecated". Este estado no se necesita realmente puesto que nadie volvera a usar este recurso. - // Pero simplemente se podria usar para purgar mediante temporizacion (entonces sí se haría el erase) + // Pero simplemente se podria usar para purgar mediante temporizacion (entonces s� se har�a el erase) serverSession->a_deprecated = true; // WE WILL ERASE AT createServerSession a_deliveryIterator = serverSession_begin(); @@ -532,6 +532,14 @@ void LocalServer::eventPeerShutdown(const ServerSession* serverSession) throw() ); } +void LocalServer::eventRequestRetransmission(const ServerSession* serverSession, Message *request) throw() { + LOGWARNING( + std::string msg(serverSession->asString()); + msg += " | eventRequestRetransmission"; + anna::Logger::warning(msg, ANNA_FILE_LOCATION); + ); +} + std::string LocalServer::asString() const throw() { std::string result("diameter::comm::LocalServer { "); result += "Description: "; diff --git a/source/diameter.comm/Message.cpp b/source/diameter.comm/Message.cpp index 88cbe91..a07de1a 100644 --- a/source/diameter.comm/Message.cpp +++ b/source/diameter.comm/Message.cpp @@ -27,7 +27,7 @@ using namespace anna::diameter::comm; const char* Message::asText(const OnExpiry::_v rc) throw() { - static const char* text [] = { "Abandon", "Ignore" }; + static const char* text [] = { "Abandon", "Ignore", "Retransmit" }; return text [rc]; } @@ -61,6 +61,7 @@ throw() { //// a_onExpiry = OnExpiry::Ignore; //} + bool Message::fixRequestSequence(HopByHop hbh, EndToEnd ete) throw() { setRequestHopByHop(getHopByHop()); // original request hop-by-hop (backup) setRequestEndToEnd(getEndToEnd()); // original request end-to-end (backup) @@ -71,7 +72,7 @@ bool Message::fixRequestSequence(HopByHop hbh, EndToEnd ete) throw() { result = true; } - if(a_updateEndToEnd) { + if(a_endToEndSequenced) { if(ete != getRequestEndToEnd()) { codec::functions::setEndToEnd((anna::DataBlock&)getBody(), ete); result = true; @@ -85,7 +86,7 @@ bool Message::fixRequestSequence(HopByHop hbh, EndToEnd ete) throw() { msg += " (original) -> "; msg += anna::functions::asString(hbh); msg += " (session)"; - msg += a_updateEndToEnd ? " | End to end: " : " | End to end [end-to-end unchanged]: "; + msg += a_endToEndSequenced ? " | End to end: " : " | End to end [end-to-end unchanged]: "; msg += anna::functions::asString(getRequestEndToEnd()); msg += " (original) -> "; msg += anna::functions::asString(ete); diff --git a/source/diameter.comm/Server.cpp b/source/diameter.comm/Server.cpp index 4b96c5e..a751d48 100644 --- a/source/diameter.comm/Server.cpp +++ b/source/diameter.comm/Server.cpp @@ -315,27 +315,32 @@ anna::xml::Node* Server::asXML(anna::xml::Node* parent) const throw() { void Server::eventPeerShutdown(const ClientSession *clientSession) throw() { - // Inform father server: + // Inform father entity: a_parent->eventPeerShutdown(clientSession); } +void Server::eventRequestRetransmission(const ClientSession* clientSession, Message *request) throw() { + // Inform father entity: + a_parent->eventRequestRetransmission(clientSession, request); +} + void Server::eventResponse(const Response& response) throw(anna::RuntimeException) { - // Inform father server: + // Inform father entity: a_parent->eventResponse(response); } void Server::eventRequest(ClientSession *clientSession, const anna::DataBlock & request) throw(anna::RuntimeException) { - // Inform father server: + // Inform father entity: a_parent->eventRequest(clientSession, request); } void Server::eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock & response) throw(anna::RuntimeException) { - // Inform father server: + // Inform father entity: a_parent->eventUnknownResponse(clientSession, response); } void Server::eventDPA(ClientSession *clientSession, const anna::DataBlock & response) throw(anna::RuntimeException) { - // Inform father server: + // Inform father entity: a_parent->eventDPA(clientSession, response); } diff --git a/source/diameter.comm/ServerSession.cpp b/source/diameter.comm/ServerSession.cpp index 3c493d0..a615c78 100644 --- a/source/diameter.comm/ServerSession.cpp +++ b/source/diameter.comm/ServerSession.cpp @@ -215,11 +215,18 @@ const Response* ServerSession::send(const Message* message) throw(anna::RuntimeE // Trace non-application messages: LOGDEBUG( - if((cid == helpers::base::COMMANDID__Device_Watchdog_Request) || - (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { - anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); - try { anna::diameter::codec::Message msg; msg.decode(message->getBody()); /* decode to be traced */ } catch(anna::RuntimeException&) {;} - } + if( (cid == helpers::base::COMMANDID__Device_Watchdog_Request) || + (cid == helpers::base::COMMANDID__Disconnect_Peer_Request)) { + anna::Logger::debug("Sent DataBlock to XML representation:", ANNA_FILE_LOCATION); + try { + anna::diameter::codec::Message msg(a_engine->getBaseProtocolCodecEngine()); msg.decode(message->getBody()); /* decode to be traced */ + } + catch(anna::RuntimeException &ex) { + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + } + } ); // Restore sequences: @@ -306,6 +313,11 @@ void ServerSession::eventPeerShutdown() throw() { a_parent->eventPeerShutdown(this); } +void ServerSession::eventRequestRetransmission(Message *request) throw() { + // Inform father server: + a_parent->eventRequestRetransmission(this, request); +} + void ServerSession::eventResponse(const Response& response) throw(anna::RuntimeException) { // Inform father server: a_parent->eventResponse(response); @@ -344,9 +356,18 @@ throw(anna::RuntimeException) { msg += anna::diameter::functions::commandIdAsPairString(cid); anna::Logger::debug(msg, ANNA_FILE_LOCATION); - if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) - try { anna::diameter::codec::Message dmsg; dmsg.decode(db); /* decode to be traced */ } catch(anna::RuntimeException&) {;} -); + if( (cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) || + (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) { + try { + anna::diameter::codec::Message dmsg(a_engine->getBaseProtocolCodecEngine()); dmsg.decode(db); /* decode to be traced */ + } + catch(anna::RuntimeException &ex) { + std::string msg = ex.getText(); + msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing"; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + } + } + ); // Main counters: OamModule &oamModule = OamModule::instantiate(); oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived); @@ -571,7 +592,7 @@ throw(anna::RuntimeException) { if(cea.isEmpty()) { LOGDEBUG(anna::Logger::debug("Empty CEA message. Remote client never will bound this connection at application level", ANNA_FILE_LOCATION)); - LOGWARNING(anna::Logger::warning("Discarding received CER without sending CEA (consider to send CEA with Result-Code DIAMETER_UNKNOWN_PEER)", ANNA_FILE_LOCATION)); + LOGWARNING(anna::Logger::warning("Discarding received CER: cannot send empty CEA (consider to send CEA with Result-Code DIAMETER_UNKNOWN_PEER)", ANNA_FILE_LOCATION)); return; } diff --git a/source/diameter.comm/Session.cpp b/source/diameter.comm/Session.cpp index fada503..051cbce 100644 --- a/source/diameter.comm/Session.cpp +++ b/source/diameter.comm/Session.cpp @@ -238,6 +238,7 @@ void Session::expireResponse(diameter::comm::Response* response) throw() { LOGMETHOD(anna::TraceMethod traceMethod("anna::diameter::comm::Session", "expireResponse", ANNA_FILE_LOCATION)); bool doUnbind = false; + bool doRetransmission = false; // Quitar el OnExpiry: no tiene sentido habiendo keep-alive (DWR) if(response->getClassCode() != ClassCode::Bind) { @@ -245,9 +246,13 @@ throw() { a_onDisconnect = OnDisconnect::IgnorePendings; // Abandon is not graceful doUnbind = true; } + else if(response->getRequest()->getOnExpiry() == Message::OnExpiry::Retransmit) { + doRetransmission = true; + } } else doUnbind = true; // (*) + try { response->setMessage(NULL); eventResponse(*response); @@ -263,6 +268,25 @@ throw() { setState(State::Bound); } + if(doRetransmission) { + diameter::comm::Message *request = const_cast(response->getRequest()); + eventRequestRetransmission(request); + + int retries = request->getRetries(); + if (retries > 0) { + retries--; + request->setRetries(retries); + LOGDEBUG + ( + //std::string msg(asString()); + std::string msg = anna::functions::asString("Retransmission initiated for request with HopByHop: %u; remaining %d retries", response->getHopByHop(), retries); + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + diameter::codec::functions::setPotentiallyReTransmittedMessageBit(*request); + send(request); + } + } + response_erase(response); if(doUnbind) unbind(); @@ -275,7 +299,7 @@ void Session::finalize() throw() { cancelActionTimer(); // Action timer eventPeerShutdown(); /////////////////////////////////////////////////////////////////////// -// Notificar la finalización de las respuestas pendientes de recibir // +// Notificar la finalizaci�n de las respuestas pendientes de recibir // /////////////////////////////////////////////////////////////////////// // RFC 3588 - 5.5.4. Failover and Failback Procedures // diff --git a/source/diameter/codec/Message.cpp b/source/diameter/codec/Message.cpp index 1d41374..b9c4fbd 100644 --- a/source/diameter/codec/Message.cpp +++ b/source/diameter/codec/Message.cpp @@ -205,7 +205,7 @@ void Message::setId(const char *name) throw(anna::RuntimeException) { //------------------------------------------------------------------------------ //-------------------------------------------------- Message::setApplicationId() //------------------------------------------------------------------------------ -void Message::setApplicationId(U32 aid) throw() { +void Message::setApplicationId(U32 aid) throw(anna::RuntimeException) { a_applicationId = aid; // Default behaviour: diff --git a/source/diameter/codec/functions.cpp b/source/diameter/codec/functions.cpp index 3e8ce1f..a58372d 100644 --- a/source/diameter/codec/functions.cpp +++ b/source/diameter/codec/functions.cpp @@ -80,14 +80,34 @@ anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) th return (anna::diameter::CommandId(code, (flags & Message::RBitMask) != 0x00)); } - -bool functions::isRequest(const anna::DataBlock & db) throw(anna::RuntimeException) { +bool 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) { + 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) { + 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) { + 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) { if(db.getSize() < Message::HeaderLength) throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); @@ -279,4 +299,15 @@ 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) { + if(db.getSize() < Message::HeaderLength) { + throw anna::RuntimeException("Not enough bytes to cover command header length", ANNA_FILE_LOCATION); + } + + static char flags[1]; + flags[0] = *(db.getData() + 4); + if(activate) flags[0] |= Message::TBitMask; else flags[0] &= (~Message::TBitMask); + memcpy((char *)(db.getData() + 4), flags, 1); +} +