-// 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/core/functions.hpp>
#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/LocalServer.hpp>
#include <anna/diameter.comm/ServerSessionReceiver.hpp>
#include <anna/diameter.comm/ReceiverFactoryImpl.hpp>
+#include <anna/diameter.comm/OriginHostManager.hpp>
+#include <anna/diameter.comm/OriginHost.hpp>
#include <anna/app/functions.hpp>
#include <anna/comm/ClientSocket.hpp>
ServerSession::ServerSession() : Session("diameter::comm::ServerSession", "Diameter Inactivity Detection Timer"),
- a_receiverFactory(this),
- a_cer(ClassCode::Bind),
- a_dwr(ClassCode::ApplicationMessage) // realmente no es necesario, los Message son por defecto de aplicacion
+ a_receiverFactory(this)
{ initialize(); }
-void ServerSession::initialize() throw() {
+void ServerSession::initialize() {
Session::initialize();
a_parent = NULL;
a_clientSocket = NULL;
//ServerSession::~ServerSession() {;}
-void ServerSession::setClientSocket(anna::comm::ClientSocket *clientSocket) throw() {
+void ServerSession::setClientSocket(anna::comm::ClientSocket *clientSocket) {
a_clientSocket = clientSocket;
a_clientSocket->setReceiverFactory(a_receiverFactory);
}
-const std::string& ServerSession::getAddress() const throw() {
+const std::string& ServerSession::getAddress() const {
return a_parent->getKey().first;
}
-int ServerSession::getPort() const throw() {
+int ServerSession::getPort() const {
return a_parent->getKey().second;
}
-
-const Response* ServerSession::send(const Message* message) throw(anna::RuntimeException) {
+const Response* ServerSession::send(const Message* message) noexcept(false) {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "send", ANNA_FILE_LOCATION));
if(!message)
// 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);
if(isRequest) {
// 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)
}
//
updateOutgoingActivityTime();
// OAM
- countSendings(cid, true /* send ok */);
- // 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&) {;}
- }
- );
+ countSendings(cid, aid, true /* send ok */);
// Restore sequences:
if(fixed) message_nc->restoreSequencesAfterFix(); // restore to application sequences after fix
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;
}
-bool ServerSession::unbind(bool forceDisconnect) throw(anna::RuntimeException) {
+bool ServerSession::unbind(bool forceDisconnect) noexcept(false) {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "unbind", ANNA_FILE_LOCATION));
if(a_state == State::Closed)
return false;
}
-void ServerSession::eventPeerShutdown() throw() {
+void ServerSession::eventPeerShutdown() {
// Inform father server:
a_parent->eventPeerShutdown(this);
}
-void ServerSession::eventResponse(const Response& response) throw(anna::RuntimeException) {
+void ServerSession::eventRequestRetransmission(Message *request) {
+
+ // OAM
+ OamModule &oamModule = OamModule::instantiate();
+ oamModule.count(OamModule::Counter::RequestRetransmitted);
+ oamModule.count(OamModule::Counter::RequestRetransmittedOnServerSession);
+
+ // Inform father server:
+ a_parent->eventRequestRetransmission(this, request);
+}
+
+void ServerSession::eventResponse(const Response& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
+ // Inform father server:
+ a_parent->eventResponse(response, myNode);
+}
+
+void ServerSession::eventRequest(const anna::DataBlock &request, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
// Inform father server:
- a_parent->eventResponse(response);
+ a_parent->eventRequest(this, request, myNode);
}
-void ServerSession::eventRequest(const anna::DataBlock &request) throw(anna::RuntimeException) {
+void ServerSession::eventUnknownResponse(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
// Inform father server:
- a_parent->eventRequest(this, request);
+ a_parent->eventUnknownResponse(this, response, myNode);
}
-void ServerSession::eventUnknownResponse(const anna::DataBlock& response) throw(anna::RuntimeException) {
+void ServerSession::eventDPA(const anna::DataBlock& response, const anna::diameter::comm::OriginHost *myNode) noexcept(false) {
// Inform father server:
- a_parent->eventUnknownResponse(this, response);
+ a_parent->eventDPA(this, response, myNode);
}
+anna::U32 ServerSession::getAuthApplicationIdFromCER(const anna::DataBlock &cer, bool &found) const {
+
+ anna::U32 result{};
+ found = true;
+
+ anna::diameter::codec::Message codecMsg; // codec engine to pre-assigned, but will be inferred from ApplicationId during decoding:
+ try { codecMsg.decode(cer); } catch(anna::RuntimeException &ex) { ex.trace(); found = false; return result; }
+
+ // Look at first level:
+ try {
+ result = codecMsg.getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->getValue();
+ }
+ catch(anna::RuntimeException &ex) {
+ found = false;
+ }
+
+ // Look within Vendor-Specific-Application-Id:
+ if (!found) {
+ try {
+ result = codecMsg.getAvp(helpers::base::AVPID__Vendor_Specific_Application_Id)->getAvp(helpers::base::AVPID__Auth_Application_Id)->getUnsigned32()->getValue();
+ }
+ catch(anna::RuntimeException &ex) {
+ found = false;
+ }
+ }
+
+ return result;
+}
+
//------------------------------------------------------------------------------------------
// Se invoca desde el diameter::comm::Receiver
//------------------------------------------------------------------------------------------
void ServerSession::receive(const anna::comm::Message& message)
-throw(anna::RuntimeException) {
+noexcept(false) {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "receive", ANNA_FILE_LOCATION));
+
+
// Activity:
updateIncomingActivityTime();
activateTimer();
std::string msg = "Received diameter message: ";
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&) {;}
-);
+ );
// Main counters:
OamModule &oamModule = OamModule::instantiate();
oamModule.count(isRequest ? OamModule::Counter::RequestReceived : OamModule::Counter::AnswerReceived);
oamModule.count(isRequest ? OamModule::Counter::RequestReceivedOnServerSession : OamModule::Counter::AnswerReceivedOnServerSession);
// 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)
+
+ // OriginHostManager (to register remote origin host in order to associate with specific comm engine):
+ anna::diameter::comm::OriginHostManager &ohm = anna::diameter::comm::OriginHostManager::instantiate();
+
+ // Extract OriginHost from datablock (db):
+ std::string remoteOriginHost = anna::diameter::helpers::base::functions::getOriginHost(db);
+ LOGDEBUG(anna::Logger::debug(anna::functions::asString("REMOTE ORIGIN HOST FOR THE MESSAGE RECEIVED: %s", remoteOriginHost.c_str()), ANNA_FILE_LOCATION));
+
+ // Now, get the corresponding own origin host for it; in case of CER received, this will be unkonwn:
+ const anna::diameter::comm::OriginHost *originHost = ohm.getOriginHostForRemoteOriginHost(remoteOriginHost);
if(isRequest) {
// Si recibo un request, el message solo tiene fiable el DataBlock. Como por defecto se construye como ApplicationMessage,
// Received CER
if(cid == helpers::base::COMMANDID__Capabilities_Exchange_Request) {
+
+ // For CERs, we need to extract the Auth-Application-Id:
+ bool found;
+ anna::U32 authApplicationId = getAuthApplicationIdFromCER(db, found);
+
+ // Now, sequential search in OriginHostManager for that id:
+ anna::diameter::comm::OriginHost *originHost = ohm.getOriginHost(authApplicationId);
+
+ if (!originHost) {
+ LOGWARNING(anna::Logger::warning("DIAMETER_NO_COMMON_APPLICATION with received CER. TODO: send CEA with that result code", ANNA_FILE_LOCATION));
+ unbind(true /* always immediate */);
+ return;
+ }
+
+ // Map origin host of received CER, to own OriginHost pointer. This will be used in future: DWR, DPR, normal messages
+ ohm.registerRemoteOriginHost(remoteOriginHost, originHost->getName());
+
+
+ // OAM
oamModule.count(OamModule::Counter::CERReceived);
if(a_state == State::Bound) {
LOGWARNING(anna::Logger::warning("Received another CER over already bound connection. Anyway, will be replied with CEA", ANNA_FILE_LOCATION));
}
- a_cer.setBody(db);
- sendCEA();
+ // Basic DRA:
+ originHost->getCommEngine()->manageDrDhServerSession(this, true /* register */);
+
+ sendCEA(originHost->getCommEngine(), db);
//activateTimer(); // Ya se invoca al inicio de este metodo ::receive
//bool changes = a_parent->refreshAvailability();
return; // (*)
// Received DWR
else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) {
oamModule.count(OamModule::Counter::DWRReceived);
- a_dwr.setBody(db);
- sendDWA();
+
+ if (!originHost) return; // TODO, responding DWA with result code error
+
+ sendDWA(originHost->getCommEngine(), db);
return; // (**)
}
// Received DPR
else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) {
oamModule.count(OamModule::Counter::DPRReceived);
+ if (!originHost) return; // TODO, responding DPA with result code error
+
if(a_state == State::Bound) {
- a_dpr.setBody(db);
setState(State::Disconnecting);
LOGWARNING(anna::Logger::warning("DPR has been received from peer (diameter client)", ANNA_FILE_LOCATION));
// Ignore pending on server sessions:
- /*if (getOTARequests() == 0) */sendDPA();
+ /*if (getOTARequests() == 0) */sendDPA(originHost->getCommEngine(), db);
return; // DPR won't be informed because virtual readDPA is available for this
}
}
try {
- eventRequest(db);
+ // application message counters
+ ApplicationMessageOamModule::instantiate().count(cid.first, -1 /* no result code */, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Request_Received_AsServer);
+
+ if (!originHost) return; // TODO, responding DWA with result code error
+
+ eventRequest(db, originHost);
} catch(anna::RuntimeException& ex) {
ex.trace();
}
doUnbind = true;
}
}
+
+ if (originHost)
+ eventDPA(db, originHost);
+
} else if(cid == helpers::base::COMMANDID__Device_Watchdog_Answer) { // non usual (server should not send DWR's)
oamModule.count(OamModule::Counter::DWAReceived);
}
oamModule.count(OamModule::Counter::AnswerReceivedUnknown);
oamModule.count(OamModule::Counter::AnswerReceivedOnServerSessionUnknown);
oamModule.activateAlarm(OamModule::Alarm::AnswerReceivedOnServerSessionUnknown);
- eventUnknownResponse(db);
+
+ // application message counters
+ ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_UnknownReceived_AsServer);
+
+ if (originHost)
+ eventUnknownResponse(db, originHost);
+
string msg(asString());
msg += anna::functions::asString(" | Response received from client, for non registered context (HopByHop: %u)", hopByHop);
throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
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 client (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 client (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->setRequestClientSessionKey(response->getRequest()->getRequestClientSessionKey()); // "" means unkown/unset
);
diameter::codec::functions::setHopByHop((anna::DataBlock&)db, response->getRequest()->getRequestHopByHop());
diameter::codec::functions::setEndToEnd((anna::DataBlock&)db, response->getRequest()->getRequestEndToEnd());
- eventResponse(*response);
+
+ // application message counters
+ ApplicationMessageOamModule::instantiate().count(cid.first, resultCode, anna::diameter::codec::functions::getApplicationId(db), ApplicationMessageOamModule::Counter::Answer_Received_AsServer);
+
+ if (originHost)
+ eventResponse(*response, originHost);
+
} catch(anna::RuntimeException& ex) {
ex.trace();
}
unbind(true /* always immediate */);
}
-void ServerSession::finalize() throw() {
+void ServerSession::finalize() {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "finalize", ANNA_FILE_LOCATION));
// Configuration overiddings
setOnDisconnect(OnDisconnect::IgnorePendings);
}
// Inform father local server (availability changes):
- bool changes = getParent()->refreshAvailability();
+ getParent()->refreshAvailability();
// OAM
bool multipleConnections = (getParent()->getMaxConnections() > 1);
std::string socket = anna::functions::socketLiteralAsString(getAddress(), getPort());
-void ServerSession::sendCEA()
-throw(anna::RuntimeException) {
+void ServerSession::sendCEA(const Engine *commEngine, const anna::DataBlock &cerDataBlock)
+noexcept(false) {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendCEA", ANNA_FILE_LOCATION));
+
anna::DataBlock cea(true);
- a_engine->readCEA(cea, a_cer.getBody()); // Asume that CEA is valid ...
+ commEngine->readCEA(cea, cerDataBlock); // Asume that CEA is valid ...
// If one peer sends a CER message to another Peer and receiver does not have support for
//
// 1) any common application then it must return the CEA with Result-Code Avp set to DIAMETER_NO_COMMON_APPLICATION
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;
}
}
}
-void ServerSession::sendDWA()
-throw(anna::RuntimeException) {
+void ServerSession::sendDWA(const Engine *commEngine, const anna::DataBlock &dwrDataBlock)
+noexcept(false) {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "sendDWA", ANNA_FILE_LOCATION));
anna::DataBlock dwa(true);
- a_engine->readDWA(dwa, a_dwr.getBody()); // Asume that DWA is valid ...
+ commEngine->readDWA(dwa, dwrDataBlock); // Asume that DWA is valid ...
if(dwa.isEmpty())
throw anna::RuntimeException("This diameter agent defines an empty DWA message. Remote client never will validate this connection health", ANNA_FILE_LOCATION);
// Se invoca desde diameter::comm::Timer
//-------------------------------------------------------------------------
void ServerSession::expireResponse(diameter::comm::Response* response)
-throw() {
+{
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expireResponse", ANNA_FILE_LOCATION));
Session::expireResponse(response);
// OAM
}
std::string ServerSession::asString() const
-throw() {
+{
string result = Session::asString();
result += " | Parent Local Server: ";
result += anna::functions::socketLiteralAsString(getAddress(), getPort());
}
anna::xml::Node* ServerSession::asXML(anna::xml::Node* parent) const
-throw() {
+{
anna::xml::Node* result = Session::asXML(parent);
parent->createChild("diameter.comm.ServerSession");
result->createAttribute("ParentLocalServer", anna::functions::socketLiteralAsString(getAddress(), getPort()));
//------------------------------------------------------------------------------
//------------------------------------------------------ ServerSession::expire()
//------------------------------------------------------------------------------
-void ServerSession::expire(anna::timex::Engine *timeController) throw(anna::RuntimeException) {
+void ServerSession::expire(anna::timex::Engine *timeController) noexcept(false) {
LOGMETHOD(anna::TraceMethod traceMethod(a_className, "expire (inactivity check timer)", ANNA_FILE_LOCATION));
LOGWARNING(anna::Logger::warning("Detecting anomaly (too inactivity time) over server session. Resetting", ANNA_FILE_LOCATION));
// OAM
unbind(true /* always immediate */); // no delegamos en un planning o similar
}
-void ServerSession::setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) throw() {
+void ServerSession::setAllowedInactivityTime(const anna::Millisecond & allowedInactivityTime) {
setTimeout(allowedInactivityTime);
}
//------------------------------------------------------------------------------
//---------------------------------- ServerSession::updateIncomingActivityTime()
//------------------------------------------------------------------------------
-void ServerSession::updateIncomingActivityTime() throw() {
+void ServerSession::updateIncomingActivityTime() {
Session::updateIncomingActivityTime();
a_parent->updateIncomingActivityTime();
}
//------------------------------------------------------------------------------
//---------------------------------- ServerSession::updateOutgoingActivityTime()
//------------------------------------------------------------------------------
-void ServerSession::updateOutgoingActivityTime(void) throw() {
+void ServerSession::updateOutgoingActivityTime(void) {
Session::updateOutgoingActivityTime();
a_parent->updateOutgoingActivityTime();
}
//------------------------------------------------------------------------------
//----------------------------------------------- ServerSession::countSendings()
//------------------------------------------------------------------------------
-void ServerSession::countSendings(const diameter::CommandId & cid, bool ok)throw() {
+void ServerSession::countSendings(const diameter::CommandId & cid, unsigned int aid, bool ok){
OamModule &oamModule = OamModule::instantiate();
+ ApplicationMessageOamModule &appMsgOamModule = ApplicationMessageOamModule::instantiate();
+
bool isRequest = cid.second;
if(ok) {
else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentOK); // not usual
else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentOK);
else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentOK);
+ // Application messages:
+ else {
+ appMsgOamModule.count(cid.first, -1 /* no result code */, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentOK_AsServer);
+ }
} else {
// Main counters:
oamModule.count(isRequest ? OamModule::Counter::RequestSentNOK : OamModule::Counter::AnswerSentNOK);
else if(cid == helpers::base::COMMANDID__Device_Watchdog_Request) oamModule.count(OamModule::Counter::DWRSentNOK); // not usual
else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Answer) oamModule.count(OamModule::Counter::DPASentNOK);
else if(cid == helpers::base::COMMANDID__Disconnect_Peer_Request) oamModule.count(OamModule::Counter::DPRSentNOK);
+ // Application messages:
+ else {
+ appMsgOamModule.count(cid.first, -1 /* no result code */, aid, isRequest ? ApplicationMessageOamModule::Counter::Request_SentNOK_AsServer : ApplicationMessageOamModule::Counter::Answer_SentNOK_AsServer);
+ }
}
}