Base protocol codec for comm::Engine. Supported retransmissions
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Mon, 13 Jul 2015 02:34:30 +0000 (04:34 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Mon, 13 Jul 2015 02:34:30 +0000 (04:34 +0200)
28 files changed:
example/diameter/launcher/DEPLOY_clientAndServer.sh [new file with mode: 0755]
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/Launcher.hpp
example/diameter/launcher/MyDiameterEngine.hpp
example/diameter/launcher/MyDiameterEntity.cpp
example/diameter/launcher/MyLocalServer.cpp
include/anna/diameter.comm/ClientSession.hpp
include/anna/diameter.comm/Engine.hpp
include/anna/diameter.comm/Entity.hpp
include/anna/diameter.comm/LocalServer.hpp
include/anna/diameter.comm/Message.hpp
include/anna/diameter.comm/Server.hpp
include/anna/diameter.comm/ServerSession.hpp
include/anna/diameter.comm/Session.hpp
include/anna/diameter/app/dcca/Message.hpp
include/anna/diameter/codec/EngineImpl.hpp
include/anna/diameter/codec/Message.hpp
include/anna/diameter/codec/functions.hpp
source/diameter.comm/ClientSession.cpp
source/diameter.comm/Engine.cpp
source/diameter.comm/Entity.cpp
source/diameter.comm/LocalServer.cpp
source/diameter.comm/Message.cpp
source/diameter.comm/Server.cpp
source/diameter.comm/ServerSession.cpp
source/diameter.comm/Session.cpp
source/diameter/codec/Message.cpp
source/diameter/codec/functions.cpp

diff --git a/example/diameter/launcher/DEPLOY_clientAndServer.sh b/example/diameter/launcher/DEPLOY_clientAndServer.sh
new file mode 100755 (executable)
index 0000000..c8bf3e6
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#############
+# VARIABLES #
+#############
+DEPLOY_SCR=`dirname $0`/DEPLOY.sh
+
+#############
+# FUNCTIONS #
+#############
+usage() {
+  echo
+  echo "Usage: $0 <empty directory>"
+  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
+
index 710ebfe..05422f4 100644 (file)
@@ -58,7 +58,14 @@ void Launcher::releaseCommMessage(anna::diameter::comm::Message *msg) throw() {
   a_commMessages.release(msg);
 }
 
   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
   //   <CER> ::= < Diameter Header: 257, REQ >
   //             { Origin-Host } 264 diameterIdentity
   // Build CER
   //   <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, ",");
 
   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;
     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
 
 
   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);
   // 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) {
     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"));
       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();
 
     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);
 
     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);
     }
 
       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(
     }
   } catch(anna::RuntimeException &ex) {
     LOGDEBUG(
index b1bf52a..d7e4bba 100644 (file)
@@ -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); }
   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);
   MyDiameterEntity *getEntity() throw() { return a_entity; }
   MyLocalServer* getDiameterLocalServer() throw() { return a_diameterLocalServer; }
   void eventOperation(const std::string &, std::string &) throw(anna::RuntimeException);
index 4606edc..13aae6c 100644 (file)
@@ -20,7 +20,7 @@
 class MyDiameterEngine : public anna::diameter::comm::Engine {
 public:
 
 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
 
 // Default implementation is enough
 //   void readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw() {;} // DPA is not replied
index 702ec56..ae4a3db 100644 (file)
@@ -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();
   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);
       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();
     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);
         msg->setBody(*message);
         bool success = localServer->send(msg, request->getRequestServerSessionKey());
         my_app.releaseCommMessage(msg);
index 91e95f5..599917f 100644 (file)
@@ -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();
   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"));
     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();
 
       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:
         msg->setBody(*message);
 
         // Metodo 1:
index 93490cb..0b4b437 100644 (file)
@@ -232,6 +232,13 @@ private:
   */
   void eventPeerShutdown() throw();
 
   */
   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
 
   /**
      Handler for diameter server (client-session) responses
 
index d1c276e..609c459 100644 (file)
@@ -94,6 +94,27 @@ class LocalServer;
 class Engine : public anna::app::Component {
 public:
 
 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).
 
   /**
      Diameter application node realm name (used to be the site domain name).
 
@@ -613,9 +634,18 @@ public:
 protected:
   /**
      Constructor.
 protected:
   /**
      Constructor.
+
      @param className Component class name
      @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
 
 
   // INTERNAL CREATORS AND CLOSE METHODS
@@ -668,6 +698,9 @@ protected:
 
 private:
 
 
 private:
 
+  // Internal use: tracing and readCEA/DPA/DWA
+  codec::Engine *a_baseProtocolCodecEngine;
+
   std::string a_realm;
   std::string a_host;
   bool a_autoBind;
   std::string a_realm;
   std::string a_host;
   bool a_autoBind;
index 2335d82..d0da8c5 100644 (file)
@@ -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
 //   */
 
 // 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.
 
 //      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();
 
   */
   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
 
   /**
      Handler for diameter server (server) responses
 
index f8f0079..9d733d4 100644 (file)
@@ -359,6 +359,14 @@ protected:
   */
   virtual void eventPeerShutdown(const ServerSession* serverSession) throw();
 
   */
   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
 
   /**
      Handler for diameter client responses
 
index b5cb459..9fc265a 100644 (file)
@@ -48,7 +48,7 @@ public:
   /**
    * Define las acciones a realizar en caso de que el temporizador de la petici�n expire.
    */
   /**
    * 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.
 
   /**
      Constructor.
@@ -112,19 +112,26 @@ public:
   // http://diameter-protocol.blogspot.com.es/2011/05/diameter-message-structure-and-message.html
 
   /**
   // 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
 
 
   // Statistics
@@ -147,12 +154,12 @@ public:
 
   /** Initializes class information */
   void initialize() throw() {
 
   /** 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_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
   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);
 
   void send(ClientSession&) const throw(anna::RuntimeException);
   void send(ServerSession&) const throw(anna::RuntimeException);
index f7c3831..15c29de 100644 (file)
@@ -281,6 +281,13 @@ protected:
   */
   virtual void eventPeerShutdown(const ClientSession*) throw();
 
   */
   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
 
   /**
      Handler for diameter server (client-session) responses
 
index 5581a4b..5b30204 100644 (file)
@@ -169,6 +169,13 @@ private:
   */
   void eventPeerShutdown() throw();
 
   */
   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
 
   /**
      Handler for diameter client responses
 
index c1b9bbb..b23f8c0 100644 (file)
@@ -87,16 +87,16 @@ public:
 
 
       // Cierre de iniciativa local:
 
 
       // 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:
       // 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).
       // 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 */
 
       // 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
 //
 // 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 temporizacin. 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.
 // 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
   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)
 
   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;
 
   */
   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
 
   /**
      Handler for diameter session responses
 
@@ -365,8 +372,8 @@ protected:
   */
   virtual void receive(const anna::comm::Message& message) throw(anna::RuntimeException) = 0;
 //PROTOCOL ERRORS
   */
   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 \93E\94 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 \93M\94 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.
 //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.
index a0455d2..006e23a 100644 (file)
@@ -84,7 +84,7 @@ public:
       const anna::diameter::codec::Avp * sid;
       int pos = 1;
 
       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;
       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;
 
       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;
       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;
index 753d15e..bb7c6f5 100644 (file)
@@ -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.
   *
   * @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; }
 
   */
   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.
 
     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; }
 
   */
   bool hasSelectStackWithApplicationId (void) throw() { return a_selectStackWithApplicationId; }
 
index 449a49a..6ec6e3a 100644 (file)
@@ -272,7 +272,7 @@ public:
 
      @param aid Application-id.
   */
 
      @param aid Application-id.
   */
-  void setApplicationId(U32 aid) throw();
+  void setApplicationId(U32 aid) throw(anna::RuntimeException);
 
   /**
      Sets the message hop-by-hop
 
   /**
      Sets the message hop-by-hop
index df544e0..770fcc1 100644 (file)
@@ -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 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 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)); }
 
 
 
   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.
   *
   /**
   * 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);
   // 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);
 };
 
 
 };
 
 
index 7974ae7..5a7ca94 100644 (file)
 #include <stdlib.h> // rand()
 #include <time.h>
 
 #include <stdlib.h> // rand()
 #include <time.h>
 
+// XXXXXXXXXX
+#include <iostream>
+
+
 
 
 using namespace std;
 
 
 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(
     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) ||
       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);
 }
 
   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);
 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);
 
     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();
 );
   // Main counters:
   OamModule &oamModule = OamModule::instantiate();
index 53de6ac..4028991 100644 (file)
@@ -37,8 +37,9 @@ using namespace std;
 using namespace anna::diameter::comm;
 
 
 using namespace anna::diameter::comm;
 
 
-Engine::Engine(const char *className) :
+Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
   anna::app::Component(className),
   anna::app::Component(className),
+  a_baseProtocolCodecEngine(baseProtocolCodecEngine),
   a_autoBind(true),
   a_availableForEntities(false),
   a_availableForLocalServers(false),
   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 {
   //        [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);
     // 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) {
     // 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 {
   //        [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);
     // 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) {
     // 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 {
   //       *[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);
     // 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) {
     // 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);
   }
 }
 
   }
 }
 
index 67916c7..25a879c 100644 (file)
@@ -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();
 std::string Entity::asString() const throw() {
   std::string result("diameter::comm::Entity { ");
   std::string realm = a_engine->getRealm();
index 293cc83..985e4a8 100644 (file)
@@ -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->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(); // despus 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));
   // (*) 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.
   //   #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();
   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: ";
 std::string LocalServer::asString() const throw() {
   std::string result("diameter::comm::LocalServer { ");
   result += "Description: ";
index 88cbe91..a07de1a 100644 (file)
@@ -27,7 +27,7 @@ using namespace anna::diameter::comm;
 
 const char* Message::asText(const OnExpiry::_v rc)
 throw() {
 
 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];
 }
 
   return text [rc];
 }
 
@@ -61,6 +61,7 @@ throw() {
 ////   a_onExpiry = OnExpiry::Ignore;
 //}
 
 ////   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)
 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;
   }
 
     result = true;
   }
 
-  if(a_updateEndToEnd) {
+  if(a_endToEndSequenced) {
     if(ete != getRequestEndToEnd()) {
       codec::functions::setEndToEnd((anna::DataBlock&)getBody(), ete);
       result = true;
     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 += " (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);
     msg += anna::functions::asString(getRequestEndToEnd());
     msg += " (original) -> ";
     msg += anna::functions::asString(ete);
index 4b96c5e..a751d48 100644 (file)
@@ -315,27 +315,32 @@ anna::xml::Node* Server::asXML(anna::xml::Node* parent) const throw() {
 
 
 void Server::eventPeerShutdown(const ClientSession *clientSession) throw() {
 
 
 void Server::eventPeerShutdown(const ClientSession *clientSession) throw() {
-  // Inform father server:
+  // Inform father entity:
   a_parent->eventPeerShutdown(clientSession);
 }
 
   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) {
 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) {
   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) {
   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) {
   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);
 }
 
   a_parent->eventDPA(clientSession, response);
 }
 
index 3c493d0..a615c78 100644 (file)
@@ -215,11 +215,18 @@ const Response* ServerSession::send(const Message* message) throw(anna::RuntimeE
     // Trace non-application messages:
     LOGDEBUG(
 
     // 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:
     );
 
     // Restore sequences:
@@ -306,6 +313,11 @@ void ServerSession::eventPeerShutdown() throw() {
   a_parent->eventPeerShutdown(this);
 }
 
   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);
 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);
 
     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);
   // 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));
 
   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;
   }
 
     return;
   }
 
index fada503..051cbce 100644 (file)
@@ -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;
 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) {
 
   // 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;
     }
       a_onDisconnect = OnDisconnect::IgnorePendings; // Abandon is not graceful
       doUnbind = true;
     }
+    else if(response->getRequest()->getOnExpiry() == Message::OnExpiry::Retransmit) {
+      doRetransmission = true;
+    }
   } else
     doUnbind = true; // (*)
 
   } else
     doUnbind = true; // (*)
 
+
   try {
     response->setMessage(NULL);
     eventResponse(*response);
   try {
     response->setMessage(NULL);
     eventResponse(*response);
@@ -263,6 +268,25 @@ throw() {
     setState(State::Bound);
   }
 
     setState(State::Bound);
   }
 
+  if(doRetransmission) {
+    diameter::comm::Message *request = const_cast<Message*>(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();
   response_erase(response);
 
   if(doUnbind) unbind();
@@ -275,7 +299,7 @@ void Session::finalize() throw() {
   cancelActionTimer(); // Action timer
   eventPeerShutdown();
 ///////////////////////////////////////////////////////////////////////
   cancelActionTimer(); // Action timer
   eventPeerShutdown();
 ///////////////////////////////////////////////////////////////////////
-// Notificar la finalización de las respuestas pendientes de recibir //
+// Notificar la finalizacin de las respuestas pendientes de recibir //
 ///////////////////////////////////////////////////////////////////////
 // RFC 3588 - 5.5.4.  Failover and Failback Procedures
 //
 ///////////////////////////////////////////////////////////////////////
 // RFC 3588 - 5.5.4.  Failover and Failback Procedures
 //
index 1d41374..b9c4fbd 100644 (file)
@@ -205,7 +205,7 @@ void Message::setId(const char *name) throw(anna::RuntimeException) {
 //------------------------------------------------------------------------------
 //-------------------------------------------------- Message::setApplicationId()
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 //-------------------------------------------------- Message::setApplicationId()
 //------------------------------------------------------------------------------
-void Message::setApplicationId(U32 aid) throw() {
+void Message::setApplicationId(U32 aid) throw(anna::RuntimeException) {
   a_applicationId = aid;
 
   // Default behaviour:
   a_applicationId = aid;
 
   // Default behaviour:
index 3e8ce1f..a58372d 100644 (file)
@@ -80,14 +80,34 @@ anna::diameter::CommandId functions::getCommandId(const anna::DataBlock & db) th
   return (anna::diameter::CommandId(code, (flags & Message::RBitMask) != 0x00));
 }
 
   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);
 }
 
   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);
 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);
 }
 
   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);
+}
+