Node class, command line redesign. New xml template for process configuration.
[anna.git] / source / diameter.comm / Engine.cpp
index b6f0b55..538001a 100644 (file)
@@ -1,37 +1,9 @@
-// ANNA - Anna is Not Nothingness Anymore
-//
-// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-//
-// http://redmine.teslayout.com/projects/anna-suite
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     *  Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: eduardo.ramos.testillano@gmail.com
-//          cisco.tierra@gmail.com
+// ANNA - Anna is Not Nothingness Anymore                                                         //
+//                                                                                                //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
+//                                                                                                //
+// See project site at http://redmine.teslayout.com/projects/anna-suite                           //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
 
 
 #include <anna/diameter.comm/Engine.hpp>
@@ -65,8 +37,9 @@ using namespace std;
 using namespace anna::diameter::comm;
 
 
-Engine::Engine() :
-  anna::app::Component(getClassName()),
+Engine::Engine(const char *className, codec::Engine *baseProtocolCodecEngine) :
+  anna::app::Component(className),
+  a_baseProtocolCodecEngine(baseProtocolCodecEngine),
   a_autoBind(true),
   a_availableForEntities(false),
   a_availableForLocalServers(false),
@@ -76,8 +49,7 @@ Engine::Engine() :
 //      a_dwa(true),
   a_watchdogPeriod(ClientSession::DefaultWatchdogPeriod),
   a_maxConnectionDelay(anna::comm::ClientSocket::DefaultMaxConnectionDelay /* 200 ms*/),
-  a_numberOfClientSessionsPerServer(1),
-  a_freezeEndToEndOnSending(false) {
+  a_numberOfClientSessionsPerServer(1) {
   anna::diameter::sccs::activate();
   a_realm = anna::functions::getDomainname();
   a_host = anna::functions::getHostname();
@@ -89,7 +61,7 @@ ClientSession* Engine::allocateClientSession() throw() { return a_clientSessions
 void Engine::releaseClientSession(ClientSession *clientSession) throw() { a_clientSessionsRecycler.release(clientSession); }
 
 
-void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
+void Engine::setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) throw(anna::RuntimeException) {
   if(codec::functions::getCommandId(cer) != helpers::base::COMMANDID__Capabilities_Exchange_Request) {
     throw anna::RuntimeException("The message provided as 'CER' is not a Capabilities-Exchange-Request", ANNA_FILE_LOCATION);
   }
@@ -102,18 +74,86 @@ void Engine::setCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & d
   a_dwr = dwr;
 }
 
-//void Engine::setCEAandDWA(const anna::DataBlock & cea, const anna::DataBlock & dwa) throw(anna::RuntimeException) {
-//   if (codec::functions::getCommandId(cea) != helpers::base::COMMANDID__Capabilities_Exchange_Answer) {
-//      throw anna::RuntimeException("The message provided as 'CEA' is not a Capabilities-Exchange-Answer", ANNA_FILE_LOCATION);
-//   }
-//
-//   if (codec::functions::getCommandId(dwa) != helpers::base::COMMANDID__Device_Watchdog_Answer) {
-//      throw anna::RuntimeException("The message provided as 'DWA' is not a Device-Watchdog-Answer", ANNA_FILE_LOCATION);
-//   }
-//
-//   a_cea = cea;
-//   a_dwa = dwa;
-//}
+void Engine::setClientCERandDWR(const std::string & cer, const std::string & dwr) throw(anna::RuntimeException) {
+
+  // Check for base protocol codec engine:
+  if (!getBaseProtocolCodecEngine())
+    throw anna::RuntimeException("Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow base protocol messages encoding, or use setClientCERandDWR(const anna::DataBlock & cer, const anna::DataBlock & dwr) which expect externally encoded messages", ANNA_FILE_LOCATION);
+
+  // Build CER
+  //   <CER> ::= < Diameter Header: 257, REQ >
+  //             { Origin-Host } 264 diameterIdentity
+  //             { Origin-Realm } 296 idem
+  //          1* { Host-IP-Address } 257, address
+  //             { Vendor-Id } 266 Unsigned32
+  //             { Product-Name } 269 UTF8String
+  //             [Origin-State-Id] 278 Unsigned32
+  //           * [ Supported-Vendor-Id ]  265 Unsigned32
+  //           * [ Auth-Application-Id ] 258 Unsigned32
+  //           * [Acct-Application-Id]  259 Unsigned32
+  anna::diameter::codec::Message diameterCER(getBaseProtocolCodecEngine());
+  int applicationId = 0 /*anna::diameter::helpers::APPID__3GPP_Rx*/; // Unsigned32
+  std::string OH = getHost();
+  std::string OR = getRealm();
+  std::string hostIP = anna::functions::getHostnameIP(); // Address
+  int vendorId = anna::diameter::helpers::VENDORID__tgpp; // Unsigned32
+  std::string productName = "ANNA Diameter Client"; // UTF8String
+  bool encodeDefault = false;
+
+  if (cer != "") {
+    try {
+      diameterCER.loadXML(cer);
+    } catch(anna::RuntimeException &ex) {
+      //ex.trace();
+      encodeDefault = true;
+      LOGWARNING(anna::Logger::warning("CER file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
+    }
+  }
+  else {
+    encodeDefault = true;
+  }
+
+  if(encodeDefault) {
+    diameterCER.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Request);
+    diameterCER.setApplicationId(applicationId);
+    diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
+    diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
+    diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Host_IP_Address)->getAddress()->fromPrintableString(hostIP.c_str()); // supported by Address class, anyway is better to provide "1|<ip address>"
+    diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Vendor_Id)->getUnsigned32()->setValue(vendorId);
+    diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Product_Name)->getUTF8String()->setValue(productName);
+    diameterCER.addAvp(anna::diameter::helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->setValue(applicationId);
+  }
+
+  // Build DWR
+  //   <DWR>  ::= < Diameter Header: 280, REQ >
+  //              { Origin-Host }
+  //              { Origin-Realm }
+  anna::diameter::codec::Message diameterDWR(getBaseProtocolCodecEngine());
+  encodeDefault = false;
+
+  if (dwr != "") {
+    try {
+      diameterDWR.loadXML(dwr);
+    } catch(anna::RuntimeException &ex) {
+      //ex.trace();
+      encodeDefault = true;
+      LOGWARNING(anna::Logger::warning("DWR file not found or unable to parse. Encoding harcoded default version ...", ANNA_FILE_LOCATION));
+    }
+  }
+  else {
+    encodeDefault = true;
+  }
+
+  if(encodeDefault) {
+    diameterDWR.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Request);
+    diameterDWR.setApplicationId(applicationId);
+    diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Host)->getDiameterIdentity()->setValue(OH);
+    diameterDWR.addAvp(anna::diameter::helpers::base::AVPID__Origin_Realm)->getDiameterIdentity()->setValue(OR);
+  }
+
+  // Assignment for internal encoded versions:
+  setClientCERandDWR(diameterCER.code(), diameterDWR.code());
+}
 
 void Engine::setWatchdogPeriod(const anna::Millisecond & wp) throw(anna::RuntimeException) {
   if(wp < ClientSession::DefaultWatchdogPeriod) {
@@ -289,7 +329,7 @@ throw(anna::RuntimeException) {
   result->setWatchdogPeriod(a_watchdogPeriod);
   result->a_parent = server;
   result->a_socketId = socketId;
-  result->initializeSequences(); // después de asignar el server y el socketId (*)
+  result->initializeSequences(); // despus de asignar el server 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 = this;
   clientSession_key key = ClientSession::getKey(server->getAddress(), server->getPort(), socketId);
@@ -968,10 +1008,10 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw()
   //        [Error-Message].................................(281,0)
   //       *[Failed-AVP]....................................(279,0)
   try {
-    anna::diameter::codec::Message diameterDPA;
-    anna::diameter::codec::Avp avpRC;
-    anna::diameter::codec::Avp avpOH;
-    anna::diameter::codec::Avp avpOR;
+    anna::diameter::codec::Message diameterDPA(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
     // Message header
     diameterDPA.setId(anna::diameter::helpers::base::COMMANDID__Disconnect_Peer_Answer);
     diameterDPA.setVersion(1);
@@ -996,7 +1036,10 @@ void Engine::readDPA(anna::DataBlock &dpa, const anna::DataBlock & dpr) throw()
     // Encode
     dpa = diameterDPA.code();
   } catch(anna::RuntimeException &ex) {
-    ex.trace();
+    std::string msg = ex.getText();
+    msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DPA)";
+    anna::Logger::error(msg, ANNA_FILE_LOCATION);
+    //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
   }
 }
 
@@ -1022,10 +1065,10 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw()
   //        [Firmware-Revision].............................(267,0)
   //       *[AVP]...........................................(0,0)
   try {
-    anna::diameter::codec::Message diameterCEA;
-    anna::diameter::codec::Avp avpRC;
-    anna::diameter::codec::Avp avpOH;
-    anna::diameter::codec::Avp avpOR;
+    anna::diameter::codec::Message diameterCEA(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
     // Message header
     diameterCEA.setId(anna::diameter::helpers::base::COMMANDID__Capabilities_Exchange_Answer);
     diameterCEA.setVersion(1);
@@ -1059,7 +1102,10 @@ void Engine::readCEA(anna::DataBlock &cea, const anna::DataBlock & cer) throw()
     // Encode
     cea = diameterCEA.code();
   } catch(anna::RuntimeException &ex) {
-    ex.trace();
+    std::string msg = ex.getText();
+    msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with CEA)";
+    anna::Logger::error(msg, ANNA_FILE_LOCATION);
+    //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
   }
 }
 
@@ -1075,10 +1121,10 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw()
   //       *[Failed-AVP]....................................(279,0)
   //        [Origin-State-Id]...............................(278,0)
   try {
-    anna::diameter::codec::Message diameterDWA;
-    anna::diameter::codec::Avp avpRC;
-    anna::diameter::codec::Avp avpOH;
-    anna::diameter::codec::Avp avpOR;
+    anna::diameter::codec::Message diameterDWA(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpRC(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpOH(getBaseProtocolCodecEngine());
+    anna::diameter::codec::Avp avpOR(getBaseProtocolCodecEngine());
     // Message header
     diameterDWA.setId(anna::diameter::helpers::base::COMMANDID__Device_Watchdog_Answer);
     diameterDWA.setVersion(1);
@@ -1103,7 +1149,10 @@ void Engine::readDWA(anna::DataBlock &dwa, const anna::DataBlock & dwr) throw()
     // Encode
     dwa = diameterDWA.code();
   } catch(anna::RuntimeException &ex) {
-    ex.trace();
+    std::string msg = ex.getText();
+    msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages encoding (unable to answer with DWA)";
+    anna::Logger::error(msg, ANNA_FILE_LOCATION);
+    //throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
   }
 }