App counters including message name and result code if proceed
[anna.git] / source / diameter.comm / ClientSession.cpp
index 73d097a..aea2851 100644 (file)
@@ -1,37 +1,9 @@
-// ANNA - Anna is Not 'N' Anymore
-//
-// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-//
-// https://bitbucket.org/testillano/anna
-//
-// 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 Google Inc. 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/core/functions.hpp>
@@ -50,6 +22,7 @@
 #include <anna/diameter.comm/Response.hpp>
 #include <anna/diameter.comm/Message.hpp>
 #include <anna/diameter.comm/OamModule.hpp>
+#include <anna/diameter.comm/ApplicationMessageOamModule.hpp>
 #include <anna/diameter.comm/TimerManager.hpp>
 #include <anna/diameter.comm/Timer.hpp>
 #include <anna/diameter.comm/ClientSessionReceiver.hpp>
@@ -69,7 +42,6 @@
 #include <time.h>
 
 
-
 using namespace std;
 using namespace anna::diameter;
 using namespace anna::diameter::comm;
@@ -109,7 +81,7 @@ int ClientSession::getPort() const throw() {
 void ClientSession::setState(State::_v state) throw() {
   Session::setState(state);
   // Inform father server (availability changes):
-  bool changes = a_parent->refreshAvailability();
+  a_parent->refreshAvailability();
 }
 
 void ClientSession::bind() throw(anna::RuntimeException) {
@@ -140,7 +112,11 @@ void ClientSession::bind() throw(anna::RuntimeException) {
     return;
   }
 
-  // OAM Lo comento, porque no se contabilizan los reintentos y por lo tanto no son muy útiles.
+  // Some operations could be done before sending CER, for example non-standard Origin-Host manipulation for
+  // Tekelec PCRF
+  a_engine->bindingClientSession(this);
+
+  // OAM Lo comento, porque no se contabilizan los reintentos y por lo tanto no son muy �tiles.
 //  OamModule &oamModule = OamModule::instantiate();
 //  oamModule.count(a_server->isAvailable() ? OamModule::Counter::TCPConnectOK:OamModule::Counter::TCPConnectNOK);
   // Application bind
@@ -177,6 +153,8 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
   // Command id:
   bool isRequest;
   diameter::CommandId cid = message->getCommandId(isRequest);
+  diameter::ApplicationId aid = message->getApplicationId();
+
   LOGDEBUG(
     std::string msg = "Sending diameter message: ";
     msg += anna::diameter::functions::commandIdAsPairString(cid);
@@ -297,7 +275,7 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
     }
 
     // Fixing indicator:
-    fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd, a_engine->getFreezeEndToEndOnSending());
+    fixed = message_nc->fixRequestSequence(a_nextHopByHop, a_nextEndToEnd);
     message_nc->updateRequestTimestampMs(); // statistics purposes (processing time for request type)
   }
 
@@ -320,15 +298,21 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
     //
     updateOutgoingActivityTime();
     // OAM
-    countSendings(cid, true /* send ok */);
+    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);
+      }
     }
     );
 
@@ -338,7 +322,7 @@ const Response* ClientSession::send(const Message* message) throw(anna::RuntimeE
     if(fixed) message_nc->restoreSequencesAfterFix();  // restore to application sequences after fix
 
     // OAM
-    countSendings(cid, false /* send no ok */);
+    countSendings(cid, aid, false /* send no ok */);
     throw;
   }
 
@@ -463,6 +447,17 @@ void ClientSession::eventPeerShutdown() throw() {
   a_parent->eventPeerShutdown(this);
 }
 
+void ClientSession::eventRequestRetransmission(Message *request) throw() {
+
+  // OAM
+  OamModule &oamModule = OamModule::instantiate();
+  oamModule.count(OamModule::Counter::RequestRetransmitted);
+  oamModule.count(OamModule::Counter::RequestRetransmittedOnClientSession);
+
+  // Inform father server:
+  a_parent->eventRequestRetransmission(this, request);
+}
+
 void ClientSession::eventResponse(const Response& response) throw(anna::RuntimeException) {
   // Inform father server:
   a_parent->eventResponse(response);
@@ -478,6 +473,11 @@ void ClientSession::eventUnknownResponse(const anna::DataBlock& response) throw(
   a_parent->eventUnknownResponse(this, response);
 }
 
+void ClientSession::eventDPA(const anna::DataBlock& response) throw(anna::RuntimeException) {
+  // Inform father server:
+  a_parent->eventDPA(this, response);
+}
+
 
 
 //------------------------------------------------------------------------------------------
@@ -498,15 +498,25 @@ throw(anna::RuntimeException) {
     msg += anna::diameter::functions::commandIdAsPairString(cid);
     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
 
-    if((cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) || (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first))
-  try { anna::diameter::codec::Message dmsg; dmsg.decode(db); /* decode to be traced */ } catch(anna::RuntimeException&) {;}
+    if( (cid == helpers::base::COMMANDID__Capabilities_Exchange_Answer) ||
+        (cid.first == helpers::base::COMMANDID__Device_Watchdog_Request.first)) {
+      try {
+        anna::diameter::codec::Message dmsg(a_engine->getBaseProtocolCodecEngine()); dmsg.decode(db); /* decode to be traced */
+      }
+      catch(anna::RuntimeException &ex) {
+        std::string msg = ex.getText();
+        msg += " | Use diameter::comm::Engine::setBaseProtocolCodecEngine() to allow internal base protocol messages full tracing";
+        anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+      }
+    }
 );
+
   // Main counters:
   OamModule &oamModule = OamModule::instantiate();
   oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived);
   oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnClientSession : OamModule::Counter::AnswerReceivedOnClientSession);
   // Statistic (size)
-  a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize()); // only on reception (application could manage sent sizes)
+  a_parent->updateReceivedMessageSizeStatisticConcept(message.getSize(), cid); // only on reception (application could manage sent sizes)
 
   if(isRequest) {
     /////////////////////////////
@@ -543,6 +553,9 @@ throw(anna::RuntimeException) {
     }
 
     try {
+      // application message counters
+      ApplicationMessageOamModule::instantiate().count(cid.first, -1 /* no result code */, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsClient);
+
       eventRequest(db);
     } catch(anna::RuntimeException& ex) {
       ex.trace();
@@ -578,13 +591,16 @@ throw(anna::RuntimeException) {
     }
 
     if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) {
-      LOGWARNING(anna::Logger::warning("Received CEA with non-success Result-Code. Unbinding connection.", ANNA_FILE_LOCATION));
+      LOGWARNING(
+        std::string msg = anna::functions::asString("Received CEA with non-success Result-Code (%d). Unbinding connection.", resultCode);
+        anna::Logger::warning(msg, ANNA_FILE_LOCATION);
+      );
       doUnbind = true;
     } else {
       setState(State::Bound);
       //activateTimer(); // Ya se invoca al inicio de este metodo ::receive
       // Inform father server (availability changes):
-      bool changes = a_parent->refreshAvailability();
+      a_parent->refreshAvailability();
       //startClock();
     }
   }
@@ -594,7 +610,10 @@ throw(anna::RuntimeException) {
     setWatchdogState(WatchdogState::WaitingTimerExpiration);
 
     if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS)
-      LOGWARNING(anna::Logger::warning("Received DWA with non-success Result-Code... but ASSUME keep-alive is reached", ANNA_FILE_LOCATION));
+      LOGWARNING(
+        std::string msg = anna::functions::asString("Received DWA with non-success Result-Code (%d)... but ASSUME keep-alive is reached", resultCode);
+        anna::Logger::warning(msg, ANNA_FILE_LOCATION);
+      );
 
     if(a_state == State::Failover) {
       setState(State::Bound);
@@ -615,7 +634,10 @@ throw(anna::RuntimeException) {
 
     if(a_state == State::WaitingDPA) {
       if(resultCode != helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) {
-        LOGWARNING(anna::Logger::warning("Received DPA with non-success Result-Code. Ignoring and recovering Bound state", ANNA_FILE_LOCATION));
+        LOGWARNING(
+          std::string msg = anna::functions::asString("Received DPA with non-success Result-Code (%d). Ignoring and recovering Bound state", resultCode);
+          anna::Logger::warning(msg, ANNA_FILE_LOCATION);
+        );
         setState(State::Bound);
       } else {
         LOGWARNING(anna::Logger::warning("Received DPA With Result-Code = DIAMETER_SUCCESS. Disconnect now.", ANNA_FILE_LOCATION));
@@ -634,6 +656,10 @@ throw(anna::RuntimeException) {
     oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
     oamModule.count(OamModule::Counter::AnswerReceivedOnClientSessionUnknown);
     oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnClientSessionUnknown);
+
+    // application message counters
+    ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsClient);
+
     eventUnknownResponse(db);
     string msg(asString());
     msg += anna::functions::asString(" | Response received from entity, for non registered context (HopByHop: %u)", hopByHop);
@@ -653,20 +679,19 @@ throw(anna::RuntimeException) {
   anna::Millisecond current = (anna::Millisecond)anna::functions::millisecond();
   anna::Millisecond request = response->getRequest()->getRequestTimestampMs();
   anna::Millisecond timeToAnswerMs = current - request;
-  a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs);
-  LOGDEBUG
-  (
-    std::string msg = "This diameter request context lasted ";
-    msg += anna::functions::asString(timeToAnswerMs);
-    msg += " milliseconds at diameter server (included network time)";
-    anna::Logger::debug(msg, ANNA_FILE_LOCATION);
-  );
+  a_parent->updateProcessingTimeStatisticConcept(timeToAnswerMs, cid);
+  //LOGDEBUG
+  //(
+  //  std::string msg = "This diameter request context lasted ";
+  //  msg += anna::functions::asString(timeToAnswerMs);
+  //  msg += " milliseconds at diameter server (included network time)";
+  //  anna::Logger::debug(msg, ANNA_FILE_LOCATION);
+  //);
   // Progress origin for tracking purposes on asyncronous boxes with both diameter interfaces (entities and clients)
   Message * requestMessage = const_cast<Message*>(response->getRequest());
   requestMessage->setRequestServerSessionKey(response->getRequest()->getRequestServerSessionKey()); // -1 means unkown/unset
 
   if(cid != helpers::base::COMMANDID__Disconnect_Peer_Answer) {
-    // don't progress DPA: unbind is automatically performed and not open to any application decision
     try {
       response->setMessage(&db);
       // Restore received datablock
@@ -680,11 +705,21 @@ throw(anna::RuntimeException) {
       );
       diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
       diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
+
+      // application message counters
+      if(cid != helpers::base::COMMANDID__Capabilities_Exchange_Answer)
+        ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsClient);
+
       eventResponse(*response);
     } catch(anna::RuntimeException& ex) {
       ex.trace();
     }
   }
+  else { // DPA
+    // unbind is automatically performed, anyway we can inform to the application just in case some additional
+    //  procedure could be issued:
+    eventDPA(db);
+  }
 
   response_erase(response);
 
@@ -696,10 +731,8 @@ throw(anna::RuntimeException) {
 void ClientSession::finalize() throw() {
   LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION));
   Session::finalize();
-  // Check deprecated entity:
-  const Entity *entity = getParent() /* server */ ->getParent() /* entity */;
   // Inform father server (availability changes):
-  bool changes = a_parent->refreshAvailability();
+  a_parent->refreshAvailability();
   // OAM
   const Server *server = getParent();
   bool multipleConnections = (server->getMaxClientSessions() > 1);
@@ -730,7 +763,7 @@ void ClientSession::recover() throw() {
   }
 
   // Inform father server (availability changes):
-  bool changes = a_parent->refreshAvailability();
+  a_parent->refreshAvailability();
   // OAM
   const Server *server = getParent();
   bool multipleConnections = (server->getMaxClientSessions() > 1);
@@ -928,8 +961,10 @@ void ClientSession::updateOutgoingActivityTime(void) throw() {
 //------------------------------------------------------------------------------
 //----------------------------------------------- ClientSession::countSendings()
 //------------------------------------------------------------------------------
-void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw() {
+void ClientSession::countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok)throw() {
   OamModule &oamModule = OamModule::instantiate();
+  ApplicationMessageOamModule &appMsgOamModule = ApplicationMessageOamModule::instantiate();
+
   bool isRequest = cid.second;
 
   if(ok) {
@@ -942,6 +977,10 @@ void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw
     else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentOK);  // not usual (dwr was received from server)
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
+    // Application messages:
+    else {
+      appMsgOamModule.count(cid.first, -1 /* no result code */, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentOK_AsClient : ApplicationMessageOamModule::Counter::Answer_SentOK_AsClient);
+    }
   } else {
     // Main counters:
     oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
@@ -952,6 +991,10 @@ void ClientSession::countSendings(const diameter::CommandId & cid, bool ok)throw
     else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) oamModule.count(OamModule::Counter::DWASentNOK);  // not usual (dwr was received from server)
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);
     else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
+    // Application messages:
+    else {
+      appMsgOamModule.count(cid.first, -1 /* no result code */, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentNOK_AsClient : ApplicationMessageOamModule::Counter::Answer_SentNOK_AsClient);
+    }
   }
 }