--- /dev/null
+#!/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
+
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
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;
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);
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"));
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(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(
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);
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
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);
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);
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"));
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:
*/
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
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).
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
private:
+ // Internal use: tracing and readCEA/DPA/DWA
+ codec::Engine *a_baseProtocolCodecEngine;
+
std::string a_realm;
std::string a_host;
bool a_autoBind;
// */
// 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.
*/
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
*/
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
/**
* 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.
// 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
/** 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;
}
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);
*/
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
*/
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
// 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 */
//
// 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.
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 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
*/
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.
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;
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;
*
* @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; }
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; }
@param aid Application-id.
*/
- void setApplicationId(U32 aid) throw();
+ void setApplicationId(U32 aid) throw(anna::RuntimeException);
/**
Sets the message hop-by-hop
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.
*
// 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);
};
#include <stdlib.h> // rand()
#include <time.h>
+// XXXXXXXXXX
+#include <iostream>
+
+
using namespace std;
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);
+ }
}
);
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);
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();
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),
// [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);
// 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);
}
}
// [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);
// 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);
}
}
// *[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);
// Encode
dwa = diameterDWA.code();
} catch(anna::RuntimeException &ex) {
- ex.trace();
+ std::string msg = ex.getText();
+ msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)";
+ anna::Logger::error(msg, ANNA_FILE_LOCATION);
+ //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
}
}
);
}
+void 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();
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));
// #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();
);
}
+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: ";
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];
}
//// 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)
result = true;
}
- if(a_updateEndToEnd) {
+ if(a_endToEndSequenced) {
if(ete != getRequestEndToEnd()) {
codec::functions::setEndToEnd((anna::DataBlock&)getBody(), ete);
result = true;
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);
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);
}
// 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:
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);
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);
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;
}
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) {
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);
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();
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
//
//------------------------------------------------------------------------------
//-------------------------------------------------- Message::setApplicationId()
//------------------------------------------------------------------------------
-void Message::setApplicationId(U32 aid) throw() {
+void Message::setApplicationId(U32 aid) throw(anna::RuntimeException) {
a_applicationId = aid;
// Default behaviour:
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);
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);
+}
+