4584 lines
154 KiB
C++
4584 lines
154 KiB
C++
/**
|
|
* tcap.cpp
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
*
|
|
* Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
|
|
*
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
|
* Copyright (C) 2004-2014 Null Team
|
|
*
|
|
* This software is distributed under multiple licenses;
|
|
* see the COPYING file in the main directory for licensing
|
|
* information for this specific distribution.
|
|
*
|
|
* This use of this software may be subject to additional restrictions.
|
|
* See the LEGAL file in the main directory for details.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#include "yatesig.h"
|
|
#include "yateasn.h"
|
|
|
|
|
|
using namespace TelEngine;
|
|
|
|
#ifdef DEBUG
|
|
static void dumpData(int debugLevel, SS7TCAP* tcap, String message, void* obj, NamedList& params,
|
|
DataBlock data = DataBlock::empty())
|
|
{
|
|
if (tcap) {
|
|
String tmp;
|
|
params.dump(tmp,"\r\n ",'\'',true);
|
|
String str;
|
|
str.hexify(data.data(),data.length(),' ');
|
|
Debug(tcap,debugLevel,"%s [%p] - \r\nparams='%s',\r\ndata='%s'",
|
|
message.safe(),obj,tmp.c_str(),str.c_str());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
TCAPUser::~TCAPUser()
|
|
{
|
|
Debug(this,DebugAll,"TCAPUser::~TCAPUser() [%p] - tcap user destroyed",this);
|
|
}
|
|
|
|
void TCAPUser::destroyed()
|
|
{
|
|
Debug(this,DebugAll,"TCAPUser::destroyed() [%p]",this);
|
|
Lock lock(m_tcapMtx);
|
|
if (m_tcap) {
|
|
// notify SCCP OutOfService
|
|
NamedList p("");
|
|
m_tcap->updateUserStatus(this,SCCPManagement::UserOutOfService,p);
|
|
|
|
m_tcap->detach(this);
|
|
Debug(this,DebugAll,"TCAPUser::~TCAPUser() [%p] - Detached from TCAP (%p,%s)",this,m_tcap,m_tcap->toString().safe());
|
|
m_tcap->deref();
|
|
m_tcap = 0;
|
|
}
|
|
lock.drop();
|
|
SignallingComponent::destroyed();
|
|
}
|
|
|
|
void TCAPUser::attach(SS7TCAP* tcap)
|
|
{
|
|
Lock lock(m_tcapMtx);
|
|
|
|
if (m_tcap == tcap)
|
|
return;
|
|
SS7TCAP* tmp = m_tcap;
|
|
m_tcap = tcap;
|
|
lock.drop();
|
|
DDebug(this,DebugAll,"TCAPUser::attach(tcap=%s [%p], replacing tcap=%s [%p] [%p]",(m_tcap ? m_tcap->toString().safe() : ""),m_tcap,
|
|
(tmp ? tmp->toString().c_str() : ""),tmp,this);
|
|
if (tmp) {
|
|
tmp->detach(this);
|
|
Debug(this,DebugAll,"TCAPUser::attach() - Detached from TCAP (%p,%s) [%p]",tmp,tmp->toString().safe(),this);
|
|
tmp->deref();
|
|
tmp = 0;
|
|
}
|
|
if (!tcap)
|
|
return;
|
|
|
|
tcap->attach(this);
|
|
tcap->ref();
|
|
Debug(this,DebugAll,"Attached to TCAP (%p,%s) [%p] tcapRefCount=%d",tcap,tcap->toString().safe(),this,tcap->refcount());
|
|
}
|
|
|
|
bool TCAPUser::tcapIndication(NamedList& params)
|
|
{
|
|
Debug(this,DebugStub,"Please implement TCAPUser::tcapIndication()");
|
|
return false;
|
|
}
|
|
|
|
bool TCAPUser::managementNotify(SCCP::Type type, NamedList& params)
|
|
{
|
|
Debug(this,DebugStub,"Please implement TCAPUser::managementNotify()");
|
|
return false;
|
|
}
|
|
|
|
int TCAPUser::managementState()
|
|
{
|
|
return SCCPManagement::UserOutOfService;
|
|
}
|
|
|
|
struct PrimitiveMapping {
|
|
int primitive;
|
|
int mappedTo;
|
|
};
|
|
|
|
static bool s_extendedDbg = false;
|
|
static bool s_printMsgs = false;
|
|
static const String s_checkAddr = "tcap.checkAddress";
|
|
static const String s_localPC = "LocalPC";
|
|
static const String s_remotePC = "RemotePC";
|
|
static const String s_callingPA = "CallingPartyAddress";
|
|
static const String s_callingSSN = "CallingPartyAddress.ssn";
|
|
static const String s_callingRoute = "CallingPartyAddress.route";
|
|
static const String s_calledPA = "CalledPartyAddress";
|
|
static const String s_calledSSN = "CalledPartyAddress.ssn";
|
|
static const String s_HopCounter = "HopCounter";
|
|
|
|
// TCAP message parameters
|
|
static const String s_tcapUser = "tcap.user";
|
|
static const String s_tcapBasicTerm = "tcap.transaction.terminationBasic";
|
|
static const String s_tcapEndNow = "tcap.transaction.endNow";
|
|
static const String s_tcapRequest = "tcap.request.type";
|
|
static const String s_tcapRequestError = "tcap.request.error";
|
|
static const String s_tcapTransPrefix = "tcap.transaction";
|
|
static const String s_tcapMsgType = "tcap.transaction.messageType";
|
|
static const String s_tcapLocalTID = "tcap.transaction.localTID";
|
|
static const String s_tcapRemoteTID = "tcap.transaction.remoteTID";
|
|
static const String s_tcapAbortCause = "tcap.transaction.abort.cause";
|
|
static const String s_tcapAbortInfo = "tcap.transaction.abort.information";
|
|
|
|
static const String s_tcapDialogPrefix = "tcap.dialogPDU";
|
|
static const String s_tcapProtoVers = "tcap.dialogPDU.protocol-version";
|
|
static const String s_tcapIntAppID = "tcap.dialogPDU.integerApplicationId";
|
|
static const String s_tcapObjAppID = "tcap.dialogPDU.objectApplicationId";
|
|
static const String s_tcapIntSecID = "tcap.dialogPDU.integerSecurityId";
|
|
static const String s_tcapObjSecID = "tcap.dialogPDU.objectSecurityId";
|
|
static const String s_tcapIntConfidID = "tcap.dialogPDU.integerConfidentialityId";
|
|
static const String s_tcapObjConfidID = "tcap.dialogPDU.objectConfidentialityId";
|
|
static const String s_tcapReference = "tcap.dialogPDU.userInformation.direct-reference";
|
|
static const String s_tcapDataDesc = "tcap.dialogPDU.userInformation.data-descriptor";
|
|
static const String s_tcapEncodingContent = "tcap.dialogPDU.userInformation.encoding-contents";
|
|
static const String s_tcapEncodingType = "tcap.dialogPDU.userInformation.encoding-type";
|
|
|
|
static const String s_tcapCompCount = "tcap.component.count";
|
|
static const String s_tcapCompPrefix = "tcap.component";
|
|
static const String s_tcapLocalCID = "localCID";
|
|
static const String s_tcapRemoteCID = "remoteCID";
|
|
static const String s_tcapCompType = "componentType";
|
|
static const String s_tcapOpCodeType = "operationCodeType";
|
|
static const String s_tcapOpCode = "operationCode";
|
|
static const String s_tcapErrCodeType = "errorCodeType";
|
|
static const String s_tcapErrCode = "errorCode";
|
|
static const String s_tcapProblemCode = "problemCode";
|
|
static const String s_tcapPayload = "payload";
|
|
|
|
|
|
static void populateSCCPAddress(NamedList& localAddr, NamedList& remoteAddr, NamedList& initParams, bool initLocal,
|
|
bool keepPrefix = false)
|
|
{
|
|
String localParam(initLocal ? s_callingPA : s_calledPA);
|
|
String remoteParam(initLocal ? s_calledPA : s_callingPA);
|
|
|
|
NamedList aux("");
|
|
aux.copySubParams(initParams,localParam + ".");
|
|
if (keepPrefix) {
|
|
for (unsigned int i = 0; i < aux.count(); i++) {
|
|
NamedString* p = aux.getParam(i);
|
|
if (!TelEngine::null(p)) {
|
|
localAddr.setParam(remoteParam + "." + p->name(),*p);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
localAddr.copyParams(aux);
|
|
if (!TelEngine::null(initParams.getParam(s_localPC)))
|
|
localAddr.copyParam(initParams,s_localPC);
|
|
|
|
aux.clearParams();
|
|
aux.copySubParams(initParams,remoteParam + ".");
|
|
if (keepPrefix) {
|
|
for (unsigned int i = 0; i < aux.count(); i++) {
|
|
NamedString* p = aux.getParam(i);
|
|
if (!TelEngine::null(p)) {
|
|
remoteAddr.setParam(localParam + "." + p->name(),*p);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
remoteAddr.copyParams(aux);
|
|
if (!TelEngine::null(initParams.getParam(s_remotePC)))
|
|
remoteAddr.copyParam(initParams,s_remotePC);
|
|
}
|
|
|
|
static void compPrefix(String& prefix, unsigned int index, bool endSep = false)
|
|
{
|
|
prefix = s_tcapCompPrefix;
|
|
prefix << "." << index << (endSep ? "." : "");
|
|
}
|
|
|
|
/**
|
|
* SS7TCAP implementation
|
|
*/
|
|
const TokenDict SS7TCAP::s_tcapVersion[] = {
|
|
{"UnknownTCAP", SS7TCAP::UnknownTCAP},
|
|
{"ITU-T TCAP", SS7TCAP::ITUTCAP},
|
|
{"ANSI TCAP", SS7TCAP::ANSITCAP},
|
|
{0,-1},
|
|
};
|
|
|
|
const TokenDict SS7TCAP::s_compPrimitives[] = {
|
|
{"Invoke", SS7TCAP::TC_Invoke},
|
|
{"ResultLast", SS7TCAP::TC_ResultLast},
|
|
{"U_Error", SS7TCAP::TC_U_Error},
|
|
{"U_Reject", SS7TCAP::TC_U_Reject},
|
|
{"R_Reject", SS7TCAP::TC_R_Reject},
|
|
{"L_Reject", SS7TCAP::TC_L_Reject},
|
|
{"InvokeNotLast", SS7TCAP::TC_InvokeNotLast},
|
|
{"ResultNotLast", SS7TCAP::TC_ResultNotLast},
|
|
{"L_Cancel", SS7TCAP::TC_L_Cancel},
|
|
{"U_Cancel", SS7TCAP::TC_U_Cancel},
|
|
{"TimerReset", SS7TCAP::TC_TimerReset},
|
|
{0,0},
|
|
};
|
|
|
|
const TokenDict SS7TCAP::s_transPrimitives[] = {
|
|
{"Unidirectional", SS7TCAP::TC_Unidirectional},
|
|
{"Begin", SS7TCAP::TC_Begin},
|
|
{"QueryWithPerm", SS7TCAP::TC_QueryWithPerm},
|
|
{"QueryWithoutPerm", SS7TCAP::TC_QueryWithoutPerm},
|
|
{"Continue", SS7TCAP::TC_Continue},
|
|
{"ConversationWithPerm", SS7TCAP::TC_ConversationWithPerm},
|
|
{"ConversationWithoutPerm", SS7TCAP::TC_ConversationWithoutPerm},
|
|
{"End", SS7TCAP::TC_End},
|
|
{"Response", SS7TCAP::TC_Response},
|
|
{"U_Abort", SS7TCAP::TC_U_Abort},
|
|
{"P_Abort", SS7TCAP::TC_P_Abort},
|
|
{"Notice", SS7TCAP::TC_Notice},
|
|
{"Unknown", SS7TCAP::TC_Unknown},
|
|
{0,0},
|
|
};
|
|
|
|
const TokenDict SS7TCAP::s_compOperClasses[] = {
|
|
{"reportAll", SS7TCAP::SuccessOrFailureReport},
|
|
{"reportFail", SS7TCAP::FailureOnlyReport},
|
|
{"reportSuccess", SS7TCAP::SuccessOnlyReport},
|
|
{"reportNone", SS7TCAP::NoReport},
|
|
};
|
|
|
|
|
|
SS7TCAP::SS7TCAP(const NamedList& params)
|
|
: SCCPUser(params),
|
|
m_usersMtx(true,"TCAPUsers"),
|
|
m_inQueueMtx(true,"TCAPPendingMsg"),
|
|
m_SSN(0),
|
|
m_defaultRemoteSSN(0),
|
|
m_defaultHopCounter(0),
|
|
m_defaultRemotePC(0),
|
|
m_remoteTypePC(SS7PointCode::Other),
|
|
m_trTimeout(300),
|
|
m_transactionsMtx(true,"TCAPTransactions"),
|
|
m_tcapType(UnknownTCAP),
|
|
m_idsPool(0)
|
|
{
|
|
Debug(this,DebugAll,"SS7TCAP::SS7TCAP() [%p] created",this);
|
|
m_recvMsgs = m_sentMsgs = m_discardMsgs = m_normalMsgs = m_abnormalMsgs = 0;
|
|
m_ssnStatus = SCCPManagement::UserOutOfService;
|
|
}
|
|
|
|
SS7TCAP::~SS7TCAP()
|
|
{
|
|
Debug(this,DebugAll,"SS7TCAP::~SS7TCAP() [%p] destroyed, refCount=%d, usersCount=%d",this,refcount(),m_users.count());
|
|
if (m_users.count()) {
|
|
Debug(this,DebugCrit,"SS7TCAP destroyed while having %d user(s) still attached [%p]",m_users.count(),this);
|
|
ListIterator iter(m_users);
|
|
for (;;) {
|
|
TCAPUser* user = static_cast<TCAPUser*>(iter.get());
|
|
// End of iteration?
|
|
if (!user)
|
|
break;
|
|
if(user->tcap())
|
|
user->setTCAP(0);
|
|
}
|
|
m_users.setDelete(false);
|
|
}
|
|
m_transactions.clear();
|
|
m_inQueue.clear();
|
|
|
|
}
|
|
|
|
bool SS7TCAP::initialize(const NamedList* config)
|
|
{
|
|
#ifdef DEBUG
|
|
if(config && debugAt(DebugAll)) {
|
|
String tmp;
|
|
config->dump(tmp,"\r\n ",'\'',true);
|
|
Debug(this,DebugAll,"SS7TCAP::initialize([%p]) [%p] for configuration '%s'",config,this,tmp.c_str());
|
|
}
|
|
#endif
|
|
if (config) {
|
|
// read local point code and default remote point code
|
|
m_SSN = config->getIntValue(YSTRING("local_SSN"),-1);
|
|
m_defaultRemoteSSN = config->getIntValue(YSTRING("default_remote_SSN"),-1);
|
|
m_defaultHopCounter = config->getIntValue(YSTRING("default_hopcounter"),0);
|
|
if (m_defaultHopCounter > 15 || config->getBoolValue(YSTRING("default_hopcounter")))
|
|
m_defaultHopCounter = 15;
|
|
|
|
const char* code = config->getValue(YSTRING("default_remote_pointcode"));
|
|
m_remoteTypePC = SS7PointCode::lookup(config->getValue(YSTRING("pointcodetype"),""));
|
|
if (!(m_defaultRemotePC.assign(code,m_remoteTypePC) && m_defaultRemotePC.pack(m_remoteTypePC))) {
|
|
int codeInt = config->getIntValue(YSTRING("default_remote_pointcode"));
|
|
if (!m_defaultRemotePC.unpack(m_remoteTypePC,codeInt))
|
|
Debug(this,DebugMild,"SS7TCAP::initialize([%p]) [%p] - Invalid default_remote_pointcode=%s value configured",
|
|
config,this,code);
|
|
}
|
|
|
|
m_trTimeout = config->getIntValue(YSTRING("transact_timeout"),m_trTimeout / 1000) * 1000; // seconds to miliseconds
|
|
s_printMsgs = config->getBoolValue(YSTRING("print-messages"),false);
|
|
s_extendedDbg = config->getBoolValue(YSTRING("extended-debug"),false);
|
|
}
|
|
bool ok = SCCPUser::initialize(config);
|
|
if (ok) {
|
|
NamedList p("");
|
|
sendSCCPNotify(p);
|
|
Debug(this,DebugInfo,"SSN=%d has status='%s'[%p]",m_SSN,lookup(m_ssnStatus,SCCPManagement::broadcastType(),""),this);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool SS7TCAP::sendData(DataBlock& data, NamedList& params)
|
|
{
|
|
if (params.getBoolValue(s_callingSSN))
|
|
params.setParam(s_callingSSN,String(m_SSN));
|
|
if (params.getBoolValue(s_checkAddr,true)) {
|
|
String dpc = params.getValue(s_remotePC,"");
|
|
unsigned int pc = m_defaultRemotePC.pack(m_remoteTypePC);
|
|
if (dpc.null() && pc)
|
|
params.addParam(s_remotePC,String(pc));
|
|
int ssn = params.getIntValue(s_calledSSN,-1);
|
|
if (ssn < 0 && m_defaultRemoteSSN <= 255)
|
|
params.setParam(s_calledSSN,String(m_defaultRemoteSSN));
|
|
ssn = params.getIntValue(s_callingSSN,-1);
|
|
if (ssn < 0 && m_SSN <= 255) {
|
|
params.setParam(s_callingSSN,String(m_SSN));
|
|
if (!params.getParam(s_callingRoute))
|
|
params.addParam(s_callingRoute,"ssn");
|
|
}
|
|
if (m_defaultHopCounter && !params.getParam(s_HopCounter))
|
|
params.addParam(s_HopCounter,String(m_defaultHopCounter));
|
|
}
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && debugAt(DebugInfo))
|
|
dumpData(DebugInfo,this,"Sending to SCCP : ",this,params,data);
|
|
#endif
|
|
return SCCPUser::sendData(data,params);
|
|
}
|
|
|
|
HandledMSU SS7TCAP::receivedData(DataBlock& data, NamedList& params)
|
|
{
|
|
HandledMSU result;
|
|
if (!data.length())
|
|
return result;
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && debugAt(DebugInfo))
|
|
dumpData(DebugInfo,this,"Received from SCCP: ",this,params,data);
|
|
#endif
|
|
unsigned int cpaSSN = params.getIntValue(s_calledSSN,0);
|
|
unsigned int ssn = params.getIntValue("ssn",0);
|
|
if (m_SSN != cpaSSN && m_SSN != ssn)
|
|
return result;
|
|
enqueue(new SS7TCAPMessage(params,data));
|
|
result = HandledMSU::Accepted;
|
|
return result;
|
|
}
|
|
|
|
HandledMSU SS7TCAP::notifyData(DataBlock& data, NamedList& params)
|
|
{
|
|
HandledMSU result;
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && debugAt(DebugInfo))
|
|
dumpData(DebugInfo,this,"Received notify from SCCP: ",this,params,data);
|
|
#endif
|
|
enqueue(new SS7TCAPMessage(params,data,true));
|
|
return result;
|
|
}
|
|
|
|
bool SS7TCAP::managementNotify(SCCP::Type type, NamedList& params)
|
|
{
|
|
Lock lock(m_usersMtx);
|
|
ListIterator iter(m_users);
|
|
bool ok = false;
|
|
|
|
if (type == SCCP::SubsystemStatus && m_SSN != (unsigned int)params.getIntValue("ssn")) {
|
|
params.setParam("subsystem-status","UserOutOfService");
|
|
return true;
|
|
}
|
|
bool inService = false;
|
|
for (;;) {
|
|
TCAPUser* user = static_cast<TCAPUser*>(iter.get());
|
|
// End of iteration?
|
|
if (!user)
|
|
break;
|
|
if (user->managementNotify(type,params))
|
|
ok = true;
|
|
if (user->managementState() == (int) SCCPManagement::UserInService)
|
|
inService = true;
|
|
}
|
|
if (type == SCCP::SubsystemStatus)
|
|
params.setParam("subsystem-status",(inService ? "UserInService" : "UserOutOfService"));
|
|
return ok;
|
|
}
|
|
|
|
void SS7TCAP::updateUserStatus(TCAPUser* user, SCCPManagement::LocalBroadcast status, NamedList& params)
|
|
{
|
|
if (!user)
|
|
return;
|
|
DDebug(this,DebugAll,"SS7TCAP::updateUserStatus(user=%s[%p],status=%d) [%p]",user->toString().c_str(),user,status,this);
|
|
bool notify = false;
|
|
Lock l(m_usersMtx);
|
|
SCCPManagement::LocalBroadcast tmp = m_ssnStatus;
|
|
switch (m_ssnStatus) {
|
|
case SCCPManagement::UserOutOfService:
|
|
if (status == SCCPManagement::UserInService) {
|
|
m_ssnStatus = SCCPManagement::UserInService;
|
|
notify = true;
|
|
}
|
|
break;
|
|
case SCCPManagement::UserInService:
|
|
if (status == SCCPManagement::UserOutOfService) {
|
|
ListIterator it(m_users);
|
|
for (;;) {
|
|
TCAPUser* usr = static_cast<TCAPUser*>(it.get());
|
|
// End of iteration?
|
|
if (!usr) {
|
|
m_ssnStatus = SCCPManagement::UserOutOfService;
|
|
notify = true;
|
|
break;
|
|
}
|
|
if (usr->managementState() == (int) SCCPManagement::UserInService)
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (notify) {
|
|
sendSCCPNotify(params); // it always returns false, so no point in checking result
|
|
Debug(this,DebugInfo,"SSN=%d changed status from '%s' to '%s' [%p]",m_SSN,
|
|
lookup(tmp,SCCPManagement::broadcastType(),""),lookup(m_ssnStatus,SCCPManagement::broadcastType(),""),this);
|
|
}
|
|
}
|
|
|
|
bool SS7TCAP::sendSCCPNotify(NamedList& params)
|
|
{
|
|
params.setParam(YSTRING("subsystem-status"),lookup(m_ssnStatus,SCCPManagement::broadcastType(),""));
|
|
params.setParam(YSTRING("ssn"),String(m_SSN));
|
|
if (!params.getParam(YSTRING("smi")))
|
|
params.setParam("smi","0");
|
|
return sccpNotify(SCCP::StatusRequest,params);
|
|
}
|
|
|
|
void SS7TCAP::attach(TCAPUser* user)
|
|
{
|
|
if (!user)
|
|
return;
|
|
DDebug(this,DebugAll,"SS7TCAP::attach(user=%s [%p]) [%p]",user->toString().safe(),user,this);
|
|
Lock l(m_usersMtx);
|
|
if (m_users.find(user))
|
|
return;
|
|
m_users.append(user);
|
|
Debug(this,DebugAll,"SS7TCAP '%s'[%p] attached user=%s [%p]",toString().safe(),this,user->toString().safe(),user);
|
|
}
|
|
|
|
void SS7TCAP::detach(TCAPUser* user)
|
|
{
|
|
if (!user)
|
|
return;
|
|
DDebug(this,DebugAll,"SS7TCAP::detach(user=%s [%p]) [%p], refCount=%d",user->toString().safe(),user,this,refcount());
|
|
Lock l(m_usersMtx);
|
|
if (m_users.find(user)) {
|
|
m_users.remove(user,false);
|
|
Debug(this,DebugAll,"SS7TCAP '%s'[%p] detached user=%s [%p], refCount=%d",toString().safe(),this,user->toString().c_str(),user,refcount());
|
|
}
|
|
}
|
|
|
|
void SS7TCAP::enqueue(SS7TCAPMessage* msg)
|
|
{
|
|
if (!msg)
|
|
return;
|
|
Lock lock(m_inQueueMtx);
|
|
m_inQueue.append(msg);
|
|
XDebug(this,DebugAll,"SS7TCAP::enqueue(). Enqueued transaction wrapper (%p) [%p]",msg,this);
|
|
}
|
|
|
|
SS7TCAPMessage* SS7TCAP::dequeue()
|
|
{
|
|
Lock lock(m_inQueueMtx,SignallingEngine::maxLockWait());
|
|
if (!lock.locked())
|
|
return 0;
|
|
ObjList* obj = m_inQueue.skipNull();
|
|
if (!obj)
|
|
return 0;
|
|
SS7TCAPMessage* msg = static_cast<SS7TCAPMessage*>(obj->get());
|
|
m_inQueue.remove(msg,false);
|
|
XDebug(this,DebugAll,"SS7TCAP::dequeue(). Dequeued transaction wrapper (%p) [%p]",msg,this);
|
|
return msg;
|
|
}
|
|
|
|
void SS7TCAP::allocTransactionID(String& str)
|
|
{
|
|
u_int32_t tmp = m_idsPool;
|
|
m_idsPool++;
|
|
unsigned char buff[sizeof(tmp)];
|
|
int len = sizeof(tmp);
|
|
for (int index = len - 1; index >= 0; index--) {
|
|
buff[index] = tmp & 0xff;
|
|
tmp >>= 8;
|
|
}
|
|
str.hexify(buff,len,' ');
|
|
XDebug(this,DebugAll,"SS7TCAP::allocTransactionID() - allocated new transaction ID=%s [%p]",str.c_str(),this);
|
|
}
|
|
|
|
const String SS7TCAP::allocTransactionID()
|
|
{
|
|
String str;
|
|
allocTransactionID(str);
|
|
return str;
|
|
}
|
|
|
|
bool SS7TCAP::sendToUser(NamedList& params)
|
|
{
|
|
String userName = params.getValue(s_tcapUser,""); // if it has a specified user, send it to that user
|
|
Lock lock(m_usersMtx);
|
|
if (!userName.null()) {
|
|
ObjList* obj = m_users.find(userName);
|
|
if (!obj) {
|
|
Debug(this,DebugInfo,"SS7TCAP::sendToUser() [%p] - failed to send message with id=%s to user=%s,"
|
|
" no such application",this,params.getValue(s_tcapLocalTID),userName.c_str());
|
|
return false;
|
|
}
|
|
TCAPUser* user = static_cast<TCAPUser*>(obj->get());
|
|
if (!user) {
|
|
Debug(this,DebugInfo,"SS7TCAP::sendToUser() [%p] - failed to send message with id=%s to user,%s"
|
|
" no such application",this,params.getValue(s_tcapLocalTID),userName.c_str());
|
|
return false;
|
|
}
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && debugAt(DebugInfo))
|
|
dumpData(DebugInfo,this,"Sent to TCAP user: ",this,params);
|
|
#endif
|
|
return user->tcapIndication(params);
|
|
}
|
|
else {
|
|
ListIterator iter(m_users);
|
|
for (;;) {
|
|
TCAPUser* user = static_cast<TCAPUser*>(iter.get());
|
|
// End of iteration?
|
|
if (!user) {
|
|
Debug(this,DebugInfo,"SS7TCAP::sendToUser() [%p] - failed to send message with id=%s to any user",
|
|
this,params.getValue(s_tcapLocalTID));
|
|
return false;
|
|
}
|
|
if (user->tcapIndication(params)) {
|
|
params.setParam(s_tcapUser,user->toString()); // set the user for this transaction
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && debugAt(DebugInfo))
|
|
dumpData(DebugInfo,this,"Sent to TCAP user: ",this,params);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void SS7TCAP::status(NamedList& status)
|
|
{
|
|
status.setParam("totalIncoming",String(m_recvMsgs));
|
|
status.setParam("totalOutgoing",String(m_sentMsgs));
|
|
status.setParam("totalDiscarded",String(m_discardMsgs));
|
|
status.setParam("totalNormal",String(m_normalMsgs));
|
|
status.setParam("totalAbnormal",String(m_abnormalMsgs));
|
|
}
|
|
|
|
void SS7TCAP::userStatus(NamedList& status)
|
|
{
|
|
Debug(this,DebugStub,"Please implement SS7TCAP::userStatus()");
|
|
}
|
|
|
|
SS7TCAPTransaction* SS7TCAP::getTransaction(const String& tid)
|
|
{
|
|
SS7TCAPTransaction* tr = 0;
|
|
Lock lock(m_transactionsMtx);
|
|
ObjList* o = m_transactions.find(tid);
|
|
if (o)
|
|
tr = static_cast<SS7TCAPTransaction*>(o->get());
|
|
if (tr && tr->ref())
|
|
return tr;
|
|
return 0;
|
|
}
|
|
|
|
void SS7TCAP::removeTransaction(SS7TCAPTransaction* tr)
|
|
{
|
|
Lock lock(m_transactionsMtx);
|
|
m_transactions.remove(tr);
|
|
}
|
|
|
|
void SS7TCAP::timerTick(const Time& when)
|
|
{
|
|
// first check pending received messages
|
|
SS7TCAPMessage* msg = dequeue();
|
|
|
|
while (msg) {
|
|
processSCCPData(msg);
|
|
TelEngine::destruct(msg);
|
|
//break;
|
|
msg = dequeue();
|
|
}
|
|
|
|
// update/handle rest of transactions
|
|
Lock lock(m_transactionsMtx);
|
|
ListIterator iter(m_transactions);
|
|
for (;;) {
|
|
SS7TCAPTransaction* tr = static_cast<SS7TCAPTransaction*>(iter.get());
|
|
// End of iteration?
|
|
if (!tr)
|
|
break;
|
|
if (!tr->ref())
|
|
continue;
|
|
lock.drop();
|
|
NamedList params("");
|
|
DataBlock data;
|
|
if (tr->transactionState() != SS7TCAPTransaction::Idle)
|
|
tr->checkComponents();
|
|
if (tr->endNow())
|
|
tr->setState(SS7TCAPTransaction::Idle);
|
|
if (tr->timedOut()) {
|
|
DDebug(this,DebugInfo,"SS7TCAP::timerTick() - transaction with id=%s(%p) timed out [%p]",tr->toString().c_str(),tr,this);
|
|
tr->updateToEnd();
|
|
buildSCCPData(params,tr);
|
|
if (!tr->basicEnd())
|
|
tr->transactionData(params);
|
|
sendToUser(params);
|
|
tr->setState(SS7TCAPTransaction::Idle);
|
|
}
|
|
|
|
if (tr->transactionState() == SS7TCAPTransaction::Idle)
|
|
removeTransaction(tr);
|
|
TelEngine::destruct(tr);
|
|
if (!lock.acquire(m_transactionsMtx))
|
|
break;
|
|
}
|
|
}
|
|
|
|
HandledMSU SS7TCAP::processSCCPData(SS7TCAPMessage* msg)
|
|
{
|
|
HandledMSU result;
|
|
if (!msg)
|
|
return result;
|
|
XDebug(this,DebugAll,"SS7TCAP::processSCCPData(msg=[%p]) [%p]",msg,this);
|
|
|
|
NamedList& msgParams = msg->msgParams();
|
|
DataBlock& msgData = msg->msgData();
|
|
|
|
SS7TCAPError transactError = decodeTransactionPart(msgParams,msgData);
|
|
if (transactError.error() != SS7TCAPError::NoError)
|
|
return handleError(transactError,msgParams,msgData);
|
|
|
|
NamedString* trID = msgParams.getParam(s_tcapLocalTID);
|
|
String trType = msgParams.getValue(s_tcapRequest);
|
|
SS7TCAP::TCAPUserTransActions type = (SS7TCAP::TCAPUserTransActions)trType.toInteger(SS7TCAP::s_transPrimitives);
|
|
|
|
// check if it's a notice from SCCP, switch the ids if so
|
|
if (msg->isNotice()) {
|
|
trID = msgParams.getParam(s_tcapRemoteTID);
|
|
msgParams.setParam(s_tcapRemoteTID,msgParams.getValue(s_tcapLocalTID));
|
|
msgParams.setParam(s_tcapLocalTID,(TelEngine::null(trID) ? "" : *trID));
|
|
type = TC_Notice;
|
|
msgParams.setParam(s_tcapRequest,lookup(type,SS7TCAP::s_transPrimitives,"Notice"));
|
|
}
|
|
else
|
|
incCounter(SS7TCAP::IncomingMsgs);
|
|
|
|
SS7TCAPTransaction* tr = 0;
|
|
switch (type) {
|
|
case SS7TCAP::TC_Unidirectional:
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
// if there isn't a destination ID, allocate a new one and build a transaction
|
|
if (TelEngine::null(trID)) {
|
|
String newID;
|
|
allocTransactionID(newID);
|
|
tr = buildTransaction(type,newID,msgParams,false);
|
|
tr->ref();
|
|
m_transactionsMtx.lock();
|
|
m_transactions.append(tr);
|
|
m_transactionsMtx.unlock();
|
|
msgParams.setParam(s_tcapLocalTID,newID);
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_U_Abort:
|
|
case SS7TCAP::TC_Notice:
|
|
if (TelEngine::null(trID)) {
|
|
transactError.setError(SS7TCAPError::Transact_UnassignedTransactionID);
|
|
return handleError(transactError,msgParams,msgData);
|
|
}
|
|
tr = getTransaction(*trID);
|
|
if (!tr) {
|
|
transactError.setError(SS7TCAPError::Transact_UnassignedTransactionID);
|
|
return handleError(transactError,msgParams,msgData);
|
|
}
|
|
transactError = tr->update((SS7TCAP::TCAPUserTransActions)type,msgParams,false);
|
|
if (transactError.error() != SS7TCAPError::NoError) {
|
|
result = handleError(transactError,msgParams,msgData,tr);
|
|
TelEngine::destruct(tr);
|
|
return result;
|
|
}
|
|
break;
|
|
default:
|
|
incCounter(SS7TCAP::DiscardedMsgs);
|
|
return result;
|
|
}
|
|
if (tr) {
|
|
transactError = tr->handleData(msgParams,msgData);
|
|
if (transactError.error() != SS7TCAPError::NoError) {
|
|
result = handleError(transactError,msgParams,msgData,tr);
|
|
TelEngine::destruct(tr);
|
|
return result;
|
|
}
|
|
|
|
tr->addSCCPAddressing(msgParams,true);
|
|
tr->updateState(false);
|
|
if (sendToUser(msgParams)) {
|
|
tr->setUserName(msgParams.getValue(s_tcapUser));
|
|
tr->endNow(msgParams.getBoolValue(s_tcapEndNow,false));
|
|
|
|
if (tr->transactionType() == SS7TCAP::TC_Unidirectional
|
|
|| tr->transactionType() == SS7TCAP::TC_U_Abort
|
|
|| tr->transactionType() == SS7TCAP::TC_P_Abort
|
|
|| tr->transactionType() == SS7TCAP::TC_End
|
|
|| tr->transactionType() == SS7TCAP::TC_Response)
|
|
tr->setState(SS7TCAPTransaction::Idle);
|
|
else
|
|
tr->setTransmitState(SS7TCAPTransaction::Transmitted);
|
|
}
|
|
else if (type != SS7TCAP::TC_Notice) {
|
|
tr->update(SS7TCAP::TC_U_Abort,msgParams,false);
|
|
buildSCCPData(msgParams,tr);
|
|
tr->setTransmitState(SS7TCAPTransaction::Transmitted);
|
|
tr->updateState(false);
|
|
}
|
|
else
|
|
tr->setState(SS7TCAPTransaction::Idle);
|
|
TelEngine::destruct(tr);
|
|
}
|
|
result = HandledMSU::Accepted;
|
|
incCounter(SS7TCAP::NormalMsgs);
|
|
return result;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAP::userRequest(NamedList& params)
|
|
{
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && debugAt(DebugInfo))
|
|
dumpData(DebugInfo,this,"SS7TCAP::userRequest() - received request ",this,params);
|
|
#endif
|
|
|
|
NamedString* req = params.getParam(s_tcapRequest);
|
|
|
|
NamedString* otid = params.getParam(s_tcapLocalTID);
|
|
NamedString* user = params.getParam(s_tcapUser);
|
|
SS7TCAPError error(m_tcapType);
|
|
if (TelEngine::null(req)) {
|
|
Debug(this,DebugInfo,"SS7TCAP::userRequest()[%p] - received a transaction request from user=%s with originating ID=%s"
|
|
" without request type, rejecting it",this,(user ? user->c_str() : ""),(otid ? otid->c_str() : ""));
|
|
params.setParam(s_tcapRequestError,"missing_primitive");
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
|
|
SS7TCAPTransaction* tr = 0;
|
|
if (!TelEngine::null(req)) {
|
|
int type = req->toInteger(SS7TCAP::s_transPrimitives);
|
|
switch (type) {
|
|
case SS7TCAP::TC_Unidirectional:
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
// if otid not set, alloc one and set it
|
|
if (TelEngine::null(otid)) {
|
|
params.setParam(s_tcapLocalTID,allocTransactionID());
|
|
otid = params.getParam(s_tcapLocalTID);
|
|
}
|
|
else {
|
|
// if set, check if we already have it
|
|
tr = getTransaction(*otid);
|
|
if (tr) {
|
|
Debug(this,DebugInfo,"SS7TCAP::userRequest()[%p] - received a new transaction request from user=%s with originating ID=%s which is the ID "
|
|
"of an already existing transaction, rejecting the request",this,(user ? user->c_str() : ""),otid->c_str());
|
|
params.setParam(s_tcapRequestError,"allocated_id");
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
TelEngine::destruct(tr);
|
|
return error;
|
|
}
|
|
}
|
|
// create transaction
|
|
tr = buildTransaction((SS7TCAP::TCAPUserTransActions)type,otid,params,true);
|
|
if (!TelEngine::null(user))
|
|
tr->setUserName(user);
|
|
tr->ref();
|
|
m_transactionsMtx.lock();
|
|
m_transactions.append(tr);
|
|
m_transactionsMtx.unlock();
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
case SS7TCAP::TC_U_Abort:
|
|
// find transaction and update
|
|
if (!TelEngine::null(otid)) {
|
|
tr = getTransaction(*otid);
|
|
if (!tr) {
|
|
params.setParam(s_tcapRequestError,"unknown_transaction");
|
|
error.setError(SS7TCAPError::Transact_UnassignedTransactionID);
|
|
return error;
|
|
}
|
|
error = tr->update((SS7TCAP::TCAPUserTransActions)type,params);
|
|
if (error.error() != SS7TCAPError::NoError) {
|
|
TelEngine::destruct(tr);
|
|
return error;
|
|
}
|
|
}
|
|
else {
|
|
params.setParam(s_tcapRequestError,"need_transaction_id");
|
|
error.setError(SS7TCAPError::Transact_UnassignedTransactionID);
|
|
return error;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Unknown:
|
|
if (!TelEngine::null(otid))
|
|
tr = getTransaction(*otid);
|
|
break;
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_Notice:
|
|
default:
|
|
Debug(this,DebugAll,"SS7TCAP::userRequest() - received user request with unsuited primitive='%s' [%p]",req->c_str(),this);
|
|
params.setParam(s_tcapRequestError,"wrong_primitive");
|
|
error.setError(SS7TCAPError::Transact_UnrecognizedPackageType);
|
|
return error;
|
|
}
|
|
}
|
|
if (tr) {
|
|
error = tr->handleDialogPortion(params,true);
|
|
if (error.error() != SS7TCAPError::NoError) {
|
|
TelEngine::destruct(tr);
|
|
return error;
|
|
}
|
|
error = tr->handleComponents(params,true);
|
|
if (error.error() != SS7TCAPError::NoError) {
|
|
TelEngine::destruct(tr);
|
|
return error;
|
|
}
|
|
if (tr->transmitState() == SS7TCAPTransaction::PendingTransmit) {
|
|
tr->updateState(true);
|
|
buildSCCPData(params,tr);
|
|
tr->setTransmitState(SS7TCAPTransaction::Transmitted);
|
|
}
|
|
else if (tr->transmitState() == SS7TCAPTransaction::NoTransmit)
|
|
removeTransaction(tr);
|
|
TelEngine::destruct(tr);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAP::buildSCCPData(NamedList& params, SS7TCAPTransaction* tr)
|
|
{
|
|
if (!tr)
|
|
return;
|
|
DDebug(this,DebugAll,"SS7TCAP::buildSCCPData(tr=%p) for local transaction ID=%s [%p]",tr,tr->toString().c_str(),this);
|
|
|
|
Lock l(tr);
|
|
bool sendOk = true;
|
|
int type = tr->transactionType();
|
|
if (type == SS7TCAP::TC_End
|
|
|| type == TC_Response) {
|
|
if (!tr->basicEnd()) {
|
|
sendOk = false; // prearranged end, don't send to remote Transaction End message
|
|
Debug(this,DebugAll,"SS7TCAP::buildSCCPData(tr=%p) [%p] - transaction with id=%s has set prearranged end, won't be"
|
|
" sending anything to SCCP",tr,this,tr->toString().c_str());
|
|
}
|
|
}
|
|
|
|
if (sendOk) {
|
|
DataBlock data;
|
|
tr->requestContent(params,data);
|
|
tr->addSCCPAddressing(params,false);
|
|
encodeTransactionPart(params,data);
|
|
|
|
if (!sendData(data,params)) {
|
|
params.setParam("ReturnCause","Network failure");
|
|
enqueue(new SS7TCAPMessage(params,data,true));
|
|
Debug(this,DebugInfo,"SS7TCAP::buildSCCPData(tr=%p) [%p] - message for transaction with id=%s failed to be sent",
|
|
tr,this,tr->toString().c_str());
|
|
return;
|
|
};
|
|
incCounter(SS7TCAP::OutgoingMsgs);
|
|
}
|
|
}
|
|
|
|
HandledMSU SS7TCAP::handleError(SS7TCAPError& error, NamedList& params, DataBlock& data, SS7TCAPTransaction* tr)
|
|
{
|
|
Debug(this,DebugInfo,"SS7TCAP::handleError(error=%s) for transaction with id=%s(%p) [%p]",error.errorName().c_str(),
|
|
(tr ? tr->toString().c_str() : "unknown"),tr,this);
|
|
HandledMSU result = HandledMSU::Accepted;
|
|
|
|
int type = lookup(params.getValue(s_tcapRequest,""),SS7TCAP::s_transPrimitives);
|
|
NamedString* rtid = params.getParam(s_tcapRemoteTID);
|
|
NamedString* ltid = params.getParam(s_tcapLocalTID);
|
|
bool buildRemAbort = false;
|
|
bool buildLocAbort = false;
|
|
switch (type) {
|
|
case SS7TCAP::TC_Unidirectional:
|
|
incCounter(SS7TCAP::DiscardedMsgs);
|
|
return result; // return with rejected, meaning Discarded
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
if (!TelEngine::null(rtid))
|
|
buildRemAbort = true;
|
|
else {
|
|
// no originating ID, we don't know to whom to send the Abort, meaning we'll discard the message
|
|
incCounter(SS7TCAP::DiscardedMsgs);
|
|
return result;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
if (TelEngine::null(rtid) && TelEngine::null(ltid)) {
|
|
incCounter(SS7TCAP::DiscardedMsgs);
|
|
return result;
|
|
}
|
|
if (!TelEngine::null(rtid)) {
|
|
buildRemAbort = true;
|
|
if (!TelEngine::null(ltid))
|
|
buildLocAbort = true;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_U_Abort:
|
|
if (TelEngine::null(ltid)) {
|
|
incCounter(SS7TCAP::DiscardedMsgs);
|
|
return result;
|
|
}
|
|
else
|
|
buildLocAbort = true;
|
|
break;
|
|
default:
|
|
if (!TelEngine::null(rtid)) {
|
|
buildRemAbort = true;
|
|
if (!TelEngine::null(ltid))
|
|
buildLocAbort = true;
|
|
}
|
|
else {
|
|
incCounter(SS7TCAP::DiscardedMsgs);
|
|
return result;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (buildLocAbort && !TelEngine::null(ltid)) { // notify user of the abort
|
|
params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_P_Abort,SS7TCAP:: s_transPrimitives));
|
|
params.setParam(s_tcapAbortCause,"pAbort");
|
|
params.setParam(s_tcapAbortInfo,String(error.error()));
|
|
if (tr) {
|
|
tr->update(SS7TCAP::TC_P_Abort,params,false);
|
|
tr->updateState();
|
|
}
|
|
sendToUser(params);
|
|
}
|
|
if (buildRemAbort) {
|
|
// clean dataBlock
|
|
data.clear();
|
|
|
|
if (!TelEngine::null(rtid)) { // we have the remote ID, notify of abort
|
|
NamedList addr("");
|
|
populateSCCPAddress(addr,addr,params,false,true);
|
|
params.copyParams(addr);
|
|
|
|
if (error.error() != SS7TCAPError::Dialog_Abnormal) {
|
|
params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_P_Abort,SS7TCAP::s_transPrimitives));
|
|
params.setParam(s_tcapAbortCause,"pAbort");
|
|
params.setParam(s_tcapAbortInfo,String(error.error()));
|
|
}
|
|
else if (tr)
|
|
tr->abnormalDialogInfo(params);
|
|
|
|
if (tcapType() == ANSITCAP)
|
|
SS7TCAPTransactionANSI::encodePAbort(tr,params,data);
|
|
else if (tcapType() == ITUTCAP)
|
|
SS7TCAPTransactionITU::encodePAbort(tr,params,data);
|
|
|
|
encodeTransactionPart(params,data);
|
|
sendData(data,params);
|
|
}
|
|
}
|
|
if (buildRemAbort || buildLocAbort) {
|
|
incCounter(SS7TCAP::AbnormalMsgs);
|
|
result = HandledMSU::Accepted;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* SS7TCAPError implementation
|
|
*/
|
|
struct TCAPError {
|
|
SS7TCAPError::ErrorType errorType;
|
|
u_int16_t errorCode;
|
|
};
|
|
|
|
static const TCAPError s_ansiErrorDefs[] = {
|
|
// error fullcode
|
|
{ SS7TCAPError::Transact_UnrecognizedPackageType, 0x01},
|
|
{ SS7TCAPError::Transact_IncorrectTransactionPortion, 0x02},
|
|
{ SS7TCAPError::Transact_BadlyStructuredTransaction, 0x03},
|
|
{ SS7TCAPError::Transact_UnassignedTransactionID, 0x04},
|
|
{ SS7TCAPError::Transact_PermissionToReleaseProblem, 0x05},
|
|
{ SS7TCAPError::Transact_ResourceUnavailable, 0x06},
|
|
|
|
{ SS7TCAPError::Dialog_UnrecognizedDialoguePortionID, 0x07},
|
|
{ SS7TCAPError::Dialog_BadlyStructuredDialoguePortion, 0x08},
|
|
{ SS7TCAPError::Dialog_MissingDialoguePortion, 0x09},
|
|
{ SS7TCAPError::Dialog_InconsistentDialoguePortion, 0x0a},
|
|
|
|
// GeneralProblem
|
|
{ SS7TCAPError::General_UnrecognizedComponentType, 0x101},
|
|
{ SS7TCAPError::General_IncorrectComponentPortion, 0x102},
|
|
{ SS7TCAPError::General_BadlyStructuredCompPortion, 0x103},
|
|
{ SS7TCAPError::General_IncorrectComponentCoding, 0x104},
|
|
|
|
// InvokeProblem
|
|
{ SS7TCAPError::Invoke_DuplicateInvokeID, 0x201},
|
|
{ SS7TCAPError::Invoke_UnrecognizedOperationCode, 0x202},
|
|
{ SS7TCAPError::Invoke_IncorrectParameter, 0x203},
|
|
{ SS7TCAPError::Invoke_UnrecognizedCorrelationID, 0x204},
|
|
|
|
// ReturnResult
|
|
{ SS7TCAPError::Result_UnrecognisedCorrelationID, 0x301},
|
|
{ SS7TCAPError::Result_UnexpectedReturnResult, 0x302},
|
|
{ SS7TCAPError::Result_IncorrectParameter, 0x303},
|
|
|
|
// ReturnError
|
|
{ SS7TCAPError::Error_UnrecognisedCorrelationID, 0x401},
|
|
{ SS7TCAPError::Error_UnexpectedReturnError, 0x402},
|
|
{ SS7TCAPError::Error_UnrecognisedError, 0x403},
|
|
{ SS7TCAPError::Error_UnexpectedError, 0x404},
|
|
{ SS7TCAPError::Error_IncorrectParameter, 0x405},
|
|
|
|
{ SS7TCAPError::NoError, 0xfff},
|
|
};
|
|
|
|
static const TCAPError s_ituErrorDefs[] = {
|
|
// error fullcode
|
|
{ SS7TCAPError::Transact_UnrecognizedPackageType, 0x00},
|
|
{ SS7TCAPError::Transact_UnassignedTransactionID, 0x01},
|
|
{ SS7TCAPError::Transact_BadlyStructuredTransaction, 0x02},
|
|
{ SS7TCAPError::Transact_IncorrectTransactionPortion, 0x03},
|
|
{ SS7TCAPError::Transact_ResourceUnavailable, 0x04},
|
|
|
|
{ SS7TCAPError::Dialog_Abnormal, 0x7000},
|
|
|
|
// GeneralProblem
|
|
{ SS7TCAPError::General_UnrecognizedComponentType, 0x8000},
|
|
{ SS7TCAPError::General_IncorrectComponentPortion, 0x8001},
|
|
{ SS7TCAPError::General_BadlyStructuredCompPortion, 0x8002},
|
|
|
|
// InvokeProblem
|
|
{ SS7TCAPError::Invoke_DuplicateInvokeID, 0x8100},
|
|
{ SS7TCAPError::Invoke_UnrecognizedOperationCode, 0x8101},
|
|
{ SS7TCAPError::Invoke_IncorrectParameter, 0x8102},
|
|
{ SS7TCAPError::Invoke_UnrecognizedCorrelationID, 0x8105},
|
|
{ SS7TCAPError::Invoke_ResourceLimitation, 0x8103},
|
|
{ SS7TCAPError::Invoke_InitiatingRelease, 0x8104},
|
|
{ SS7TCAPError::Invoke_LinkedResponseUnexpected, 0x8106},
|
|
{ SS7TCAPError::Invoke_UnexpectedLinkedOperation, 0x8107},
|
|
|
|
// ReturnResult
|
|
{ SS7TCAPError::Result_UnrecognizedInvokeID, 0x8200},
|
|
{ SS7TCAPError::Result_UnexpectedReturnResult, 0x8201},
|
|
{ SS7TCAPError::Result_IncorrectParameter, 0x8202},
|
|
|
|
// ReturnError
|
|
{ SS7TCAPError::Error_UnrecognizedInvokeID, 0x8300},
|
|
{ SS7TCAPError::Error_UnexpectedReturnError, 0x8301},
|
|
{ SS7TCAPError::Error_UnrecognisedError, 0x8302},
|
|
{ SS7TCAPError::Error_UnexpectedError, 0x8303},
|
|
{ SS7TCAPError::Error_IncorrectParameter, 0x8304},
|
|
|
|
{ SS7TCAPError::NoError, 0xffff},
|
|
};
|
|
|
|
const TokenDict SS7TCAPError::s_errorTypes[] = {
|
|
{"Transact-UnrecognizedPackageType", SS7TCAPError::Transact_UnrecognizedPackageType},
|
|
{"Transact-IncorrectTransactionPortion", SS7TCAPError::Transact_IncorrectTransactionPortion},
|
|
{"Transact-BadlyStructuredTransaction", SS7TCAPError::Transact_BadlyStructuredTransaction},
|
|
{"Transact-UnassignedTransactionID", SS7TCAPError::Transact_UnassignedTransactionID },
|
|
{"Transact-PermissionToReleaseProblem", SS7TCAPError::Transact_PermissionToReleaseProblem},
|
|
{"Transact-ResourceUnavailable", SS7TCAPError::Transact_ResourceUnavailable},
|
|
|
|
{"Dialog-UnrecognizedDialoguePortionID", SS7TCAPError::Dialog_UnrecognizedDialoguePortionID},
|
|
{"Dialog-BadlyStructuredDialoguePortion", SS7TCAPError::Dialog_BadlyStructuredDialoguePortion},
|
|
{"Dialog-MissingDialoguePortion", SS7TCAPError::Dialog_MissingDialoguePortion},
|
|
{"Dialog-InconsistentDialoguePortion", SS7TCAPError::Dialog_InconsistentDialoguePortion},
|
|
{"Dialog-Abnormal", SS7TCAPError::Dialog_Abnormal},
|
|
|
|
{"General-UnrecognizedComponentType", SS7TCAPError::General_UnrecognizedComponentType},
|
|
{"General-IncorrectComponentPortion", SS7TCAPError::General_IncorrectComponentPortion},
|
|
{"General-BadlyStructuredCompPortion", SS7TCAPError::General_BadlyStructuredCompPortion},
|
|
{"General-IncorrectComponentCoding", SS7TCAPError::General_IncorrectComponentCoding},
|
|
|
|
{"Invoke-DuplicateInvokeID", SS7TCAPError::Invoke_DuplicateInvokeID},
|
|
{"Invoke-UnrecognizedOperationCode", SS7TCAPError::Invoke_UnrecognizedOperationCode},
|
|
{"Invoke-IncorrectParameter", SS7TCAPError::Invoke_IncorrectParameter},
|
|
{"Invoke-UnrecognizedCorrelationID", SS7TCAPError::Invoke_UnrecognizedCorrelationID},
|
|
{"Invoke-ResourceLimitation", SS7TCAPError::Invoke_ResourceLimitation},
|
|
{"Invoke-InitiatingRelease", SS7TCAPError::Invoke_InitiatingRelease},
|
|
{"Invoke-LinkedResponseUnexpected", SS7TCAPError::Invoke_LinkedResponseUnexpected},
|
|
{"Invoke-UnexpectedLinkedOperation", SS7TCAPError::Invoke_UnexpectedLinkedOperation},
|
|
|
|
{"Result-UnrecognizedInvokeID", SS7TCAPError::Result_UnrecognizedInvokeID},
|
|
{"Result-UnrecognisedCorrelationID", SS7TCAPError::Result_UnrecognisedCorrelationID},
|
|
{"Result-UnexpectedReturnResult", SS7TCAPError::Result_UnexpectedReturnResult},
|
|
{"Result-IncorrectParameter", SS7TCAPError::Result_IncorrectParameter},
|
|
|
|
{"Error-UnrecognizedInvokeID", SS7TCAPError::Error_UnrecognizedInvokeID},
|
|
{"Error-UnrecognisedCorrelationID", SS7TCAPError::Error_UnrecognisedCorrelationID},
|
|
{"Error-UnexpectedReturnError", SS7TCAPError::Error_UnexpectedReturnError},
|
|
{"Error-UnrecognisedError", SS7TCAPError::Error_UnrecognisedError},
|
|
{"Error-UnexpectedError", SS7TCAPError::Error_UnexpectedError},
|
|
{"Error-IncorrectParameter", SS7TCAPError::Error_IncorrectParameter},
|
|
|
|
{"NoError", SS7TCAPError::NoError},
|
|
{0,0},
|
|
};
|
|
|
|
SS7TCAPError::SS7TCAPError(SS7TCAP::TCAPType tcapType)
|
|
: m_tcapType(tcapType), m_error(SS7TCAPError::NoError)
|
|
{
|
|
}
|
|
|
|
SS7TCAPError::SS7TCAPError(SS7TCAP::TCAPType tcapType, ErrorType error)
|
|
: m_tcapType(tcapType), m_error(error)
|
|
{
|
|
XDebug(DebugAll,"SS7TCAPError created TCAP=%s with error=%s [%p]",lookup(tcapType,SS7TCAP::s_tcapVersion),
|
|
lookup(error,s_errorTypes),this);
|
|
}
|
|
|
|
SS7TCAPError::~SS7TCAPError()
|
|
{
|
|
}
|
|
|
|
const String SS7TCAPError::errorName()
|
|
{
|
|
return lookup(m_error,s_errorTypes,"NoError");
|
|
}
|
|
|
|
u_int16_t SS7TCAPError::errorCode()
|
|
{
|
|
const TCAPError* errDef = (m_tcapType == SS7TCAP::ANSITCAP ? s_ansiErrorDefs : s_ituErrorDefs);
|
|
for (;errDef && errDef->errorType != SS7TCAPError::NoError; errDef++) {
|
|
if (errDef->errorType == m_error)
|
|
break;
|
|
}
|
|
return errDef->errorCode;
|
|
}
|
|
|
|
int SS7TCAPError::errorFromCode(SS7TCAP::TCAPType tcapType, u_int16_t code)
|
|
{
|
|
const TCAPError* errDef = (tcapType == SS7TCAP::ANSITCAP ? s_ansiErrorDefs : s_ituErrorDefs);
|
|
for (;errDef && errDef->errorType != SS7TCAPError::NoError; errDef++) {
|
|
if (errDef->errorCode == code)
|
|
break;
|
|
}
|
|
return errDef->errorType;
|
|
}
|
|
|
|
u_int16_t SS7TCAPError::codeFromError(SS7TCAP::TCAPType tcapType, int err)
|
|
{
|
|
const TCAPError* errDef = (tcapType == SS7TCAP::ANSITCAP ? s_ansiErrorDefs : s_ituErrorDefs);
|
|
for (;errDef && errDef->errorType != SS7TCAPError::NoError; errDef++) {
|
|
if (errDef->errorType == err)
|
|
break;
|
|
}
|
|
return errDef->errorCode;
|
|
}
|
|
|
|
/**
|
|
* SS7TCAPTransaction
|
|
*/
|
|
SS7TCAPTransaction::SS7TCAPTransaction(SS7TCAP* tcap, SS7TCAP::TCAPUserTransActions type,
|
|
const String& transactID, NamedList& params, u_int64_t timeout, bool initLocal)
|
|
: Mutex(true,"TcapTransaction"),
|
|
m_tcap(tcap), m_tcapType(SS7TCAP::UnknownTCAP), m_userName(""), m_localID(transactID), m_type(type),
|
|
m_localSCCPAddr(""), m_remoteSCCPAddr(""), m_basicEnd(true), m_endNow(false), m_timeout(timeout)
|
|
{
|
|
|
|
DDebug(m_tcap,DebugAll,"SS7TCAPTransaction(tcap = '%s' [%p], transactID = %s) created [%p]",
|
|
m_tcap->toString().c_str(),tcap,transactID.c_str(),this);
|
|
|
|
m_remoteID = params.getValue(s_tcapRemoteTID);
|
|
populateSCCPAddress(m_localSCCPAddr,m_remoteSCCPAddr,params,initLocal,false);
|
|
m_endNow = params.getBoolValue(s_tcapEndNow,false);
|
|
if (initLocal)
|
|
setState(PackageSent);
|
|
else
|
|
setState(PackageReceived);
|
|
}
|
|
|
|
SS7TCAPTransaction::~SS7TCAPTransaction()
|
|
{
|
|
DDebug(tcap(),DebugAll,"Transaction with ID=%s of user=%s destroyed [%p]",
|
|
m_localID.c_str(),m_userName.c_str(),this);
|
|
m_components.clear();
|
|
m_tcap = 0;
|
|
}
|
|
|
|
SS7TCAPComponent* SS7TCAPTransaction::findComponent(const String& id)
|
|
{
|
|
SS7TCAPComponent* comp = 0;
|
|
ObjList* o = m_components.find(id);
|
|
if (o)
|
|
comp = static_cast<SS7TCAPComponent*>(o->get());
|
|
return comp;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransaction::update(SS7TCAP::TCAPUserTransActions type, NamedList& params, bool updateByUser)
|
|
{
|
|
DDebug(tcap(),DebugStub,"SS7TCAPTransaction::update() [%p], localID=%s - stub",this,m_localID.c_str());
|
|
SS7TCAPError error(m_tcapType);
|
|
return error;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransaction::buildComponentError(SS7TCAPError& error, NamedList& params, DataBlock& data)
|
|
{
|
|
if (error.error() == SS7TCAPError::NoError)
|
|
return error;
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransaction::buildComponentError(error=%s) for transaction with id=%s [%p]",error.errorName().c_str(),
|
|
toString().c_str(),this);
|
|
int compCount = params.getIntValue(s_tcapCompCount,1);
|
|
|
|
if (!compCount)
|
|
return error;
|
|
|
|
String param;
|
|
compPrefix(param,compCount,true);
|
|
bool buildRej = false;
|
|
NamedString* typeStr = params.getParam(param + s_tcapCompType);
|
|
if (TelEngine::null(typeStr))
|
|
buildRej = true;
|
|
else {
|
|
int type = typeStr->toInteger(SS7TCAP::s_compPrimitives);
|
|
NamedString* invokeID = params.getParam(param + s_tcapRemoteCID);
|
|
|
|
switch (type) {
|
|
case SS7TCAP::TC_ResultLast:
|
|
case SS7TCAP::TC_ResultNotLast:
|
|
case SS7TCAP::TC_U_Error:
|
|
if (!TelEngine::null(invokeID)) {
|
|
SS7TCAPComponent* comp = findComponent(*invokeID);
|
|
if (comp)
|
|
m_components.remove(comp);
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Invoke:
|
|
case SS7TCAP::TC_R_Reject:
|
|
default:
|
|
break;
|
|
}
|
|
buildRej = true;
|
|
}
|
|
|
|
params.setParam(param + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives,"L_Reject"));
|
|
params.setParam(param + s_tcapProblemCode,String(error.error()));
|
|
if (buildRej) {
|
|
SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,compCount);
|
|
if (comp)
|
|
m_components.append(comp);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransaction::handleComponents(NamedList& params, bool updateByUser)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransaction::handleComponents(updateByUser=%s) [%p]",String::boolText(updateByUser),this);
|
|
int count = params.getIntValue(s_tcapCompCount,0);
|
|
SS7TCAPError error(m_tcapType);
|
|
if (!count)
|
|
return error;
|
|
int index = 0;
|
|
Lock l(this);
|
|
while (index < count) {
|
|
index++;
|
|
String paramRoot;
|
|
compPrefix(paramRoot,index,true);
|
|
|
|
NamedString* localCID = params.getParam(paramRoot + s_tcapLocalCID);
|
|
NamedString* typeStr = params.getParam(paramRoot + s_tcapCompType);
|
|
if (TelEngine::null(typeStr))
|
|
continue;
|
|
int type = typeStr->toInteger(SS7TCAP::s_compPrimitives);
|
|
switch (type) {
|
|
case SS7TCAP::TC_Invoke:
|
|
case SS7TCAP::TC_InvokeNotLast:
|
|
if (!updateByUser) {
|
|
if (!TelEngine::null(localCID)) {
|
|
// we have a linked/correlation ID, check the state of that component
|
|
SS7TCAPComponent* linkedTo = findComponent(*localCID);
|
|
if (!linkedTo) {
|
|
type = SS7TCAP::TC_L_Reject;
|
|
params.setParam(paramRoot + s_tcapProblemCode,String(SS7TCAPError::Invoke_UnrecognizedCorrelationID));
|
|
}
|
|
else {
|
|
if (linkedTo->state() != SS7TCAPComponent::OperationSent) {
|
|
type = SS7TCAP::TC_L_Reject;
|
|
params.setParam(paramRoot + s_tcapProblemCode,String(SS7TCAPError::Invoke_UnexpectedLinkedOperation));
|
|
}
|
|
}
|
|
}
|
|
if (type == SS7TCAP::TC_L_Reject) {
|
|
params.setParam(paramRoot + s_tcapCompType,lookup(type,SS7TCAP::s_compPrimitives,"L_Reject"));
|
|
SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,index);
|
|
if (comp)
|
|
m_components.append(comp);
|
|
}
|
|
}
|
|
else {
|
|
if (!TelEngine::null(localCID)) {
|
|
if (findComponent(*localCID)) {
|
|
error.setError(SS7TCAPError::Invoke_DuplicateInvokeID);
|
|
return error;
|
|
}
|
|
else {
|
|
SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,index);
|
|
if (comp) {
|
|
m_components.append(comp);
|
|
comp->setState(SS7TCAPComponent::OperationSent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_ResultLast:
|
|
case SS7TCAP::TC_ResultNotLast:
|
|
case SS7TCAP::TC_U_Error:
|
|
if (!updateByUser) {
|
|
if (!TelEngine::null(localCID)) {
|
|
SS7TCAPComponent* comp = findComponent(*localCID);
|
|
if (comp)
|
|
comp->update(params,index);
|
|
else {
|
|
params.setParam(paramRoot + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives,"L_Reject"));
|
|
params.setParam(paramRoot + s_tcapProblemCode,String(SS7TCAPError::Invoke_UnexpectedLinkedOperation));
|
|
SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,index);
|
|
if (comp)
|
|
m_components.append(comp);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_R_Reject:
|
|
case SS7TCAP::TC_U_Reject:
|
|
if (!updateByUser) {
|
|
params.setParam(paramRoot + s_tcapCompType,lookup(SS7TCAP::TC_R_Reject,SS7TCAP::s_compPrimitives,"R_Reject"));
|
|
if (!TelEngine::null(localCID)) {
|
|
SS7TCAPComponent* comp = findComponent(*localCID);
|
|
if (comp)
|
|
m_components.remove(comp);
|
|
}
|
|
}
|
|
else if (!TelEngine::null(localCID)) {
|
|
m_components.remove(*localCID);
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_L_Reject:
|
|
case SS7TCAP::TC_U_Cancel:
|
|
if (updateByUser) {
|
|
if (!TelEngine::null(localCID))
|
|
m_components.remove(*localCID);
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_TimerReset:
|
|
if (updateByUser && !TelEngine::null(localCID) && m_tcapType == SS7TCAP::ITUTCAP) {
|
|
SS7TCAPComponent* comp = findComponent(*localCID);
|
|
if (comp)
|
|
comp->resetTimer(params,index);
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_L_Cancel:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransaction::handleComponents() - transaction with localID=%s handled %d components [%p]",
|
|
m_localID.c_str(),index,this);
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransaction::requestComponents(NamedList& params, DataBlock& data)
|
|
{
|
|
Lock(this);
|
|
unsigned int index = params.getIntValue(s_tcapCompCount);
|
|
for (ObjList* o = m_components.skipNull(); o; o = o->skipNext()) {
|
|
SS7TCAPComponent* comp = static_cast<SS7TCAPComponent*>(o->get());
|
|
if (comp && comp->state() == SS7TCAPComponent::OperationPending) {
|
|
index++;
|
|
comp->fill(index,params);
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransaction::requestComponents() preparing to encode components:",this,params,data);
|
|
#endif
|
|
params.setParam(s_tcapCompCount,String(index));
|
|
encodeComponents(params,data);
|
|
#ifdef DEBUG
|
|
if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransaction::requestComponents() encoded components'",this,params,data);
|
|
#endif
|
|
}
|
|
|
|
void SS7TCAPTransaction::transactionData(NamedList& params)
|
|
{
|
|
Lock l(this);
|
|
params.setParam(s_tcapRequest,lookup(m_type,SS7TCAP::s_transPrimitives));
|
|
params.setParam(s_tcapLocalTID,m_localID);
|
|
params.setParam(s_tcapRemoteTID,m_remoteID);
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransaction::transactionData() - added transaction data",this,params);
|
|
#endif
|
|
}
|
|
|
|
void SS7TCAPTransaction::checkComponents()
|
|
{
|
|
NamedList params("");
|
|
int index = 0;
|
|
Lock l(this);
|
|
ListIterator iter(m_components);
|
|
for (;;) {
|
|
SS7TCAPComponent* comp = static_cast<SS7TCAPComponent*>(iter.get());
|
|
if (!comp)
|
|
break;
|
|
if (comp->timedOut()) {
|
|
XDebug(tcap(),DebugInfo,"SS7TCAPTransaction::checkComponents() - component with local ID = %s timed out in"
|
|
" transaction with local ID = %s [%p]",comp->toString().c_str(),toString().c_str(),this);
|
|
SS7TCAP::TCAPUserCompActions type = comp->type();
|
|
String paramRoot = "";
|
|
switch (type) {
|
|
case SS7TCAP::TC_Invoke:
|
|
case SS7TCAP::TC_InvokeNotLast:
|
|
if (comp->operationClass() != SS7TCAP::NoReport) {
|
|
index++;
|
|
comp->setType(SS7TCAP::TC_L_Cancel);
|
|
comp->fill(index,params);
|
|
}
|
|
comp->setState(SS7TCAPComponent::Idle);
|
|
break;
|
|
case SS7TCAP::TC_ResultLast:
|
|
case SS7TCAP::TC_U_Error:
|
|
comp->setState(SS7TCAPComponent::Idle);
|
|
break;
|
|
case SS7TCAP::TC_ResultNotLast:
|
|
case SS7TCAP::TC_U_Reject:
|
|
case SS7TCAP::TC_L_Reject:
|
|
case SS7TCAP::TC_R_Reject:
|
|
case SS7TCAP::TC_L_Cancel:
|
|
case SS7TCAP::TC_U_Cancel:
|
|
case SS7TCAP::TC_TimerReset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (comp->state() == SS7TCAPComponent::Idle)
|
|
m_components.remove(comp);
|
|
}
|
|
if (params.count()) {
|
|
params.setParam(s_tcapCompCount,String(index));
|
|
transactionData(params);
|
|
params.clearParam(s_tcapRequest);
|
|
tcap()->sendToUser(params);
|
|
}
|
|
if (m_components.count() == 0) {// we don't have any more components
|
|
if (!m_timeout.started()) {
|
|
m_timeout.start();
|
|
XDebug(tcap(),DebugInfo,"SS7TCAPTransaction::checkComponents() - timer for transaction with localID=%s has been started [%p]",
|
|
toString().c_str(),this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SS7TCAPTransaction::setTransmitState(TransactionTransmit state)
|
|
{
|
|
Lock l(this);
|
|
m_transmit = state;
|
|
if (m_transmit == Transmitted) {
|
|
switch (m_type) {
|
|
case SS7TCAP::TC_Unidirectional:
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_U_Abort:
|
|
case SS7TCAP::TC_Response:
|
|
case SS7TCAP::TC_End:
|
|
m_state = Idle;
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SS7TCAPTransaction::addSCCPAddressing(NamedList& fillParams, bool local)
|
|
{
|
|
String localParam(local ? s_calledPA : s_callingPA);
|
|
String remoteParam(local ? s_callingPA : s_calledPA);
|
|
fillParams.clearParam(s_calledPA,'.');
|
|
fillParams.clearParam(s_callingPA,'.');
|
|
Lock l(this);
|
|
fillParams.copyParam(m_localSCCPAddr,s_localPC);
|
|
for (unsigned int i = 0; i < m_localSCCPAddr.count(); i++) {
|
|
NamedString* ns = m_localSCCPAddr.getParam(i);
|
|
if (ns && *ns && !(*ns).null()) {
|
|
const String& name = ns->name();
|
|
if (name != s_localPC)
|
|
fillParams.setParam(localParam + "." + name,*ns);
|
|
}
|
|
}
|
|
fillParams.copyParam(m_remoteSCCPAddr,s_remotePC);
|
|
for (unsigned int i = 0; i < m_remoteSCCPAddr.count(); i++) {
|
|
NamedString* ns = m_remoteSCCPAddr.getParam(i);
|
|
if (ns && *ns && !(*ns).null()) {
|
|
const String& name = ns->name();
|
|
if (name != s_remotePC)
|
|
fillParams.setParam(remoteParam + "." + name,*ns);
|
|
}
|
|
}
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransaction::handleData(NamedList& params, DataBlock& data)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransaction::handleData() transactionID=%s data length=%u [%p]",m_localID.c_str(),
|
|
data.length(),this);
|
|
Lock lock(this);
|
|
// in case of Abort message, check Cause Information
|
|
SS7TCAPError error(m_tcapType);
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransaction::updateToEnd()
|
|
{
|
|
}
|
|
|
|
void SS7TCAPTransaction::abnormalDialogInfo(NamedList& params)
|
|
{
|
|
Debug(tcap(),DebugAll,"SS7TCAPTransaction::abnormalDialogInfo() [%p]",this);
|
|
}
|
|
|
|
/**
|
|
* SS7TCAPComponent
|
|
*/
|
|
const TokenDict SS7TCAPComponent::s_compStates[] = {
|
|
{"Idle", SS7TCAPComponent::Idle},
|
|
{"OperationPending", SS7TCAPComponent::OperationPending},
|
|
{"OperationSent", SS7TCAPComponent::OperationSent},
|
|
{"WaitForReject", SS7TCAPComponent::WaitForReject},
|
|
};
|
|
|
|
SS7TCAPComponent::SS7TCAPComponent(SS7TCAP::TCAPType type, SS7TCAPTransaction* trans, NamedList& params, unsigned int index)
|
|
: m_transact(trans), m_state(Idle),
|
|
m_id(""), m_corrID(""), m_opClass(SS7TCAP::SuccessOrFailureReport), m_opTimer(0), m_error(type)
|
|
{
|
|
String paramRoot;
|
|
compPrefix(paramRoot,index,true);
|
|
|
|
m_type = (SS7TCAP::TCAPUserCompActions) lookup(params.getValue(paramRoot + s_tcapCompType),SS7TCAP::s_compPrimitives);
|
|
m_id = params.getValue(paramRoot + s_tcapLocalCID);
|
|
m_corrID = params.getValue(paramRoot + s_tcapRemoteCID);
|
|
|
|
setState(OperationPending);
|
|
|
|
m_opType = params.getValue(paramRoot + s_tcapOpCodeType,"");
|
|
m_opCode = params.getValue(paramRoot + s_tcapOpCode,"");
|
|
NamedString* opClass = params.getParam(paramRoot + "operationClass");
|
|
if (!TelEngine::null(opClass))
|
|
m_opClass = (SS7TCAP::TCAPComponentOperationClass) opClass->toInteger(SS7TCAP::s_compOperClasses,SS7TCAP::SuccessOrFailureReport);
|
|
m_opTimer.interval(params.getIntValue(paramRoot + "timeout",5) * 1000);
|
|
|
|
m_error.setError((SS7TCAPError::ErrorType)params.getIntValue(paramRoot + s_tcapProblemCode));
|
|
|
|
DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent() [%p] created for transaction='%s' [%p] with localID=%s, remoteID=%s,"
|
|
" type=%s, class=%s",this, (m_transact ? m_transact->toString().c_str() :""),m_transact,m_id.c_str(),
|
|
m_corrID.c_str(),lookup(m_type,SS7TCAP::s_compPrimitives),lookup(m_opClass,SS7TCAP::s_compOperClasses));
|
|
}
|
|
|
|
SS7TCAPComponent::~SS7TCAPComponent()
|
|
{
|
|
DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::~SS7TCAPComponent() - component [%p] destroyed",this);
|
|
m_transact = 0;
|
|
}
|
|
|
|
void SS7TCAPComponent::update(NamedList& params, unsigned int index)
|
|
{
|
|
String paramRoot;
|
|
compPrefix(paramRoot,index,false);
|
|
DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::update() - update component with localID=%s [%p]",m_id.c_str(),this);
|
|
|
|
m_type = (SS7TCAP::TCAPUserCompActions) lookup(params.getValue(paramRoot + "." + s_tcapCompType),SS7TCAP::s_compPrimitives);
|
|
switch (m_type) {
|
|
case SS7TCAP::TC_ResultLast:
|
|
if (m_opClass == SS7TCAP::SuccessOrFailureReport || m_opClass == SS7TCAP::SuccessOnlyReport)
|
|
setState(WaitForReject);
|
|
else if (m_opClass == SS7TCAP::FailureOnlyReport || m_opClass == SS7TCAP::NoReport) {
|
|
// build reject component
|
|
m_type = SS7TCAP::TC_L_Reject;
|
|
params.setParam(paramRoot + "." + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives));
|
|
params.setParam(paramRoot + "." + s_tcapProblemCode,String(SS7TCAPError::Result_UnexpectedReturnResult));
|
|
m_error.setError(SS7TCAPError::Result_UnexpectedReturnResult);
|
|
setState(OperationPending);
|
|
return;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_ResultNotLast:
|
|
if (m_opClass == SS7TCAP::FailureOnlyReport || m_opClass == SS7TCAP::NoReport) {
|
|
// build reject component
|
|
m_type = SS7TCAP::TC_L_Reject;
|
|
params.setParam(paramRoot + "." + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives));
|
|
params.setParam(paramRoot + "." + s_tcapProblemCode,String(SS7TCAPError::Result_UnexpectedReturnResult));
|
|
m_error.setError(SS7TCAPError::Result_UnexpectedReturnResult);
|
|
setState(OperationPending);
|
|
return;
|
|
}
|
|
else if (m_opClass == SS7TCAP::SuccessOnlyReport)
|
|
setState(WaitForReject);
|
|
break;
|
|
case SS7TCAP::TC_U_Error:
|
|
if (m_opClass == SS7TCAP::FailureOnlyReport)
|
|
setState(WaitForReject);
|
|
else if (m_opClass == SS7TCAP::SuccessOnlyReport || m_opClass == SS7TCAP::NoReport) {
|
|
m_type = SS7TCAP::TC_L_Reject;
|
|
params.setParam(paramRoot + "." + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives));
|
|
params.setParam(paramRoot + "." + s_tcapProblemCode,String(SS7TCAPError::Error_UnexpectedReturnError));
|
|
m_error.setError(SS7TCAPError::Error_UnexpectedReturnError);
|
|
setState(OperationPending);
|
|
return;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_TimerReset:
|
|
default:
|
|
break;
|
|
}
|
|
if (TelEngine::null(params.getParam(paramRoot + "." + s_tcapOpCode))) {
|
|
params.setParam(paramRoot + "." + s_tcapOpCode,m_opCode);
|
|
params.setParam(paramRoot + "." + s_tcapOpCodeType,m_opType);
|
|
}
|
|
}
|
|
|
|
SS7TCAPComponent* SS7TCAPComponent::componentFromNamedList(SS7TCAP::TCAPType tcapType, SS7TCAPTransaction* tr, NamedList& params, unsigned int index)
|
|
{
|
|
if (!tr)
|
|
return 0;
|
|
|
|
String paramRoot;
|
|
compPrefix(paramRoot,index,true);
|
|
NamedString* str = params.getParam(paramRoot + s_tcapLocalCID);
|
|
if (TelEngine::null(str))
|
|
str = params.getParam(paramRoot + s_tcapRemoteCID);
|
|
if (TelEngine::null(str))
|
|
return 0;
|
|
int type = lookup(params.getValue(paramRoot + s_tcapCompType),SS7TCAP::s_compPrimitives);
|
|
// we allow building Reject components that have been built by Component layer or Invokes requested by local user
|
|
if (type != SS7TCAP::TC_Invoke && type != SS7TCAP::TC_InvokeNotLast && type != SS7TCAP::TC_L_Reject
|
|
&& type != SS7TCAP::TC_U_Reject && type != SS7TCAP::TC_R_Reject)
|
|
return 0;
|
|
|
|
SS7TCAPComponent* comp = new SS7TCAPComponent(tcapType,tr,params,index);
|
|
return comp;
|
|
}
|
|
|
|
void SS7TCAPComponent::setState(TCAPComponentState state)
|
|
{
|
|
#ifdef DEBUG
|
|
if (m_transact && m_transact->tcap() && s_extendedDbg)
|
|
DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::setState(%s), locaID=%s remoteID=%s [%p]",lookup(state,s_compStates),
|
|
m_id.c_str(),m_corrID.c_str(),this);
|
|
#endif
|
|
m_state = state;
|
|
m_opTimer.stop();
|
|
if (!(state == Idle || state == OperationPending))
|
|
m_opTimer.start();
|
|
}
|
|
|
|
void SS7TCAPComponent::fill(unsigned int index, NamedList& fillIn)
|
|
{
|
|
#ifdef DEBUG
|
|
if (m_transact && m_transact->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::fill() - component with localID=%s,remoteID=%s of transaction=%s "
|
|
"fill for index=%u [%p]",m_id.c_str(),m_corrID.c_str(),m_transact->toString().c_str(),index,this);
|
|
#endif
|
|
String paramRoot;
|
|
compPrefix(paramRoot,index,true);
|
|
|
|
fillIn.setParam(paramRoot + s_tcapLocalCID,m_id);
|
|
fillIn.setParam(paramRoot + s_tcapRemoteCID,m_corrID);
|
|
fillIn.setParam(paramRoot + s_tcapCompType,lookup(m_type,SS7TCAP::s_compPrimitives,"Unknown"));
|
|
|
|
if (m_error.error() != SS7TCAPError::NoError) {
|
|
if (m_type == SS7TCAP::TC_U_Error)
|
|
fillIn.setParam(paramRoot + s_tcapErrCode,String(m_error.error()));
|
|
else if (m_type == SS7TCAP::TC_L_Reject || m_type == SS7TCAP::TC_U_Reject || m_type == SS7TCAP::TC_R_Reject)
|
|
fillIn.setParam(paramRoot + s_tcapProblemCode,String(m_error.error()));
|
|
}
|
|
if (m_type == SS7TCAP::TC_L_Cancel) {
|
|
fillIn.setParam(paramRoot + s_tcapOpCode,m_opCode);
|
|
fillIn.setParam(paramRoot + s_tcapOpCodeType,m_opType);
|
|
}
|
|
if (m_type == SS7TCAP::TC_U_Reject || m_type == SS7TCAP::TC_R_Reject || m_type == SS7TCAP::TC_L_Reject)
|
|
setState(Idle);
|
|
}
|
|
|
|
void SS7TCAPComponent::resetTimer(NamedList& params, unsigned int index)
|
|
{
|
|
DDebug(m_transact->tcap(),DebugInfo,"SS7TCAPComponent::resetTimer() [%p]",this);
|
|
String paramRoot;
|
|
compPrefix(paramRoot,index,false);
|
|
if (state() == OperationSent)
|
|
m_opTimer.start();
|
|
params.clearParam(paramRoot,'.');
|
|
}
|
|
|
|
// class SS7TCAPANSI
|
|
|
|
static u_int8_t s_tcapProtoVersion = 0x04;
|
|
|
|
static const PrimitiveMapping s_componentsANSIMap[] = {
|
|
{SS7TCAP::TC_Invoke, SS7TCAPTransactionANSI::InvokeLast},
|
|
{SS7TCAP::TC_ResultLast, SS7TCAPTransactionANSI::ReturnResultLast},
|
|
{SS7TCAP::TC_U_Error, SS7TCAPTransactionANSI::ReturnError},
|
|
{SS7TCAP::TC_U_Reject, SS7TCAPTransactionANSI::Reject},
|
|
{SS7TCAP::TC_R_Reject, SS7TCAPTransactionANSI::Reject},
|
|
{SS7TCAP::TC_L_Reject, SS7TCAPTransactionANSI::Reject},
|
|
{SS7TCAP::TC_InvokeNotLast, SS7TCAPTransactionANSI::InvokeNotLast},
|
|
{SS7TCAP::TC_ResultNotLast, SS7TCAPTransactionANSI::ReturnResultNotLast},
|
|
{SS7TCAP::TC_L_Cancel, SS7TCAPTransactionANSI::Local},
|
|
{SS7TCAP::TC_U_Cancel, SS7TCAPTransactionANSI::Local},
|
|
{SS7TCAP::TC_TimerReset, SS7TCAPTransactionANSI::Local},
|
|
};
|
|
|
|
static const PrimitiveMapping s_transANSIMap[] = {
|
|
{SS7TCAP::TC_Unidirectional, SS7TCAPTransactionANSI::Unidirectional},
|
|
{SS7TCAP::TC_QueryWithPerm, SS7TCAPTransactionANSI::QueryWithPermission},
|
|
{SS7TCAP::TC_QueryWithoutPerm, SS7TCAPTransactionANSI::QueryWithoutPermission},
|
|
{SS7TCAP::TC_Begin, SS7TCAPTransactionANSI::QueryWithPermission}, // on receiving a ITU_T Begin, we'll map it to ANSI QueryWithPermission
|
|
{SS7TCAP::TC_ConversationWithPerm, SS7TCAPTransactionANSI::ConversationWithPermission},
|
|
{SS7TCAP::TC_ConversationWithoutPerm, SS7TCAPTransactionANSI::ConversationWithoutPermission},
|
|
{SS7TCAP::TC_Continue, SS7TCAPTransactionANSI::ConversationWithPermission},
|
|
{SS7TCAP::TC_Response, SS7TCAPTransactionANSI::Response},
|
|
{SS7TCAP::TC_End, SS7TCAPTransactionANSI::Response},
|
|
{SS7TCAP::TC_U_Abort, SS7TCAPTransactionANSI::Abort},
|
|
{SS7TCAP::TC_P_Abort, SS7TCAPTransactionANSI::Abort},
|
|
{SS7TCAP::TC_Notice, SS7TCAPTransactionANSI::Unknown},
|
|
{SS7TCAP::TC_Unknown, SS7TCAPTransactionANSI::Unknown},
|
|
};
|
|
|
|
static const PrimitiveMapping* mapCompPrimitivesANSI(int primitive, int comp = -1)
|
|
{
|
|
const PrimitiveMapping* map = s_componentsANSIMap;
|
|
for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
|
|
if (primitive != -1) {
|
|
if (map->primitive == primitive )
|
|
break;
|
|
}
|
|
else if (comp != -1)
|
|
if (map->mappedTo == comp)
|
|
break;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
static const PrimitiveMapping* mapTransPrimitivesANSI(int primitive, int trans = -1)
|
|
{
|
|
const PrimitiveMapping* map = s_transANSIMap;
|
|
for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
|
|
if (primitive != -1) {
|
|
if (map->primitive == primitive )
|
|
break;
|
|
}
|
|
else if (trans != -1)
|
|
if (map->mappedTo == trans)
|
|
break;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
static const SS7TCAPTransactionANSI::ANSITransactionType primitiveToTransactANSI(String primitive,
|
|
SS7TCAP::TCAPUserTransActions primitiveType = SS7TCAP::TC_Unknown)
|
|
{
|
|
SS7TCAPTransactionANSI::ANSITransactionType type = SS7TCAPTransactionANSI::Unknown;
|
|
|
|
if (!primitive.null())
|
|
primitiveType = (SS7TCAP::TCAPUserTransActions)primitive.toInteger(SS7TCAP::s_transPrimitives);
|
|
|
|
const PrimitiveMapping* map = mapTransPrimitivesANSI(primitiveType);
|
|
if (map)
|
|
type = (SS7TCAPTransactionANSI::ANSITransactionType)map->mappedTo;
|
|
return type;
|
|
}
|
|
|
|
SS7TCAPANSI::SS7TCAPANSI(const NamedList& params)
|
|
: SignallingComponent(params.safe("SS7TCAPANSI"),¶ms,"ss7-tcap-ansi"),
|
|
SS7TCAP(params)
|
|
{
|
|
String tmp;
|
|
params.dump(tmp,"\r\n ",'\'',true);
|
|
DDebug(this,DebugAll,"SS7TCAPANSI::SS7TCAPANSI(%s)",tmp.c_str());
|
|
setTCAPType(SS7TCAP::ANSITCAP);
|
|
}
|
|
|
|
SS7TCAPANSI::~SS7TCAPANSI()
|
|
{
|
|
DDebug(this,DebugAll,"SS7TCAPANSI::~SS7TCAPANSI() [%p] destroyed with %d transactions, refCount=%d",
|
|
this,m_transactions.count(),refcount());
|
|
}
|
|
|
|
SS7TCAPTransaction* SS7TCAPANSI::buildTransaction(SS7TCAP::TCAPUserTransActions type, const String& transactID, NamedList& params,
|
|
bool initLocal)
|
|
{
|
|
return new SS7TCAPTransactionANSI(this,type,transactID,params,m_trTimeout,initLocal);
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPANSI::decodeTransactionPart(NamedList& params, DataBlock& data)
|
|
{
|
|
SS7TCAPError error(SS7TCAP::ANSITCAP);
|
|
if (data.length() < 2) // should find out which is the minimal TCAP message length
|
|
return error;
|
|
|
|
// decode message type
|
|
u_int8_t msgType = data[0];
|
|
data.cut(-1);
|
|
|
|
const PrimitiveMapping* map = mapTransPrimitivesANSI(-1,msgType);
|
|
if (map) {
|
|
String type = lookup(map->primitive,SS7TCAP::s_transPrimitives,"Unknown");
|
|
params.setParam(s_tcapRequest,type);
|
|
}
|
|
|
|
// decode message length
|
|
unsigned int len = ASNLib::decodeLength(data);
|
|
if (len != data.length())
|
|
return error;
|
|
// decode transaction IDs, start with Transaction Identifier
|
|
u_int8_t tag = data[0];
|
|
if (tag != TransactionIDTag) {// 0xc7
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error; // check it
|
|
}
|
|
data.cut(-1);
|
|
|
|
// if we'll detect an error, it should be a BadlyStructuredTransaction error
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len > data.length() || data.length() < len || (len != 0 && len != 4 && len != 8))
|
|
return error;
|
|
|
|
// transaction IDs shall be decoded according to message type
|
|
String tid1, tid2;
|
|
if (len > 0 ) {
|
|
tid1.hexify(data.data(),4,' ');
|
|
data.cut(-4);
|
|
if (len == 8) {
|
|
tid2.hexify(data.data(),4,' ');
|
|
data.cut(-4);
|
|
}
|
|
}
|
|
switch (msgType) {
|
|
case SS7TCAPTransactionANSI::Unidirectional:
|
|
if (len != 0)
|
|
return error;
|
|
break;
|
|
case SS7TCAPTransactionANSI::QueryWithPermission:
|
|
case SS7TCAPTransactionANSI::QueryWithoutPermission:
|
|
if (len != 4)
|
|
return error;
|
|
params.setParam(s_tcapRemoteTID,tid1);
|
|
break;
|
|
case SS7TCAPTransactionANSI::Response:
|
|
case SS7TCAPTransactionANSI::Abort:
|
|
if (len != 4)
|
|
return error;
|
|
params.setParam(s_tcapLocalTID,tid1);
|
|
break;
|
|
case SS7TCAPTransactionANSI::ConversationWithPermission:
|
|
case SS7TCAPTransactionANSI::ConversationWithoutPermission:
|
|
if (len != 8)
|
|
return error;
|
|
params.setParam(s_tcapRemoteTID,tid1);
|
|
params.setParam(s_tcapLocalTID,tid2);
|
|
break;
|
|
default:
|
|
error.setError(SS7TCAPError::Transact_UnrecognizedPackageType);
|
|
return error;
|
|
};
|
|
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,this,"SS7TCAPANSI::decodeTransactionPart() finished",this,params,data);
|
|
#endif
|
|
|
|
error.setError(SS7TCAPError::NoError);
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPANSI::encodeTransactionPart(NamedList& params, DataBlock& data)
|
|
{
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,this,"SS7TCAPANSI::encodeTransactionPart() - to be encoded",this,params,data);
|
|
#endif
|
|
|
|
int msgType = primitiveToTransactANSI(params.getValue(s_tcapRequest));
|
|
|
|
const String& otid = params[s_tcapLocalTID];
|
|
const String& dtid = params[s_tcapRemoteTID];
|
|
|
|
String ids;
|
|
switch (msgType) {
|
|
case SS7TCAPTransactionANSI::Unidirectional:
|
|
break;
|
|
case SS7TCAPTransactionANSI::QueryWithPermission:
|
|
case SS7TCAPTransactionANSI::QueryWithoutPermission:
|
|
ids = otid;
|
|
break;
|
|
case SS7TCAPTransactionANSI::Response:
|
|
case SS7TCAPTransactionANSI::Abort:
|
|
ids = dtid;
|
|
break;
|
|
case SS7TCAPTransactionANSI::ConversationWithPermission:
|
|
case SS7TCAPTransactionANSI::ConversationWithoutPermission:
|
|
ids << otid << " " << dtid;
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
DataBlock db;
|
|
db.unHexify(ids.c_str(),ids.length(),' ');
|
|
db.insert(ASNLib::buildLength(db));
|
|
int tag = TransactionIDTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
data.insert(db);
|
|
data.insert(ASNLib::buildLength(data));
|
|
data.insert(DataBlock(&msgType,1));
|
|
}
|
|
|
|
/**
|
|
* SS7TCAPTransactionANSI implementation
|
|
*/
|
|
const TokenDict SS7TCAPTransactionANSI::s_ansiTransactTypes[] = {
|
|
{"Unidirectional", SS7TCAPTransactionANSI::Unidirectional},
|
|
{"QueryWithPermission", SS7TCAPTransactionANSI::QueryWithPermission},
|
|
{"QueryWithoutPermission", SS7TCAPTransactionANSI::QueryWithoutPermission},
|
|
{"Response", SS7TCAPTransactionANSI::Response},
|
|
{"ConversationWithPermission", SS7TCAPTransactionANSI::ConversationWithPermission},
|
|
{"ConversationWithoutPermission", SS7TCAPTransactionANSI::ConversationWithoutPermission},
|
|
{"Abort", SS7TCAPTransactionANSI::Abort},
|
|
{0,0},
|
|
};
|
|
|
|
SS7TCAPTransactionANSI::SS7TCAPTransactionANSI(SS7TCAP* tcap, SS7TCAP::TCAPUserTransActions type,
|
|
const String& transactID, NamedList& params, u_int64_t timeout, bool initLocal)
|
|
: SS7TCAPTransaction(tcap,type,transactID,params,timeout,initLocal),
|
|
m_prevType(type)
|
|
{
|
|
DDebug(tcap,DebugAll,"SS7TCAPTransactionANSI[%p] created with type='%s' and localID='%s'",this,
|
|
lookup(type,SS7TCAP::s_transPrimitives),m_localID.c_str());
|
|
}
|
|
|
|
SS7TCAPTransactionANSI::~SS7TCAPTransactionANSI()
|
|
{
|
|
DDebug(tcap(),DebugAll,"Transaction with ID=%s of user=%s destroyed, TCAP refcount=%d [%p]",
|
|
m_localID.c_str(),m_userName.c_str(),tcap()->refcount(),this);
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionANSI::handleData(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::handleData() transactionID=%s data length=%u [%p]",m_localID.c_str(),
|
|
data.length(),this);
|
|
Lock lock(this);
|
|
// decode DialogPortion
|
|
SS7TCAPError error = decodeDialogPortion(params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
error = handleDialogPortion(params,false);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
|
|
// in case of Abort message, check Cause Information
|
|
String msg = params.getValue(s_tcapMsgType);
|
|
if (msg.toInteger(s_ansiTransactTypes) == Abort) {
|
|
error = decodePAbort(this,params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
}
|
|
// decodeComponents
|
|
error = decodeComponents(params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
buildComponentError(error,params,data);
|
|
|
|
error = handleComponents(params,false);
|
|
return error;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionANSI::update(SS7TCAP::TCAPUserTransActions type, NamedList& params, bool updateByUser)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::update() [%p], localID=%s - update to type=%s initiated by %s",this,m_localID.c_str(),
|
|
lookup(type,SS7TCAP::s_transPrimitives,"Unknown"), (updateByUser ? "user" : "remote"));
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionANSI::update() with",this,params);
|
|
#endif
|
|
Lock l(this);
|
|
SS7TCAPError error(SS7TCAP::ANSITCAP);
|
|
switch (type) {
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
case SS7TCAP::TC_Unidirectional:
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
|
|
this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
|
|
lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
params.setParam(s_tcapRequestError,"invalid_update");
|
|
params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
if (m_type == SS7TCAP::TC_QueryWithoutPerm || m_type == SS7TCAP::TC_ConversationWithoutPerm) {
|
|
params.setParam(s_tcapRequestError,"invalid_update");
|
|
params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
else {
|
|
if (!m_basicEnd)
|
|
// prearranged end, no need to transmit to remote end
|
|
m_transmit = NoTransmit;
|
|
else
|
|
m_transmit = PendingTransmit;
|
|
m_type = type;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
if (m_type == SS7TCAP::TC_End || m_type == SS7TCAP::TC_Response) {
|
|
params.setParam(s_tcapRequestError,"invalid_update");
|
|
params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
else {
|
|
m_remoteID = params.getValue(s_tcapRemoteTID);
|
|
m_type = type;
|
|
m_transmit = PendingTransmit;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
case SS7TCAP::TC_P_Abort:
|
|
if (updateByUser) {
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
|
|
this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
|
|
lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
params.setParam(s_tcapRequestError,"invalid_update");
|
|
params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
case SS7TCAP::TC_U_Abort:
|
|
if (!updateByUser && String("pAbort") == params.getValue(s_tcapAbortCause))
|
|
m_type = SS7TCAP::TC_P_Abort;
|
|
else
|
|
m_type = type;
|
|
m_transmit = PendingTransmit;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
populateSCCPAddress(m_localSCCPAddr,m_remoteSCCPAddr,params,updateByUser);
|
|
if (updateByUser) {
|
|
setState(PackageSent);
|
|
m_basicEnd = params.getBoolValue(s_tcapBasicTerm,true);
|
|
m_endNow = params.getBoolValue(s_tcapEndNow,false);
|
|
}
|
|
else
|
|
setState(PackageReceived);
|
|
if (m_timeout.started()) {
|
|
m_timeout.stop();
|
|
XDebug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::update() [%p], localID=%s - timeout timer has been stopped",this,m_localID.c_str());
|
|
}
|
|
return error;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionANSI::decodeDialogPortion(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::decodeDialogPortion() for transaction with localID=%s [%p]",
|
|
m_localID.c_str(),this);
|
|
|
|
SS7TCAPError error(SS7TCAP::ANSITCAP);
|
|
|
|
u_int8_t tag = data[0];
|
|
// dialog is not present
|
|
if (tag != SS7TCAPANSI::DialogPortionTag) // 0xf9
|
|
return error;
|
|
data.cut(-1);
|
|
|
|
// dialog portion is present, decode dialog length
|
|
int len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
tag = data[0];
|
|
// check for protocol version
|
|
if (data[0] == SS7TCAPANSI::ProtocolVersionTag) { //0xda
|
|
data.cut(-1);
|
|
// decode protocol version
|
|
u_int8_t proto;
|
|
len = ASNLib::decodeUINT8(data,&proto,false);
|
|
if (len != 1) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapProtoVers,String(proto));
|
|
}
|
|
|
|
tag = data[0];
|
|
// check for Application Context
|
|
if (tag == SS7TCAPANSI::IntApplicationContextTag || tag == SS7TCAPANSI::OIDApplicationContextTag) { // 0xdb , 0xdc
|
|
data.cut(-1);
|
|
if (tag == SS7TCAPANSI::IntApplicationContextTag) { //0xdb
|
|
u_int64_t val = 0;
|
|
len = ASNLib::decodeInteger(data,val,sizeof(int),false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapIntAppID,String((int)val));
|
|
}
|
|
if (tag == SS7TCAPANSI::OIDApplicationContextTag) { // oxdc
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapObjAppID,oid.toString());
|
|
}
|
|
}
|
|
|
|
// check for user information
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::UserInformationTag) {// 0xfd
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
tag = data[0];
|
|
if (tag != SS7TCAPANSI::ExternalTag) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
// direct Reference
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::DirectReferenceTag) { // 0x06
|
|
data.cut(-1);
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapReference,oid.toString());
|
|
}
|
|
// data Descriptor
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::DataDescriptorTag) { // 0x07
|
|
data.cut(-1);
|
|
String str;
|
|
int type;
|
|
len = ASNLib::decodeString(data,&str,&type,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapDataDesc,str);
|
|
}
|
|
// encoding
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::SingleASNTypePEncTag || tag == SS7TCAPANSI::SingleASNTypeCEncTag ||
|
|
tag == SS7TCAPANSI::OctetAlignEncTag || tag == SS7TCAPANSI::ArbitraryEncTag) {
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
DataBlock d((void*)data.data(0,len),len);
|
|
data.cut(-len);
|
|
|
|
// put encoding context in hexified form
|
|
String dataHexified;
|
|
dataHexified.hexify(d.data(),d.length(),' ');
|
|
params.setParam(s_tcapEncodingContent,dataHexified);
|
|
// put encoding identifier
|
|
switch (tag) {
|
|
case SS7TCAPANSI::SingleASNTypePEncTag: // 0x80
|
|
params.setParam(s_tcapEncodingType,"single-ASN1-type-primitive");
|
|
break;
|
|
case SS7TCAPANSI::SingleASNTypeCEncTag: // 0xa0
|
|
params.setParam(s_tcapEncodingType,"single-ASN1-type-contructor");
|
|
break;
|
|
case SS7TCAPANSI::OctetAlignEncTag: // 0x81
|
|
params.setParam(s_tcapEncodingType,"octet-aligned");
|
|
break;
|
|
case SS7TCAPANSI::ArbitraryEncTag: // 0x82
|
|
params.setParam(s_tcapEncodingType,"arbitrary");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for security context
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::IntSecurityContextTag || tag == SS7TCAPANSI::OIDSecurityContextTag) {
|
|
data.cut(-1);
|
|
if (tag == SS7TCAPANSI::IntSecurityContextTag) { //0x80
|
|
int val = 0;
|
|
len = ASNLib::decodeINT32(data,&val,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapIntSecID,String(val));
|
|
}
|
|
if (tag == SS7TCAPANSI::OIDSecurityContextTag) { // 0x81
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapObjSecID,oid.toString());
|
|
}
|
|
}
|
|
|
|
// check for Confidentiality information
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::ConfidentialityTag) { // 0xa2
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::IntSecurityContextTag || tag == SS7TCAPANSI::OIDSecurityContextTag) {
|
|
data.cut(-1);
|
|
if (tag == SS7TCAPANSI::IntSecurityContextTag) { //0x80
|
|
int val = 0;
|
|
len = ASNLib::decodeINT32(data,&val,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapIntConfidID,String(val));
|
|
}
|
|
if (tag == SS7TCAPANSI::OIDSecurityContextTag) { // 0x81
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapObjConfidID,oid.toString());
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionANSI::decodeDialogPortion() - decoded dialog portion",this,params,data);
|
|
#endif
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionANSI::encodeDialogPortion(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::encodeDialogPortion() for transaction with localID=%s [%p]",m_localID.c_str(),this);
|
|
|
|
DataBlock dialogData;
|
|
int tag;
|
|
|
|
// encode confidentiality information
|
|
NamedString* val = params.getParam(s_tcapIntConfidID);
|
|
NamedString* oidStr = params.getParam(s_tcapObjConfidID);
|
|
ASNObjId oid;
|
|
|
|
if (!TelEngine::null(val) && !TelEngine::null(oidStr)) {
|
|
// parameter error, encoding of this portion skipped
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::encodeDialogPortion() - skipping encoding of Confidentiality Information,"
|
|
" both IntegerConfidentialityAlgorithmID=%s and ObjectIDConfidentialityID=%s specified, can't pick one",
|
|
val->c_str(),oidStr->c_str());
|
|
}
|
|
else {
|
|
if (!TelEngine::null(val)) {
|
|
DataBlock db = ASNLib::encodeInteger(val->toInteger(),false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::IntSecurityContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(db);
|
|
}
|
|
else if (!TelEngine::null(oidStr)) {
|
|
oid = *oidStr;
|
|
DataBlock db = ASNLib::encodeOID(oid,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::OIDSecurityContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(db);
|
|
}
|
|
if (dialogData.length()) {
|
|
dialogData.insert(ASNLib::buildLength(dialogData));
|
|
tag = SS7TCAPANSI::ConfidentialityTag;
|
|
dialogData.insert(DataBlock(&tag,1));
|
|
}
|
|
}
|
|
// encode security information
|
|
val = params.getParam(s_tcapIntSecID);
|
|
oidStr = params.getParam(s_tcapObjSecID);
|
|
|
|
if (!TelEngine::null(val) && !TelEngine::null(oidStr)) {
|
|
// parameter error, encoding of this portion skipped
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::encodeDialogPortion() - skipping encoding of Security Context Information,"
|
|
" both IntegerSecurityContext=%s and ObjectIDSecurityContext=%s specified, can't pick one",
|
|
val->c_str(),oid.toString().c_str());
|
|
}
|
|
else if (!TelEngine::null(val)) {
|
|
DataBlock db = ASNLib::encodeInteger(val->toInteger(),false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::IntSecurityContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(db);
|
|
}
|
|
else if (!TelEngine::null(oidStr)) {
|
|
oid = *oidStr;
|
|
DataBlock db = ASNLib::encodeOID(oid,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::OIDSecurityContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(db);
|
|
}
|
|
|
|
// encode user information
|
|
DataBlock userInfo;
|
|
val = params.getParam(s_tcapEncodingType);
|
|
if (!TelEngine::null(val)) {
|
|
if (*val == "single-ASN1-type-primitive")
|
|
tag = SS7TCAPANSI::SingleASNTypePEncTag;
|
|
else if (*val == "single-ASN1-type-contructor")
|
|
tag = SS7TCAPANSI::SingleASNTypeCEncTag;
|
|
else if (*val == "octet-aligned")
|
|
tag = SS7TCAPANSI::OctetAlignEncTag;
|
|
else if (*val == "arbitrary")
|
|
tag = SS7TCAPANSI::ArbitraryEncTag;
|
|
|
|
val = params.getParam(s_tcapEncodingContent);
|
|
if (val) {
|
|
DataBlock db;
|
|
db.unHexify(val->c_str(),val->length(),' ');
|
|
db.insert(ASNLib::buildLength(db));
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
userInfo.insert(db);
|
|
}
|
|
}
|
|
val = params.getParam(s_tcapDataDesc);
|
|
if (!TelEngine::null(val)) {
|
|
DataBlock db = ASNLib::encodeString(*val,ASNLib::PRINTABLE_STR,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::DataDescriptorTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
userInfo.insert(db);
|
|
}
|
|
val = params.getParam(s_tcapReference);
|
|
if (!TelEngine::null(val)) {
|
|
oid = *val;
|
|
DataBlock db = ASNLib::encodeOID(oid,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::DirectReferenceTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
userInfo.insert(db);
|
|
}
|
|
|
|
if (userInfo.length()) {
|
|
userInfo.insert(ASNLib::buildLength(userInfo));
|
|
tag = SS7TCAPANSI::ExternalTag;
|
|
userInfo.insert(DataBlock(&tag,1));
|
|
userInfo.insert(ASNLib::buildLength(userInfo));
|
|
tag = SS7TCAPANSI::UserInformationTag;
|
|
userInfo.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(userInfo);
|
|
}
|
|
|
|
// Aplication context
|
|
val = params.getParam(s_tcapIntAppID);
|
|
oidStr = params.getParam(s_tcapObjAppID);
|
|
if (!TelEngine::null(val) && !TelEngine::null(oidStr)) {
|
|
// parameter error, encoding of this portion skipped
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::encodeDialogPortion() - skipping encoding of Application Context Information,"
|
|
" both IntegerApplicationID=%s and ObjectApplicationID=%s specified, can't pick one",val->c_str(),oid.toString().c_str());
|
|
}
|
|
else if (!TelEngine::null(val)) {
|
|
DataBlock db = ASNLib::encodeInteger(val->toInteger(),false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::IntApplicationContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(db);
|
|
}
|
|
else if (!TelEngine::null(oidStr)) {
|
|
oid = *oidStr;
|
|
DataBlock db = ASNLib::encodeOID(oid,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::OIDApplicationContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
|
|
dialogData.insert(db);
|
|
}
|
|
|
|
val = params.getParam(s_tcapProtoVers);
|
|
if (!TelEngine::null(val)) {
|
|
u_int8_t proto = val->toInteger();
|
|
DataBlock db = ASNLib::encodeInteger(proto,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPANSI::ProtocolVersionTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
dialogData.insert(db);
|
|
}
|
|
|
|
if (dialogData.length()) {
|
|
dialogData.insert(ASNLib::buildLength(dialogData));
|
|
tag = SS7TCAPANSI::DialogPortionTag;
|
|
dialogData.insert(DataBlock(&tag,1));
|
|
}
|
|
|
|
data.insert(dialogData);
|
|
params.clearParam(s_tcapDialogPrefix,'.');
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionANSI::encodeDialogPortion() - encoded dialog portion",this,params,data);
|
|
#endif
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionANSI::decodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
|
|
{
|
|
u_int8_t tag = data[0];
|
|
SS7TCAPError error(SS7TCAP::ANSITCAP);
|
|
if (tag == SS7TCAPANSI::PCauseTag || tag == SS7TCAPANSI::UserAbortPTag || tag == SS7TCAPANSI::UserAbortCTag) {
|
|
SS7TCAPError error(SS7TCAP::ANSITCAP);
|
|
data.cut(-1);
|
|
if (tag == SS7TCAPANSI::PCauseTag) {
|
|
u_int8_t pCode = 0;
|
|
int len = ASNLib::decodeUINT8(data,&pCode,false);
|
|
if (len != 1) {
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapAbortCause,"pAbort");
|
|
params.setParam(s_tcapAbortInfo,String(SS7TCAPError::errorFromCode(SS7TCAP::ANSITCAP,pCode)));
|
|
}
|
|
else {
|
|
int len = ASNLib::decodeLength(data);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
return error;
|
|
}
|
|
String str;
|
|
str.hexify(data.data(0,len),len,' ');
|
|
data.cut(-len);
|
|
params.setParam(s_tcapAbortCause,(tag == SS7TCAPANSI::UserAbortPTag ? "userAbortP" : "userAbortC"));
|
|
params.setParam(s_tcapAbortInfo,str);
|
|
if (tr)
|
|
tr->setTransactionType(SS7TCAP::TC_U_Abort);
|
|
}
|
|
#ifdef DEBUG
|
|
if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionANSI::decodePAbort() - decoded Abort info",tr,params,data);
|
|
#endif
|
|
}
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionANSI::encodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
|
|
{
|
|
NamedString* pAbortCause = params.getParam(s_tcapAbortCause);
|
|
DataBlock db;
|
|
if (!TelEngine::null(pAbortCause)) {
|
|
int tag = 0;
|
|
if (*pAbortCause == "pAbort") {
|
|
tag = SS7TCAPANSI::PCauseTag;
|
|
u_int16_t pCode = SS7TCAPError::codeFromError(SS7TCAP::ANSITCAP,params.getIntValue(s_tcapAbortInfo));
|
|
if (pCode) {
|
|
db.append(ASNLib::encodeInteger(pCode,false));
|
|
db.insert(ASNLib::buildLength(db));
|
|
}
|
|
}
|
|
else if (*pAbortCause == "userAbortP" || *pAbortCause == "userAbortC") {
|
|
NamedString* info = params.getParam(s_tcapAbortInfo);
|
|
if (!TelEngine::null(info))
|
|
db.unHexify(info->c_str(),info->length(),' ');
|
|
db.insert(ASNLib::buildLength(db));
|
|
if (*pAbortCause == "userAbortP")
|
|
tag = SS7TCAPANSI::UserAbortPTag;
|
|
else
|
|
tag = SS7TCAPANSI::UserAbortCTag;
|
|
}
|
|
if (db.length())
|
|
db.insert(DataBlock(&tag,1));
|
|
}
|
|
if (db.length()) {
|
|
data.insert(db);
|
|
params.clearParam(s_tcapAbortCause);
|
|
params.clearParam(s_tcapAbortInfo);
|
|
}
|
|
#ifdef DEBUG
|
|
if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionANSI::encodePAbort() - encoded Abort info",tr,params,data);
|
|
#endif
|
|
}
|
|
|
|
void SS7TCAPTransactionANSI::requestContent(NamedList& params, DataBlock& data)
|
|
{
|
|
#ifdef DEBUG
|
|
if (s_extendedDbg)
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::requestContent() for transaction with id=%s [%p]",m_localID.c_str(),this);
|
|
#endif
|
|
if (m_type == SS7TCAP::TC_P_Abort || m_type == SS7TCAP::TC_U_Abort)
|
|
encodePAbort(this,params,data);
|
|
else
|
|
requestComponents(params,data);
|
|
encodeDialogPortion(params,data);
|
|
transactionData(params);
|
|
}
|
|
|
|
void SS7TCAPTransactionANSI::updateToEnd()
|
|
{
|
|
if (transactionType() == SS7TCAP::TC_QueryWithoutPerm || transactionType() == SS7TCAP::TC_ConversationWithoutPerm)
|
|
setTransactionType(SS7TCAP::TC_U_Abort);
|
|
else
|
|
setTransactionType(SS7TCAP::TC_Response);
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionANSI::decodeComponents(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::decodeComponents() [%p] - data length=%u",this,data.length());
|
|
|
|
SS7TCAPError error(SS7TCAP::ANSITCAP);
|
|
if (!data.length()) {
|
|
params.setParam(s_tcapCompCount,"0");
|
|
return error;
|
|
}
|
|
|
|
u_int8_t tag = data[0];
|
|
if (tag != SS7TCAPANSI::ComponentPortionTag) { // 0xe8
|
|
error.setError(SS7TCAPError::General_IncorrectComponentPortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
// decode length of component portion
|
|
int len = ASNLib::decodeLength(data);
|
|
bool checkEoC = (len == ASNLib::IndefiniteForm);
|
|
if (!checkEoC && (len < 0 || len != (int)data.length())) { // the length of the remaining data should be the same as the decoded length()
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
return error;
|
|
}
|
|
|
|
unsigned int compCount = 0;
|
|
while (data.length()) {
|
|
if (checkEoC && ASNLib::matchEOC(data) > 0)
|
|
break;
|
|
compCount++;
|
|
// decode component type
|
|
u_int8_t compType = data[0];
|
|
data.cut(-1);
|
|
|
|
// verify component length
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
|
|
// decode component IDs, start with ComponentsIDs identifier
|
|
tag = data[0];
|
|
if (tag != SS7TCAPANSI::ComponentsIDsTag) {// 0xcf
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
data.cut(-1);
|
|
|
|
// obtain component ID(s)
|
|
u_int16_t compIDs;
|
|
len = ASNLib::decodeUINT16(data,&compIDs,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
|
|
String compParam;
|
|
compPrefix(compParam,compCount,false);
|
|
// comp IDs shall be decoded according to component type
|
|
switch (compType) {
|
|
case InvokeLast:
|
|
case InvokeNotLast:
|
|
if (len == 1)
|
|
params.setParam(compParam + "." + s_tcapRemoteCID,String(compIDs));
|
|
else if (len == 2) {
|
|
params.setParam(compParam + "." + s_tcapRemoteCID,String(compIDs >> 8));
|
|
params.setParam(compParam + "." + s_tcapLocalCID,String((u_int8_t)compIDs));
|
|
}
|
|
else {
|
|
params.setParam(compParam + "." + s_tcapRemoteCID,"");
|
|
params.setParam(compParam + "." + s_tcapLocalCID,"");
|
|
}
|
|
break;
|
|
case ReturnResultLast:
|
|
case ReturnError:
|
|
case Reject:
|
|
case ReturnResultNotLast:
|
|
if (len != 1)
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
else
|
|
params.setParam(compParam + "." + s_tcapLocalCID,String(compIDs));
|
|
break;
|
|
default:
|
|
error.setError(SS7TCAPError::General_UnrecognizedComponentType);
|
|
break;
|
|
}
|
|
const PrimitiveMapping* map = mapCompPrimitivesANSI(-1,compType);
|
|
if (!map) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
params.setParam(compParam + "." + s_tcapCompType,lookup(map->primitive,SS7TCAP::s_compPrimitives,"Unknown"));
|
|
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
break;
|
|
|
|
// decode Operation Code
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::OperationNationalTag || tag == SS7TCAPANSI::OperationPrivateTag) {
|
|
data.cut(-1);
|
|
|
|
int opCode = 0;
|
|
len = ASNLib::decodeINT32(data,&opCode,false);
|
|
if (tag == SS7TCAPANSI::OperationNationalTag) {
|
|
if (len != 2) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
params.setParam(compParam + "." + s_tcapOpCodeType,"national");
|
|
}
|
|
if (tag == SS7TCAPANSI::OperationPrivateTag)
|
|
params.setParam(compParam + "." + s_tcapOpCodeType,"private");
|
|
params.setParam(compParam + "." + s_tcapOpCode,String(opCode));
|
|
}
|
|
|
|
// decode Error Code
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::ErrorNationalTag || tag == SS7TCAPANSI::ErrorPrivateTag) { // 0xd3, 0xd4
|
|
data.cut(-1);
|
|
|
|
int errCode = 0;
|
|
len = ASNLib::decodeINT32(data,&errCode,false);
|
|
if (len < 0 || (tag == SS7TCAPANSI::ErrorNationalTag && len != 1)) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
if (tag == SS7TCAPANSI::ErrorNationalTag)
|
|
params.setParam(compParam + "." + s_tcapErrCodeType,"national");
|
|
else
|
|
params.setParam(compParam + "." + s_tcapErrCodeType,"private");
|
|
params.setParam(compParam + "." + s_tcapErrCode,String(errCode));
|
|
}
|
|
|
|
// decode Problem
|
|
tag = data[0];
|
|
if (tag == SS7TCAPANSI::ProblemCodeTag) { // 0xd5
|
|
data.cut(-1);
|
|
u_int16_t problemCode = 0;
|
|
len = ASNLib::decodeUINT16(data,&problemCode,false);
|
|
if (len != 2) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
params.setParam(compParam + "." + s_tcapProblemCode,String(SS7TCAPError::errorFromCode(tcap()->tcapType(),problemCode)));
|
|
}
|
|
// decode Parameters (Set or Sequence) as payload
|
|
tag = data[0];
|
|
String dataHexified = "";
|
|
if (tag == SS7TCAPANSI::ParameterSetTag || tag == SS7TCAPANSI::ParameterSeqTag) { // 0xf2 0x30
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
DataBlock d((void*)data.data(0,len),len);
|
|
data.cut(-len);
|
|
d.insert(ASNLib::buildLength(d));
|
|
d.insert(DataBlock(&tag,1));
|
|
dataHexified.hexify(d.data(),d.length(),' ');
|
|
}
|
|
params.setParam(compParam,dataHexified);
|
|
}
|
|
|
|
params.setParam(s_tcapCompCount,String(compCount));
|
|
#ifdef DEBUG
|
|
if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"Finished decoding message",this,params,data);
|
|
#endif
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionANSI::encodeComponents(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::encodeComponents() for transaction with localID=%s [%p]",m_localID.c_str(),this);
|
|
|
|
int componentCount = params.getIntValue(s_tcapCompCount,0);
|
|
DataBlock compData;
|
|
if (componentCount) {
|
|
int index = componentCount + 1;
|
|
|
|
while (--index) {
|
|
DataBlock codedComp;
|
|
// encode parameters
|
|
String compParam;
|
|
compPrefix(compParam,index,false);
|
|
// Component Type
|
|
NamedString* value = params.getParam(compParam + "." + s_tcapCompType);
|
|
if (TelEngine::null(value))
|
|
continue;
|
|
int compPrimitive = lookup(*value,SS7TCAP::s_compPrimitives);
|
|
const PrimitiveMapping* map = mapCompPrimitivesANSI(compPrimitive,-1);
|
|
if (!map)
|
|
continue;
|
|
int compType = map->mappedTo;
|
|
String payloadHex = params.getValue(compParam,"");
|
|
if (!payloadHex.null()) {
|
|
DataBlock payload;
|
|
payload.unHexify(payloadHex.c_str(),payloadHex.length(),' ');
|
|
//payload.insert(ASNLib::buildLength(payload));
|
|
codedComp.insert(payload);
|
|
}
|
|
|
|
// encode Problem only if Reject
|
|
if (compType == Reject) {
|
|
value = params.getParam(compParam + "." + s_tcapProblemCode);
|
|
if (!TelEngine::null(value)) {
|
|
u_int16_t code = SS7TCAPError::codeFromError(tcap()->tcapType(),value->toInteger());
|
|
DataBlock db = ASNLib::encodeInteger(code,false);
|
|
// should check that encoded length is 2
|
|
if (db.length() < 2) {
|
|
code = 0;
|
|
db.insert(DataBlock(&code,1));
|
|
}
|
|
db.insert(ASNLib::buildLength(db));
|
|
int tag = SS7TCAPANSI::ProblemCodeTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
codedComp.insert(db);
|
|
}
|
|
}
|
|
|
|
// encode Error Code only if ReturnError
|
|
if (compType == ReturnError) {
|
|
value = params.getParam(compParam + "." + s_tcapErrCodeType);
|
|
if (!TelEngine::null(value)) {
|
|
int errCode = params.getIntValue(compParam + "." + s_tcapErrCode,0);
|
|
DataBlock db = ASNLib::encodeInteger(errCode,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
|
|
int tag = 0;
|
|
if (*value == "national")
|
|
tag = SS7TCAPANSI::ErrorNationalTag;
|
|
else if (*value == "private")
|
|
tag = SS7TCAPANSI::ErrorPrivateTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
codedComp.insert(db);
|
|
}
|
|
}
|
|
|
|
// encode Operation Code only if Invoke
|
|
if (compType == InvokeLast ||
|
|
compType == InvokeNotLast) {
|
|
value = params.getParam(compParam + "." + s_tcapOpCodeType);
|
|
if (!TelEngine::null(value)) {
|
|
int opCode = params.getIntValue(compParam + "." + s_tcapOpCode,0);
|
|
DataBlock db = ASNLib::encodeInteger(opCode,false);
|
|
int tag = 0;
|
|
if (*value == "national") {
|
|
tag = SS7TCAPANSI::OperationNationalTag;
|
|
if (db.length() < 2) {
|
|
opCode = 0;
|
|
db.insert(DataBlock(&opCode,1));
|
|
}
|
|
}
|
|
else if (*value == "private")
|
|
tag = SS7TCAPANSI::OperationPrivateTag;
|
|
db.insert(ASNLib::buildLength(db));
|
|
db.insert(DataBlock(&tag,1));
|
|
codedComp.insert(db);
|
|
}
|
|
}
|
|
NamedString* invID = params.getParam(compParam + "." + s_tcapLocalCID);
|
|
NamedString* corrID = params.getParam(compParam + "." + s_tcapRemoteCID);
|
|
DataBlock db;
|
|
u_int8_t val = 0;
|
|
switch (compType) {
|
|
case InvokeLast:
|
|
case InvokeNotLast:
|
|
if (!TelEngine::null(invID)) {
|
|
val = invID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
if (!TelEngine::null(corrID)) {
|
|
val = corrID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
}
|
|
}
|
|
else {
|
|
if (!TelEngine::null(corrID)) {
|
|
val = corrID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
}
|
|
}
|
|
break;
|
|
case ReturnResultLast:
|
|
case ReturnError:
|
|
case Reject:
|
|
case ReturnResultNotLast:
|
|
val = corrID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
db.insert(ASNLib::buildLength(db));
|
|
int tag = SS7TCAPANSI::ComponentsIDsTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
codedComp.insert(db);
|
|
codedComp.insert(ASNLib::buildLength(codedComp));
|
|
codedComp.insert(DataBlock(&compType,1));
|
|
|
|
params.clearParam(compParam,'.'); // clear all params for this component
|
|
compData.insert(codedComp);
|
|
}
|
|
}
|
|
|
|
compData.insert(ASNLib::buildLength(compData));
|
|
int tag = SS7TCAPANSI::ComponentPortionTag;
|
|
compData.insert(DataBlock(&tag,1));
|
|
|
|
data.insert(compData);
|
|
params.clearParam(s_tcapCompPrefix,'.');
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionANSI::handleDialogPortion(NamedList& params, bool byUser)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::handleDialogPortion() [%p]",this);
|
|
|
|
SS7TCAPError err(SS7TCAP::ANSITCAP);
|
|
|
|
NamedList dialog("");
|
|
Lock l(this);
|
|
switch (m_type) {
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
case SS7TCAP::TC_Unidirectional:
|
|
if (!byUser) {
|
|
int protoVersion = params.getIntValue(s_tcapProtoVers);
|
|
if (protoVersion) { // there is a Dialog portion
|
|
if ((protoVersion & s_tcapProtoVersion ) != s_tcapProtoVersion)
|
|
params.setParam(s_tcapProtoVers,String(s_tcapProtoVersion));
|
|
}
|
|
}
|
|
else {
|
|
dialog.copyParams(params,s_tcapDialogPrefix,'.');
|
|
if (dialog.count())
|
|
params.setParam(s_tcapProtoVers,String(s_tcapProtoVersion));
|
|
}
|
|
return err;
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
dialog.copyParams(params,s_tcapDialogPrefix,'.');
|
|
if (dialog.count() && m_prevType != SS7TCAP::TC_Begin && m_prevType != SS7TCAP::TC_QueryWithPerm) {
|
|
err.setError(SS7TCAPError::Dialog_InconsistentDialoguePortion);
|
|
return err;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
dialog.copyParams(params,s_tcapDialogPrefix,'.');
|
|
if (dialog.count() && m_prevType != SS7TCAP::TC_Begin && m_prevType != SS7TCAP::TC_QueryWithPerm
|
|
&& m_prevType != SS7TCAP::TC_QueryWithoutPerm) {
|
|
err.setError(SS7TCAPError::Dialog_InconsistentDialoguePortion);
|
|
return err;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
case SS7TCAP::TC_P_Abort:
|
|
break;
|
|
case SS7TCAP::TC_U_Abort:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
void SS7TCAPTransactionANSI::updateState(bool byUser)
|
|
{
|
|
switch (m_type) {
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
(byUser ? setState(SS7TCAPTransaction::PackageSent) : setState(SS7TCAPTransaction::PackageReceived));
|
|
break;
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_U_Abort:
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_Response:
|
|
case SS7TCAP::TC_Unidirectional:
|
|
setState(Idle);
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
case SS7TCAP::TC_Unknown:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ITU-T SS7 TCAP implementation
|
|
*/
|
|
|
|
static const int s_ituTCAPProto = 1;
|
|
static const String s_tcapDialogueID = "tcap.dialogPDU.dialog-as-id";
|
|
static const String s_tcapDialogueAppCtxt = "tcap.dialogPDU.application-context-name";
|
|
static const String s_tcapDialoguePduType = "tcap.dialogPDU.dialog-pdu-type";
|
|
static const String s_tcapDialogueAbrtSrc = "tcap.dialogPDU.abort-source";
|
|
static const String s_tcapDialogueResult = "tcap.dialogPDU.result";
|
|
static const String s_tcapDialogueDiag = "tcap.dialogPDU.result-source-diagnostic";
|
|
static const String s_unstructDialogueOID = "0.0.17.773.1.2.1";
|
|
static const String s_structDialogueOID = "0.0.17.773.1.1.1";
|
|
|
|
static const PrimitiveMapping s_componentsITUMap[] = {
|
|
{SS7TCAP::TC_Invoke, SS7TCAPTransactionITU::Invoke},
|
|
{SS7TCAP::TC_ResultLast, SS7TCAPTransactionITU::ReturnResultLast},
|
|
{SS7TCAP::TC_U_Error, SS7TCAPTransactionITU::ReturnError},
|
|
{SS7TCAP::TC_U_Reject, SS7TCAPTransactionITU::Reject},
|
|
{SS7TCAP::TC_R_Reject, SS7TCAPTransactionITU::Reject},
|
|
{SS7TCAP::TC_L_Reject, SS7TCAPTransactionITU::Reject},
|
|
{SS7TCAP::TC_InvokeNotLast, SS7TCAPTransactionITU::Invoke},
|
|
{SS7TCAP::TC_ResultNotLast, SS7TCAPTransactionITU::ReturnResultNotLast},
|
|
{SS7TCAP::TC_L_Cancel, SS7TCAPTransactionITU::Local},
|
|
{SS7TCAP::TC_U_Cancel, SS7TCAPTransactionITU::Local},
|
|
{SS7TCAP::TC_TimerReset, SS7TCAPTransactionITU::Local},
|
|
{SS7TCAP::TC_Unknown, SS7TCAPTransactionITU::Unknown},
|
|
};
|
|
|
|
static const PrimitiveMapping s_transITUMap[] = {
|
|
{SS7TCAP::TC_Unidirectional, SS7TCAPTransactionITU::Unidirectional},
|
|
{SS7TCAP::TC_Begin, SS7TCAPTransactionITU::Begin},
|
|
{SS7TCAP::TC_QueryWithPerm, SS7TCAPTransactionITU::Begin},
|
|
{SS7TCAP::TC_QueryWithoutPerm, SS7TCAPTransactionITU::Begin},
|
|
{SS7TCAP::TC_Continue, SS7TCAPTransactionITU::Continue},
|
|
{SS7TCAP::TC_ConversationWithPerm, SS7TCAPTransactionITU::Continue},
|
|
{SS7TCAP::TC_ConversationWithoutPerm, SS7TCAPTransactionITU::Continue},
|
|
{SS7TCAP::TC_End, SS7TCAPTransactionITU::End},
|
|
{SS7TCAP::TC_Response, SS7TCAPTransactionITU::End},
|
|
{SS7TCAP::TC_U_Abort, SS7TCAPTransactionITU::Abort},
|
|
{SS7TCAP::TC_P_Abort, SS7TCAPTransactionITU::Abort},
|
|
{SS7TCAP::TC_Notice, SS7TCAPTransactionITU::Unknown},
|
|
{SS7TCAP::TC_Unknown, SS7TCAPTransactionITU::Unknown},
|
|
};
|
|
|
|
static const PrimitiveMapping* mapCompPrimitivesITU(int primitive, int comp = -1)
|
|
{
|
|
const PrimitiveMapping* map = s_componentsITUMap;
|
|
for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
|
|
if (primitive != -1) {
|
|
if (map->primitive == primitive )
|
|
break;
|
|
}
|
|
else if (comp != -1)
|
|
if (map->mappedTo == comp)
|
|
break;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
static const PrimitiveMapping* mapTransPrimitivesITU(int primitive, int trans = -1)
|
|
{
|
|
const PrimitiveMapping* map = s_transITUMap;
|
|
for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
|
|
if (primitive != -1) {
|
|
if (map->primitive == primitive )
|
|
break;
|
|
}
|
|
else if (trans != -1)
|
|
if (map->mappedTo == trans)
|
|
break;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
SS7TCAPITU::SS7TCAPITU(const NamedList& params)
|
|
: SignallingComponent(params.safe("SS7TCAPITU"),¶ms,"ss7-tcap-itu"),
|
|
SS7TCAP(params)
|
|
{
|
|
String tmp;
|
|
params.dump(tmp,"\r\n ",'\'',true);
|
|
DDebug(this,DebugAll,"SS7TCAPITU::SS7TCAPITU(%s)",tmp.c_str());
|
|
setTCAPType(SS7TCAP::ITUTCAP);
|
|
}
|
|
|
|
SS7TCAPITU::~SS7TCAPITU()
|
|
{
|
|
DDebug(this,DebugAll,"SS7TCAPITU::~SS7TCAPITU() [%p] destroyed with %d transactions, refCount=%d",
|
|
this,m_transactions.count(),refcount());
|
|
}
|
|
|
|
SS7TCAPTransaction* SS7TCAPITU::buildTransaction(SS7TCAP::TCAPUserTransActions type, const String& transactID, NamedList& params,
|
|
bool initLocal)
|
|
{
|
|
return new SS7TCAPTransactionITU(this,type,transactID,params,m_trTimeout,initLocal);
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPITU::decodeTransactionPart(NamedList& params, DataBlock& data)
|
|
{
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
if (data.length() < 2)
|
|
return error;
|
|
|
|
// decode message type
|
|
u_int8_t msgType = data[0];
|
|
data.cut(-1);
|
|
|
|
const PrimitiveMapping* map = mapTransPrimitivesITU(-1,msgType);
|
|
if (map) {
|
|
String type = lookup(map->primitive,SS7TCAP::s_transPrimitives,"Unknown");
|
|
params.setParam(s_tcapRequest,type);
|
|
}
|
|
|
|
// decode message length
|
|
int len = ASNLib::decodeLength(data);
|
|
if (len != (int)data.length()) {
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
return error;
|
|
}
|
|
|
|
// decode transaction ids
|
|
bool decodeOTID = false;
|
|
bool decodeDTID = false;
|
|
switch (map->mappedTo) {
|
|
case SS7TCAPTransactionITU::Unidirectional:
|
|
return error;
|
|
case SS7TCAPTransactionITU::Begin:
|
|
decodeOTID = true;
|
|
break;
|
|
case SS7TCAPTransactionITU::End:
|
|
case SS7TCAPTransactionITU::Abort:
|
|
decodeDTID = true;
|
|
break;
|
|
case SS7TCAPTransactionITU::Continue:
|
|
decodeOTID = true;
|
|
decodeDTID = true;
|
|
break;
|
|
default:
|
|
error.setError(SS7TCAPError::Transact_UnrecognizedPackageType);
|
|
return error;
|
|
}
|
|
|
|
u_int8_t tag = data[0];
|
|
String str;
|
|
if (decodeOTID) {
|
|
// check for originating ID
|
|
if (tag != OriginatingIDTag) {// 0x48
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 1 || len > 4 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
return error;
|
|
}
|
|
str.hexify(data.data(),len,' ');
|
|
data.cut(-len);
|
|
params.setParam(s_tcapRemoteTID,str);
|
|
}
|
|
|
|
tag = data[0];
|
|
if (decodeDTID) {
|
|
// check for originating ID
|
|
if (tag != DestinationIDTag) {// 0x49
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 1 || len > 4 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
return error;
|
|
}
|
|
str.hexify(data.data(),len,' ');
|
|
data.cut(-len);
|
|
params.setParam(s_tcapLocalTID,str);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,this,"SS7TCAPITU::decodeTransactionPart() finished",this,params,data);
|
|
#endif
|
|
|
|
error.setError(SS7TCAPError::NoError);
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPITU::encodeTransactionPart(NamedList& params, DataBlock& data)
|
|
{
|
|
String msg = params.getValue(s_tcapRequest);
|
|
const PrimitiveMapping* map = mapTransPrimitivesITU(msg.toInteger(SS7TCAP::s_transPrimitives),-1);
|
|
if (!map)
|
|
return;
|
|
|
|
u_int8_t msgType = map->mappedTo;
|
|
NamedString* val = 0;
|
|
u_int8_t tag;
|
|
bool encDTID = false;
|
|
bool encOTID = false;
|
|
|
|
switch (msgType) {
|
|
case SS7TCAPTransactionITU::Unidirectional:
|
|
break;
|
|
case SS7TCAPTransactionITU::Begin:
|
|
encOTID = true;
|
|
break;
|
|
case SS7TCAPTransactionITU::End:
|
|
case SS7TCAPTransactionITU::Abort:
|
|
encDTID = true;
|
|
break;
|
|
case SS7TCAPTransactionITU::Continue:
|
|
encOTID = true;
|
|
encDTID = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (encDTID) {
|
|
val = params.getParam(s_tcapRemoteTID);
|
|
if (!TelEngine::null(val)) {
|
|
// destination TID
|
|
DataBlock db;
|
|
db.unHexify(val->c_str(),val->length(),' ');
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = DestinationIDTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
data.insert(db);
|
|
}
|
|
}
|
|
if (encOTID) {
|
|
val = params.getParam(s_tcapLocalTID);
|
|
if (!TelEngine::null(val)) {
|
|
// origination id
|
|
DataBlock db;
|
|
db.unHexify(val->c_str(),val->length(),' ');
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = OriginatingIDTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
data.insert(db);
|
|
}
|
|
}
|
|
|
|
data.insert(ASNLib::buildLength(data));
|
|
data.insert(DataBlock(&msgType,1));
|
|
}
|
|
|
|
/**
|
|
* ITU-T SS7 TCAP transaction implementation
|
|
*/
|
|
const TokenDict SS7TCAPTransactionITU::s_dialogPDUs[] = {
|
|
{"AARQ", SS7TCAPTransactionITU::AARQDialogTag},
|
|
{"AARE", SS7TCAPTransactionITU::AAREDialogTag},
|
|
{"ABRT", SS7TCAPTransactionITU::ABRTDialogTag},
|
|
{0,0},
|
|
};
|
|
|
|
const TokenDict SS7TCAPTransactionITU::s_resultPDUValues[] = {
|
|
{"accepted", SS7TCAPTransactionITU::ResultAccepted},
|
|
{"reject-permanent", SS7TCAPTransactionITU::ResultRejected},
|
|
{"user-null", SS7TCAPTransactionITU::DiagnosticUserNull},
|
|
{"user-no-reason-given", SS7TCAPTransactionITU::DiagnosticUserNoReason},
|
|
{"user-application-context-name-not-supported", SS7TCAPTransactionITU::DiagnosticUserAppCtxtNotSupported},
|
|
{"provider-null", SS7TCAPTransactionITU::DiagnosticProviderNull},
|
|
{"provider-no-reason-given", SS7TCAPTransactionITU::DiagnosticProviderNoReason},
|
|
{"provider-no-common-dialogue-portion", SS7TCAPTransactionITU::DiagnosticProviderNoCommonDialog},
|
|
{"dialogue-service-user", SS7TCAPTransactionITU::AbortSourceUser},
|
|
{"dialogue-service-provider", SS7TCAPTransactionITU::AbortSourceProvider},
|
|
{0,-1},
|
|
};
|
|
|
|
SS7TCAPTransactionITU::SS7TCAPTransactionITU(SS7TCAP* tcap, SS7TCAP::TCAPUserTransActions type,
|
|
const String& transactID, NamedList& params, u_int64_t timeout, bool initLocal)
|
|
: SS7TCAPTransaction(tcap,type,transactID,params,timeout,initLocal)
|
|
{
|
|
DDebug(m_tcap,DebugAll,"SS7TCAPTransactionITU(tcap = '%s' [%p], transactID = %s, timeout=" FMT64 " ) created [%p]",
|
|
m_tcap->toString().c_str(),tcap,transactID.c_str(),timeout,this);
|
|
}
|
|
|
|
|
|
SS7TCAPTransactionITU::~SS7TCAPTransactionITU()
|
|
{
|
|
DDebug(tcap(),DebugAll,"Transaction with ID=%s of user=%s destroyed [%p]",
|
|
m_localID.c_str(),m_userName.c_str(),this);
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionITU::handleData(NamedList& params, DataBlock& data)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::handleData() transactionID=%s data length=%u [%p]",m_localID.c_str(),
|
|
data.length(),this);
|
|
Lock lock(this);
|
|
// in case of Abort message, check Cause Information
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
|
|
if (m_type == SS7TCAP::TC_P_Abort) {
|
|
error = decodePAbort(this,params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
}
|
|
else if (testForDialog(data)) {
|
|
// decode DialogPortion
|
|
error = decodeDialogPortion(params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
}
|
|
error = handleDialogPortion(params,false);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
|
|
// decodeComponents
|
|
error = decodeComponents(params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
buildComponentError(error,params,data);
|
|
|
|
error = handleComponents(params,false);
|
|
return error;
|
|
}
|
|
|
|
bool SS7TCAPTransactionITU::testForDialog(DataBlock& data)
|
|
{
|
|
return (data.length() && data[0] == SS7TCAPITU::DialogPortionTag);
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::updateState(bool byUser)
|
|
{
|
|
switch (m_type) {
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
setState(Active);
|
|
break;
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_U_Abort:
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_Response:
|
|
case SS7TCAP::TC_Unidirectional:
|
|
setState(Idle);
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
case SS7TCAP::TC_Unknown:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionITU::update(SS7TCAP::TCAPUserTransActions type, NamedList& params, bool updateByUser)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::update() [%p], localID=%s - update to type=%s by %s",this,m_localID.c_str(),
|
|
lookup(type,SS7TCAP::s_transPrimitives,"Unknown"), (updateByUser ? "user" : "remote"));
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::update() with",this,params);
|
|
#endif
|
|
|
|
Lock l(this);
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
switch (type) {
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
case SS7TCAP::TC_Unidirectional:
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionITU::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
|
|
this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
|
|
lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
params.setParam(s_tcapRequestError,"invalid_update");
|
|
params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
m_type = type;
|
|
if (m_state == PackageReceived) {
|
|
m_basicEnd = params.getBoolValue(s_tcapBasicTerm,m_basicEnd);
|
|
if (!m_basicEnd)
|
|
// prearranged end, no need to transmit to remote end
|
|
m_transmit = NoTransmit;
|
|
else
|
|
m_transmit = PendingTransmit;
|
|
}
|
|
else if (m_state == PackageSent) {
|
|
if(!updateByUser)
|
|
m_transmit = PendingTransmit;
|
|
else
|
|
m_transmit = NoTransmit;
|
|
}
|
|
else if (m_state == Active) {
|
|
if(!updateByUser)
|
|
m_transmit = PendingTransmit;
|
|
else {
|
|
m_basicEnd = params.getBoolValue(s_tcapBasicTerm,m_basicEnd);
|
|
if (!m_basicEnd)
|
|
// prearranged end, no need to transmit to remote end
|
|
m_transmit = NoTransmit;
|
|
else
|
|
m_transmit = PendingTransmit;
|
|
}
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
if (m_state == PackageSent)
|
|
m_remoteID = params.getValue(s_tcapRemoteTID);
|
|
m_type = type;
|
|
m_transmit = PendingTransmit;
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
m_type = type;
|
|
if (updateByUser) {
|
|
Debug(tcap(),DebugInfo,"SS7TCAPTransactionITU::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
|
|
this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
|
|
lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
params.setParam(s_tcapRequestError,"invalid_update");
|
|
params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
|
|
error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
|
|
return error;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_P_Abort:
|
|
case SS7TCAP::TC_U_Abort:
|
|
m_type = type;
|
|
if (m_state == PackageReceived)
|
|
m_transmit = PendingTransmit;
|
|
else if (m_state == PackageSent) {
|
|
if (!updateByUser) {
|
|
if (String("pAbort") == params.getValue(s_tcapAbortCause))
|
|
m_type = SS7TCAP::TC_P_Abort;
|
|
else
|
|
m_type = SS7TCAP::TC_P_Abort;
|
|
m_transmit = PendingTransmit;
|
|
}
|
|
else
|
|
m_transmit = NoTransmit;
|
|
}
|
|
else if (m_state == Active) {
|
|
if (!updateByUser) {
|
|
if (String("pAbort") == params.getValue(s_tcapAbortCause))
|
|
m_type = SS7TCAP::TC_P_Abort;
|
|
else
|
|
m_type = SS7TCAP::TC_P_Abort;
|
|
}
|
|
m_transmit = PendingTransmit;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
populateSCCPAddress(m_localSCCPAddr,m_remoteSCCPAddr,params,updateByUser);
|
|
m_basicEnd = params.getBoolValue(s_tcapBasicTerm,true);
|
|
m_endNow = params.getBoolValue(s_tcapEndNow,m_endNow);
|
|
|
|
if (m_timeout.started()) {
|
|
m_timeout.stop();
|
|
XDebug(tcap(),DebugInfo,"SS7TCAPTransactionITU::update() [%p], localID=%s - timeout timer has been stopped",this,m_localID.c_str());
|
|
}
|
|
return error;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionITU::handleDialogPortion(NamedList& params, bool byUser)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::handleDialogPortion() [%p]",this);
|
|
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
|
|
NamedString* diagPDU = params.getParam(s_tcapDialoguePduType);
|
|
NamedString* appCtxt = params.getParam(s_tcapDialogueAppCtxt);
|
|
int protoVers = params.getIntValue(s_tcapProtoVers,s_ituTCAPProto,0);
|
|
|
|
Lock l(this);
|
|
switch (m_type) {
|
|
case SS7TCAP::TC_Unidirectional:
|
|
if (byUser) {
|
|
// check for context name, if not present no AUDT
|
|
if (TelEngine::null(appCtxt))
|
|
return error;
|
|
m_appCtxt = *appCtxt;
|
|
// build AUDT.
|
|
params.setParam(s_tcapDialogueID,s_unstructDialogueOID.toString());
|
|
if (protoVers)
|
|
params.setParam(s_tcapProtoVers,String(protoVers));
|
|
params.setParam(s_tcapDialoguePduType,lookup(AARQDialogTag,s_dialogPDUs));
|
|
}
|
|
else {
|
|
// check to be AUDT
|
|
if (TelEngine::null(diagPDU) || !protoVers)
|
|
return error;
|
|
if (diagPDU->toInteger(s_dialogPDUs) != AARQDialogTag || s_ituTCAPProto != protoVers)
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Begin:
|
|
case SS7TCAP::TC_QueryWithPerm:
|
|
case SS7TCAP::TC_QueryWithoutPerm:
|
|
if (byUser) {
|
|
if (TelEngine::null(appCtxt))
|
|
break;
|
|
m_appCtxt = *appCtxt;
|
|
// build AARQ
|
|
params.setParam(s_tcapDialogueID,s_structDialogueOID);
|
|
if (protoVers)
|
|
params.setParam(s_tcapProtoVers,String(protoVers));
|
|
params.setParam(s_tcapDialoguePduType,lookup(AARQDialogTag,s_dialogPDUs));
|
|
}
|
|
else {
|
|
if (TelEngine::null(diagPDU) || !protoVers)
|
|
break;
|
|
// check to be AARQ and that it has context
|
|
if (diagPDU->toInteger(s_dialogPDUs) != AARQDialogTag || TelEngine::null(appCtxt)) {
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
break;
|
|
}
|
|
// check proto version, if not 1, build AARE - no common dialogue version, return err to build abort
|
|
if (s_ituTCAPProto != protoVers) {
|
|
params.clearParam(s_tcapDialogPrefix,'.');
|
|
params.setParam(s_tcapDialogueID,s_structDialogueOID);
|
|
params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
|
|
params.setParam(s_tcapDialogueResult,lookup(ResultRejected,s_resultPDUValues));
|
|
params.setParam(s_tcapDialogueDiag,lookup(DiagnosticProviderNoCommonDialog,s_resultPDUValues));
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
break;
|
|
}
|
|
m_appCtxt = *appCtxt;
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_End:
|
|
case SS7TCAP::TC_Response:
|
|
if (byUser) {
|
|
if (!basicEnd() || transactionState() != PackageReceived || m_appCtxt.null()) {
|
|
params.clearParam(s_tcapDialogPrefix,'.');
|
|
break;
|
|
}
|
|
if (TelEngine::null(appCtxt))
|
|
params.setParam(s_tcapDialogueAppCtxt,m_appCtxt);
|
|
// build AARE with result=accepted, result-source-diagnostic=null / dialog-service-user(null)
|
|
params.setParam(s_tcapDialogueID,s_structDialogueOID);
|
|
if (protoVers)
|
|
params.setParam(s_tcapProtoVers,String(protoVers));
|
|
params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
|
|
params.setParam(s_tcapDialogueResult,lookup(ResultAccepted,s_resultPDUValues));
|
|
if (!params.getParam(s_tcapDialogueDiag))
|
|
params.addParam(s_tcapDialogueDiag,lookup(DiagnosticUserNoReason,s_resultPDUValues));
|
|
}
|
|
else {
|
|
// page 51 q.774
|
|
// dialog info ?
|
|
// => yes => AC MODE ? = no, discard components. TC-p-abort to TCU , terminate transaction
|
|
// = yes, check correct AARE, incorrect => TC-P-Abort to user, send TC_END to user otherwise
|
|
// => no =? AC MODE ? = no, send TC_END to user (continue processing)
|
|
// = yes, TC-p-abort to TCU , terminate transaction
|
|
if (transactionState() != PackageSent && !TelEngine::null(diagPDU)) {
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
break;
|
|
}
|
|
if (!TelEngine::null(appCtxt)) {
|
|
if (m_appCtxt.null())
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
else {
|
|
if (TelEngine::null(diagPDU) || diagPDU->toInteger(s_dialogPDUs) != AAREDialogTag)
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
}
|
|
else {
|
|
if (!m_appCtxt.null() && transactionState() != Active)
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Continue:
|
|
case SS7TCAP::TC_ConversationWithPerm:
|
|
case SS7TCAP::TC_ConversationWithoutPerm:
|
|
if (byUser) {
|
|
if (transactionState() != PackageReceived || TelEngine::null(appCtxt)) {
|
|
params.clearParam(s_tcapDialogPrefix,'.');
|
|
break;
|
|
}
|
|
// build AARE
|
|
m_appCtxt = *appCtxt;
|
|
params.setParam(s_tcapDialogueID,s_structDialogueOID);
|
|
if (protoVers)
|
|
params.setParam(s_tcapProtoVers,String(protoVers));
|
|
params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
|
|
params.setParam(s_tcapDialogueResult,lookup(ResultAccepted,s_resultPDUValues));
|
|
if (!params.getParam(s_tcapDialogueDiag))
|
|
params.addParam(s_tcapDialogueDiag,lookup(DiagnosticUserNoReason,s_resultPDUValues));
|
|
}
|
|
else {
|
|
// dialog info?
|
|
// yes => AC MODE? => yes, Check AARE
|
|
// = > no, discard, build P Abort with ABRT apdu
|
|
// no => AC MODE? => no, send to user / continue processing
|
|
// => yes, build U_Abort with ABRT apdu
|
|
if (transactionState() == PackageReceived)
|
|
break;
|
|
if (!TelEngine::null(appCtxt)) {
|
|
if (m_appCtxt.null())
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
else {
|
|
if (TelEngine::null(diagPDU) || diagPDU->toInteger(s_dialogPDUs) != AAREDialogTag)
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
}
|
|
else {
|
|
if (!m_appCtxt.null() && transactionState() == PackageSent)
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
}
|
|
break;
|
|
case SS7TCAP::TC_Notice:
|
|
case SS7TCAP::TC_P_Abort:
|
|
break;
|
|
case SS7TCAP::TC_U_Abort:
|
|
if (byUser) {
|
|
if (m_appCtxt.null())
|
|
break;
|
|
params.setParam(s_tcapDialogueID,s_structDialogueOID);
|
|
if (protoVers)
|
|
params.setParam(s_tcapProtoVers,String(protoVers));
|
|
if (transactionState() == PackageReceived ) {
|
|
NamedString* abrtReason = params.getParam(s_tcapDialogueDiag);
|
|
if (!TelEngine::null(abrtReason) && (abrtReason->toInteger(s_resultPDUValues) == DiagnosticUserAppCtxtNotSupported ||
|
|
abrtReason->toInteger(s_resultPDUValues) == DiagnosticProviderNoCommonDialog)) {
|
|
// build AARE
|
|
if (TelEngine::null(appCtxt))
|
|
params.setParam(s_tcapDialogueAppCtxt,m_appCtxt);
|
|
params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
|
|
params.setParam(s_tcapDialogueResult,lookup(ResultRejected,s_resultPDUValues));
|
|
}
|
|
else {
|
|
// build ABRT
|
|
params.setParam(s_tcapDialoguePduType,lookup(ABRTDialogTag,s_dialogPDUs));
|
|
params.setParam(s_tcapDialogueAbrtSrc,lookup(AbortSourceUser,s_resultPDUValues));
|
|
}
|
|
}
|
|
else if (transactionState() == Active) {
|
|
if (TelEngine::null(params.getParam(s_tcapDialogueAbrtSrc)))
|
|
params.setParam(s_tcapDialogueAbrtSrc,lookup(AbortSourceUser,s_resultPDUValues));
|
|
params.setParam(s_tcapDialoguePduType,lookup(ABRTDialogTag,s_dialogPDUs));
|
|
}
|
|
}
|
|
else {
|
|
// state initsent/active
|
|
if (!TelEngine::null(m_appCtxt)) {
|
|
NamedString* diagID = params.getParam(s_tcapDialogueID);
|
|
NamedString* pdu = params.getParam(s_tcapDialoguePduType);
|
|
if (!TelEngine::null(diagID) && !TelEngine::null(pdu)) {
|
|
if (s_structDialogueOID == *diagID && (pdu->toInteger(s_dialogPDUs) == AAREDialogTag
|
|
|| pdu->toInteger(s_dialogPDUs) == ABRTDialogTag)) {
|
|
|
|
if (pdu->toInteger() == AAREDialogTag) {
|
|
NamedString* diag = params.getParam(s_tcapDialogueDiag);
|
|
if (transactionState() == PackageSent && !TelEngine::null(diag) &&
|
|
diag->toInteger(s_resultPDUValues) != DiagnosticProviderNoCommonDialog) {
|
|
params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_P_Abort,SS7TCAP::s_transPrimitives));
|
|
params.setParam(s_tcapAbortCause,"pAbort");
|
|
m_transmit = PendingTransmit;
|
|
}
|
|
else
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
else {
|
|
NamedString* src = params.getParam(s_tcapDialogueAbrtSrc);
|
|
if (!TelEngine::null(src) && src->toInteger(s_resultPDUValues) != AbortSourceUser)
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
}
|
|
else
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
else
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
else {
|
|
if (!TelEngine::null(appCtxt))
|
|
error.setError(SS7TCAPError::Dialog_Abnormal);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::handleDialogPortion()",this,params,DataBlock::empty());
|
|
#endif
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::abnormalDialogInfo(NamedList& params)
|
|
{
|
|
params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_U_Abort,SS7TCAP::s_transPrimitives));
|
|
params.setParam(s_tcapAbortCause,"uAbort");
|
|
params.setParam(s_tcapDialogueID,s_structDialogueOID);
|
|
params.setParam(s_tcapDialoguePduType,
|
|
lookup(SS7TCAPTransactionITU::ABRTDialogTag,SS7TCAPTransactionITU::s_dialogPDUs));
|
|
params.setParam(s_tcapDialogueAbrtSrc,
|
|
lookup(SS7TCAPTransactionITU::AbortSourceProvider,SS7TCAPTransactionITU::s_resultPDUValues));
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::encodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
|
|
{
|
|
NamedString* pAbortCause = params.getParam(s_tcapAbortCause);
|
|
DataBlock db;
|
|
if (!TelEngine::null(pAbortCause)) {
|
|
int tag = 0;
|
|
if (*pAbortCause == "pAbort") {
|
|
tag = SS7TCAPITU::PCauseTag;
|
|
u_int8_t pCode = SS7TCAPError::codeFromError(SS7TCAP::ITUTCAP,params.getIntValue(s_tcapAbortInfo));
|
|
if (pCode) {
|
|
db.append(ASNLib::encodeInteger(pCode,false));
|
|
db.insert(ASNLib::buildLength(db));
|
|
db.insert(DataBlock(&tag,1));
|
|
}
|
|
}
|
|
else if (*pAbortCause == "uAbort") {
|
|
if (tr)
|
|
tr->encodeDialogPortion(params,data);
|
|
}
|
|
}
|
|
if (db.length())
|
|
data.insert(db);
|
|
|
|
#ifdef DEBUG
|
|
if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionITU::encodePAbort() - encoded Abort info",tr,params,data);
|
|
#endif
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionITU::decodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
|
|
{
|
|
u_int8_t tag = data[0];
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
if (!tr)
|
|
return error;
|
|
SS7TCAPTransactionITU* tri = static_cast<SS7TCAPTransactionITU*>(tr);
|
|
if (!tri)
|
|
return error;
|
|
if (tag == SS7TCAPITU::PCauseTag) {
|
|
data.cut(-1);
|
|
u_int8_t pCode = 0;
|
|
int len = ASNLib::decodeUINT8(data,&pCode,false);
|
|
if (len != 1) {
|
|
error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapAbortCause,"pAbort");
|
|
params.setParam(s_tcapAbortInfo,String(SS7TCAPError::errorFromCode(SS7TCAP::ITUTCAP,pCode)));
|
|
}
|
|
else if (tri->testForDialog(data)) {
|
|
error = tri->decodeDialogPortion(params,data);
|
|
if (error.error() != SS7TCAPError::NoError)
|
|
return error;
|
|
params.setParam(s_tcapAbortCause,"uAbort");
|
|
}
|
|
#ifdef DEBUG
|
|
if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionITU::decodePAbort() - decoded Abort info",tr,params,data);
|
|
#endif
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::updateToEnd()
|
|
{
|
|
setTransactionType(SS7TCAP::TC_End);
|
|
if (transactionState() == PackageSent)
|
|
m_basicEnd = false;
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionITU::decodeDialogPortion(NamedList& params, DataBlock& data)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::decodeDialogPortion() for transaction with localID=%s [%p]",
|
|
m_localID.c_str(),this);
|
|
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
|
|
u_int8_t tag = data[0];
|
|
// dialog is not present
|
|
if (tag != SS7TCAPITU::DialogPortionTag) // 0x6b
|
|
return error;
|
|
data.cut(-1);
|
|
|
|
// dialog portion is present, decode dialog length
|
|
int len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
tag = data[0];
|
|
if (tag != SS7TCAPITU::ExternalTag) {// 0x28
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
// decode dialog-as-id
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,true);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapDialogueID,oid.toString());
|
|
|
|
// remove Encoding Tag
|
|
tag = data[0];
|
|
if (tag != SS7TCAPITU::SingleASNTypeCEncTag) {// 0xa0
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
int dialogPDU = data[0]; // should be DialoguePDU type tag
|
|
if (dialogPDU != AARQDialogTag && dialogPDU != AAREDialogTag && dialogPDU != ABRTDialogTag) {// 0x60 0x61 0x64
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
params.setParam(s_tcapDialoguePduType,lookup(dialogPDU,s_dialogPDUs));
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
// check for protocol version or abort-source
|
|
if (data[0] == SS7TCAPITU::ProtocolVersionTag) { //0x80 bitstring
|
|
data.cut(-1);
|
|
if (dialogPDU != ABRTDialogTag) {
|
|
// decode protocol version
|
|
String proto;
|
|
len = ASNLib::decodeBitString(data,&proto,false);
|
|
if (len != 1) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapProtoVers,proto);
|
|
}
|
|
else {
|
|
u_int8_t abrtSrc = 0xff;
|
|
len = ASNLib::decodeUINT8(data,&abrtSrc,false);
|
|
int code = 0x30 | abrtSrc;
|
|
params.setParam(s_tcapDialogueAbrtSrc,lookup(code,s_resultPDUValues));
|
|
}
|
|
}
|
|
|
|
// check for Application Context Tag length OID tag length
|
|
if (data[0] == SS7TCAPITU::ApplicationContextTag) { // 0xa1
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,true);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapDialogueAppCtxt,oid.toString());
|
|
}
|
|
|
|
if (data[0] == ResultTag) {
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
u_int8_t res = 0xff;
|
|
len = ASNLib::decodeUINT8(data,&res,true);
|
|
params.setParam(s_tcapDialogueResult,lookup(res,s_resultPDUValues));
|
|
}
|
|
|
|
if (data[0] == ResultDiagnosticTag) {
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (data[0] == ResultDiagnosticUserTag || data[0]== ResultDiagnosticProviderTag) {
|
|
tag = data[0];
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
u_int8_t res = 0xff;
|
|
len = ASNLib::decodeUINT8(data,&res,true);
|
|
if (tag == ResultDiagnosticUserTag) {
|
|
int code = 0x10 | res;
|
|
params.setParam(s_tcapDialogueDiag,lookup(code,s_resultPDUValues));
|
|
}
|
|
else {
|
|
int code = 0x20 | res;
|
|
params.setParam(s_tcapDialogueDiag,lookup(code,s_resultPDUValues));
|
|
}
|
|
}
|
|
}
|
|
// check for user information
|
|
if (data[0] == SS7TCAPITU::UserInformationTag) {// 0xfd
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
tag = data[0];
|
|
if (tag != SS7TCAPITU::ExternalTag) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
|
|
// direct Reference
|
|
tag = data[0];
|
|
if (tag == SS7TCAPITU::DirectReferenceTag) { // 0x06
|
|
data.cut(-1);
|
|
ASNObjId oid;
|
|
len = ASNLib::decodeOID(data,&oid,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapReference,oid.toString());
|
|
}
|
|
|
|
// data Descriptor
|
|
tag = data[0];
|
|
if (tag == SS7TCAPITU::DataDescriptorTag) { // 0x07
|
|
data.cut(-1);
|
|
String str;
|
|
int type;
|
|
len = ASNLib::decodeString(data,&str,&type,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
params.setParam(s_tcapDataDesc,str);
|
|
}
|
|
|
|
// encoding
|
|
tag = data[0];
|
|
if (tag == SS7TCAPITU::SingleASNTypePEncTag || tag == SS7TCAPITU::SingleASNTypeCEncTag ||
|
|
tag == SS7TCAPITU::OctetAlignEncTag || tag == SS7TCAPITU::ArbitraryEncTag) {
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
|
|
return error;
|
|
}
|
|
DataBlock d((void*)data.data(0,len),len);
|
|
data.cut(-len);
|
|
|
|
// put encoding context in hexified form
|
|
String dataHexified;
|
|
dataHexified.hexify(d.data(),d.length(),' ');
|
|
params.setParam(s_tcapEncodingContent,dataHexified);
|
|
// put encoding identifier
|
|
switch (tag) {
|
|
case SS7TCAPITU::SingleASNTypePEncTag: // 0x80
|
|
params.setParam(s_tcapEncodingType,"single-ASN1-type-primitive");
|
|
break;
|
|
case SS7TCAPITU::SingleASNTypeCEncTag: // 0xa0
|
|
params.setParam(s_tcapEncodingType,"single-ASN1-type-contructor");
|
|
break;
|
|
case SS7TCAPITU::OctetAlignEncTag: // 0x81
|
|
params.setParam(s_tcapEncodingType,"octet-aligned");
|
|
break;
|
|
case SS7TCAPITU::ArbitraryEncTag: // 0x82
|
|
params.setParam(s_tcapEncodingType,"arbitrary");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::decodeDialogPortion() - decoded dialog portion",this,params,data);
|
|
#endif
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::encodeDialogPortion(NamedList& params, DataBlock& data)
|
|
{
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::encodeDialogPortion() for transaction with localID=%s [%p]",
|
|
m_localID.c_str(),this);
|
|
|
|
DataBlock dialogData;
|
|
int tag;
|
|
|
|
NamedString* typeStr = params.getParam(s_tcapDialoguePduType);
|
|
if (TelEngine::null(typeStr))
|
|
return;
|
|
u_int8_t pduType = typeStr->toInteger(s_dialogPDUs);
|
|
|
|
// encode user information
|
|
DataBlock userInfo;
|
|
NamedString* val = params.getParam(s_tcapEncodingType);
|
|
if (!TelEngine::null(val)) {
|
|
if (*val == "single-ASN1-type-primitive")
|
|
tag = SS7TCAPITU::SingleASNTypePEncTag;
|
|
else if (*val == "single-ASN1-type-contructor")
|
|
tag = SS7TCAPITU::SingleASNTypeCEncTag;
|
|
else if (*val == "octet-aligned")
|
|
tag = SS7TCAPITU::OctetAlignEncTag;
|
|
else if (*val == "arbitrary")
|
|
tag = SS7TCAPITU::ArbitraryEncTag;
|
|
|
|
val = params.getParam(s_tcapEncodingContent);
|
|
if (val) {
|
|
DataBlock db;
|
|
db.unHexify(val->c_str(),val->length(),' ');
|
|
db.insert(ASNLib::buildLength(db));
|
|
db.insert(DataBlock(&tag,1));
|
|
userInfo.insert(db);
|
|
}
|
|
}
|
|
val = params.getParam(s_tcapDataDesc);
|
|
if (!TelEngine::null(val)) {
|
|
DataBlock db = ASNLib::encodeString(*val,ASNLib::PRINTABLE_STR,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPITU::DataDescriptorTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
userInfo.insert(db);
|
|
}
|
|
val = params.getParam(s_tcapReference);
|
|
if (!TelEngine::null(val)) {
|
|
ASNObjId oid = *val;
|
|
DataBlock db = ASNLib::encodeOID(oid,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPITU::DirectReferenceTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
userInfo.insert(db);
|
|
}
|
|
|
|
if (userInfo.length()) {
|
|
userInfo.insert(ASNLib::buildLength(userInfo));
|
|
tag = SS7TCAPITU::ExternalTag;
|
|
userInfo.insert(DataBlock(&tag,1));
|
|
userInfo.insert(ASNLib::buildLength(userInfo));
|
|
tag = SS7TCAPITU::UserInformationTag;
|
|
userInfo.insert(DataBlock(&tag,1));
|
|
dialogData.insert(userInfo);
|
|
}
|
|
|
|
switch (pduType) {
|
|
case AAREDialogTag:
|
|
val = params.getParam(s_tcapDialogueDiag);
|
|
if (!TelEngine::null(val)) {
|
|
u_int16_t code = val->toInteger(s_resultPDUValues);
|
|
DataBlock db = ASNLib::encodeInteger(code % 0x10,true);
|
|
db.insert(ASNLib::buildLength(db));
|
|
if ((code & 0x10) == 0x10)
|
|
tag = ResultDiagnosticUserTag;
|
|
else
|
|
tag = ResultDiagnosticProviderTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = ResultDiagnosticTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
dialogData.insert(db);
|
|
}
|
|
|
|
val = params.getParam(s_tcapDialogueResult);
|
|
if (!TelEngine::null(val)) {
|
|
u_int8_t res = val->toInteger(s_resultPDUValues);
|
|
DataBlock db = ASNLib::encodeInteger(res,true);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = ResultTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
dialogData.insert(db);
|
|
}
|
|
case AARQDialogTag:
|
|
// Application context
|
|
val = params.getParam(s_tcapDialogueAppCtxt);
|
|
if (!TelEngine::null(val)) {
|
|
ASNObjId oid = *val;
|
|
DataBlock db = ASNLib::encodeOID(oid,true);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPITU::ApplicationContextTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
dialogData.insert(db);
|
|
}
|
|
val = params.getParam(s_tcapProtoVers);
|
|
if (!TelEngine::null(val) && (val->toInteger() > 0)) {
|
|
DataBlock db = ASNLib::encodeBitString(*val,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPITU::ProtocolVersionTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
dialogData.insert(db);
|
|
}
|
|
break;
|
|
case ABRTDialogTag:
|
|
val = params.getParam(s_tcapDialogueAbrtSrc);
|
|
if (!TelEngine::null(val)) {
|
|
u_int8_t code = val->toInteger(s_resultPDUValues) % 0x30;
|
|
DataBlock db = ASNLib::encodeInteger(code,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
tag = SS7TCAPITU::ProtocolVersionTag;
|
|
db.insert(DataBlock(&tag,1));
|
|
dialogData.insert(db);
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
dialogData.insert(ASNLib::buildLength(dialogData));
|
|
dialogData.insert(DataBlock(&pduType,1));
|
|
dialogData.insert(ASNLib::buildLength(dialogData));
|
|
tag = SS7TCAPITU::SingleASNTypeCEncTag;
|
|
dialogData.insert(DataBlock(&tag,1));
|
|
|
|
val = params.getParam(s_tcapDialogueID);
|
|
if (TelEngine::null(val))
|
|
return;
|
|
|
|
ASNObjId oid = *val;
|
|
dialogData.insert(ASNLib::encodeOID(oid,true));
|
|
dialogData.insert(ASNLib::buildLength(dialogData));
|
|
tag = SS7TCAPITU::ExternalTag;
|
|
dialogData.insert(DataBlock(&tag,1));
|
|
dialogData.insert(ASNLib::buildLength(dialogData));
|
|
tag = SS7TCAPITU::DialogPortionTag;
|
|
dialogData.insert(DataBlock(&tag,1));
|
|
|
|
data.insert(dialogData);
|
|
params.clearParam(s_tcapDialogPrefix,'.');
|
|
#ifdef DEBUG
|
|
if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::encodeDialogPortion() - encoded dialog portion",this,params,data);
|
|
#endif
|
|
}
|
|
|
|
SS7TCAPError SS7TCAPTransactionITU::decodeComponents(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::decodeComponents() [%p] - data length=%u",this,data.length());
|
|
|
|
SS7TCAPError error(SS7TCAP::ITUTCAP);
|
|
if (!data.length()) {
|
|
params.setParam(s_tcapCompCount,"0");
|
|
return error;
|
|
}
|
|
|
|
u_int8_t tag = data[0];
|
|
if (tag != SS7TCAPITU::ComponentPortionTag) { // 0x6c
|
|
error.setError(SS7TCAPError::General_IncorrectComponentPortion);
|
|
return error;
|
|
}
|
|
data.cut(-1);
|
|
|
|
// decode length of component portion
|
|
int len = ASNLib::decodeLength(data);
|
|
bool checkEoC = (len == ASNLib::IndefiniteForm);
|
|
if (!checkEoC && (len < 0 || len != (int)data.length())) { // the length of the remaining data should be the same as the decoded length
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
return error;
|
|
}
|
|
|
|
unsigned int compCount = 0;
|
|
while (data.length()) {
|
|
if (checkEoC && ASNLib::matchEOC(data) > 0)
|
|
break;
|
|
compCount++;
|
|
// decode component type
|
|
u_int8_t compType = data[0];
|
|
data.cut(-1);
|
|
|
|
// verify component length
|
|
len = ASNLib::decodeLength(data);
|
|
if (len < 0 || len > (int)data.length()) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
unsigned int initLength = data.length();
|
|
unsigned int compLength = len;
|
|
|
|
// decode invoke id
|
|
u_int16_t compID;
|
|
tag = data[0];
|
|
bool notDeriv = false;
|
|
if (tag != SS7TCAPITU::LocalTag) {// 0x02
|
|
if (compType == Reject) {
|
|
ASNLib::decodeNull(data,true);
|
|
notDeriv = true;
|
|
}
|
|
else {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
} else {
|
|
data.cut(-1);
|
|
|
|
// obtain component ID(s)
|
|
len = ASNLib::decodeUINT16(data,&compID,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
}
|
|
String compParam;
|
|
compPrefix(compParam,compCount,false);
|
|
// comp IDs shall be decoded according to component type
|
|
switch (compType) {
|
|
case Invoke:
|
|
params.setParam(compParam + "." + s_tcapRemoteCID,String(compID));
|
|
if (data[0] == SS7TCAPITU::LinkedIDTag) {
|
|
data.cut(-1);
|
|
u_int16_t linkID;
|
|
len = ASNLib::decodeUINT16(data,&linkID,false);
|
|
if (len < 0) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
params.setParam(compParam + "." + s_tcapLocalCID,String(compID));
|
|
}
|
|
break;
|
|
case ReturnResultLast:
|
|
case ReturnError:
|
|
case Reject:
|
|
case ReturnResultNotLast:
|
|
if (notDeriv)
|
|
params.setParam(compParam + "." + s_tcapLocalCID,"");
|
|
else
|
|
params.setParam(compParam + "." + s_tcapLocalCID,String(compID));
|
|
break;
|
|
default:
|
|
error.setError(SS7TCAPError::General_UnrecognizedComponentType);
|
|
break;
|
|
}
|
|
|
|
const PrimitiveMapping* map = mapCompPrimitivesITU(-1,compType);
|
|
if (!map) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
params.setParam(compParam + "." + s_tcapCompType,lookup(map->primitive,SS7TCAP::s_compPrimitives,"Unknown"));
|
|
|
|
if (error.error() != SS7TCAPError::NoError) {
|
|
break;
|
|
}
|
|
|
|
// decode Operation Code
|
|
if (compType == Invoke ||
|
|
compType == ReturnResultLast ||
|
|
compType == ReturnResultNotLast) {
|
|
tag = data[0];
|
|
if (tag == SS7TCAPITU::ParameterSeqTag) {
|
|
data.cut(-1);
|
|
len = ASNLib::decodeLength(data);
|
|
}
|
|
tag = data[0];
|
|
if (tag == SS7TCAPITU::LocalTag) {
|
|
data.cut(-1);
|
|
int opCode = 0;
|
|
len = ASNLib::decodeINT32(data,&opCode,false);
|
|
params.setParam(compParam +"." + s_tcapOpCodeType,"local");
|
|
params.setParam(compParam + "." + s_tcapOpCode,String(opCode));
|
|
}
|
|
else if (tag == SS7TCAPITU::GlobalTag) {
|
|
data.cut(-1);
|
|
ASNObjId obj;
|
|
len = ASNLib::decodeOID(data,&obj,false);
|
|
params.setParam(compParam + "." + s_tcapOpCodeType,"global");
|
|
params.setParam(compParam + "." + s_tcapOpCode,obj.toString());
|
|
}
|
|
else if (compType == Invoke) {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// decode Error Code
|
|
if (compType == ReturnError) {
|
|
tag = data[0];
|
|
if (tag == SS7TCAPITU::LocalTag) {
|
|
data.cut(-1);
|
|
int opCode = 0;
|
|
len = ASNLib::decodeINT32(data,&opCode,false);
|
|
params.setParam(compParam + "." + s_tcapErrCodeType,"local");
|
|
params.setParam(compParam + "." + s_tcapErrCode,String(opCode));
|
|
}
|
|
else if (tag == SS7TCAPITU::GlobalTag) {
|
|
data.cut(-1);
|
|
ASNObjId obj;
|
|
len = ASNLib::decodeOID(data,&obj,false);
|
|
params.setParam(compParam + "." + s_tcapErrCodeType,"global");
|
|
params.setParam(compParam + "." + s_tcapErrCode,obj.toString());
|
|
}
|
|
else {
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// decode Problem
|
|
if (compType == Reject) {
|
|
tag = data[0];
|
|
data.cut(-1);
|
|
u_int16_t problemCode = 0x0 | (tag << 8);
|
|
u_int8_t code = 0;
|
|
len = ASNLib::decodeUINT8(data,&code,false);
|
|
problemCode |= code;
|
|
params.setParam(compParam + "." + s_tcapProblemCode,String(SS7TCAPError::errorFromCode(tcap()->tcapType(),problemCode)));
|
|
}
|
|
else {
|
|
// decode Parameters (Set or Sequence) as payload
|
|
int payloadLen = data.length() - (initLength - compLength);
|
|
DataBlock d((void*)data.data(0,payloadLen),payloadLen);
|
|
data.cut(-payloadLen);
|
|
String dataHexified = "";
|
|
dataHexified.hexify(d.data(),d.length(),' ');
|
|
params.setParam(compParam,dataHexified);
|
|
}
|
|
if (initLength - data.length() != compLength) { // check we consumed the announced component length
|
|
error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
|
|
break;
|
|
}
|
|
}
|
|
|
|
params.setParam(s_tcapCompCount,String(compCount));
|
|
#ifdef DEBUG
|
|
if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
|
|
dumpData(DebugAll,tcap(),"Finished decoding message",this,params,data);
|
|
#endif
|
|
return error;
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::encodeComponents(NamedList& params, DataBlock& data)
|
|
{
|
|
XDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::encodeComponents() for transaction with localID=%s [%p]",m_localID.c_str(),this);
|
|
|
|
int componentCount = params.getIntValue(s_tcapCompCount,0);
|
|
DataBlock compData;
|
|
if (componentCount) {
|
|
int index = componentCount + 1;
|
|
|
|
while (--index) {
|
|
DataBlock codedComp;
|
|
// encode parameters
|
|
String compParam;
|
|
compPrefix(compParam,index,false);
|
|
// Component Type
|
|
int compPrimitive = lookup(params.getValue(compParam + "." + s_tcapCompType,"Unknown"),SS7TCAP::s_compPrimitives);
|
|
const PrimitiveMapping* map = mapCompPrimitivesITU(compPrimitive,-1);
|
|
if (!map)
|
|
continue;
|
|
int compType = map->mappedTo;
|
|
|
|
NamedString* value = 0;
|
|
bool hasPayload = false;
|
|
if (compType == Reject) {
|
|
value = params.getParam(compParam + "." + s_tcapProblemCode);
|
|
if (!TelEngine::null(value)) {
|
|
u_int16_t codeErr = SS7TCAPError::codeFromError(tcap()->tcapType(),(SS7TCAPError::ErrorType)value->toInteger());
|
|
u_int8_t problemTag = (codeErr & 0xff00) >> 8;
|
|
u_int8_t code = codeErr & 0x000f;
|
|
DataBlock db(DataBlock(&code,1));
|
|
db.insert(ASNLib::buildLength(db));
|
|
db.insert(DataBlock(&problemTag,1));
|
|
codedComp.insert(db);
|
|
}
|
|
else {
|
|
Debug(tcap(),DebugWarn,"Missing mandatory 'problemCode' information for component with index='%d' from transaction "
|
|
"with localID=%s [%p]",index,m_localID.c_str(),this);
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
NamedString* payloadHex = params.getParam(compParam);
|
|
if (!TelEngine::null(payloadHex)) {
|
|
DataBlock payload;
|
|
payload.unHexify(payloadHex->c_str(),payloadHex->length(),' ');
|
|
codedComp.insert(payload);
|
|
hasPayload = true;
|
|
}
|
|
}
|
|
// encode Error Code only if ReturnError
|
|
if (compType == ReturnError) {
|
|
value = params.getParam(compParam + "." + s_tcapErrCodeType);
|
|
if (!TelEngine::null(value)) {
|
|
int tag = 0;
|
|
DataBlock db;
|
|
if (*value == "local") {
|
|
tag = SS7TCAPITU::LocalTag;
|
|
int errCode = params.getIntValue(compParam + "." + s_tcapErrCode,0);
|
|
db = ASNLib::encodeInteger(errCode,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
}
|
|
else if (*value == "global") {
|
|
tag = SS7TCAPITU::GlobalTag;
|
|
ASNObjId oid = String(params.getValue(compParam + "." + s_tcapErrCode));
|
|
db = ASNLib::encodeOID(oid,false);
|
|
db.insert(ASNLib::buildLength(db));
|
|
}
|
|
db.insert(DataBlock(&tag,1));
|
|
codedComp.insert(db);
|
|
}
|
|
else {
|
|
Debug(tcap(),DebugWarn,"Missing mandatory 'errorCodeType' information for component with index='%d' from transaction "
|
|
"with localID=%s [%p]",index,m_localID.c_str(),this);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// encode Operation Code only if Invoke
|
|
if (compType == Invoke ||
|
|
compType == ReturnResultNotLast ||
|
|
compType == ReturnResultLast) {
|
|
value = params.getParam(compParam + "." + s_tcapOpCodeType);
|
|
if (!TelEngine::null(value)) {
|
|
int tag = 0;
|
|
DataBlock db;
|
|
if (*value == "local") {
|
|
int opCode = params.getIntValue(compParam + "." + s_tcapOpCode,0);
|
|
db = ASNLib::encodeInteger(opCode,true);
|
|
}
|
|
else if (*value == "global") {
|
|
ASNObjId oid(params.getValue(compParam + "." + s_tcapOpCode));
|
|
db = ASNLib::encodeOID(oid,true);
|
|
//db.insert(ASNLib::buildLength(db));
|
|
}
|
|
codedComp.insert(db);
|
|
if (compType != Invoke) {
|
|
tag = SS7TCAPITU::ParameterSeqTag;
|
|
codedComp.insert(ASNLib::buildLength(codedComp));
|
|
codedComp.insert(DataBlock(&tag,1));
|
|
}
|
|
}
|
|
else {
|
|
if (compType == Invoke || hasPayload) {
|
|
Debug(tcap(),DebugWarn,"Missing mandatory 'operationCodeType' information for component with index='%d' from transaction "
|
|
"with localID=%s [%p]",index,m_localID.c_str(),this);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
NamedString* invID = params.getParam(compParam + "." + s_tcapLocalCID);
|
|
NamedString* linkID = params.getParam(compParam + "." + s_tcapRemoteCID);
|
|
DataBlock db;
|
|
u_int8_t val = 0;
|
|
switch (compType) {
|
|
case Invoke:
|
|
if (!TelEngine::null(linkID)) {
|
|
val = linkID->toInteger();
|
|
DataBlock db1;
|
|
db1.append(&val,sizeof(u_int8_t));
|
|
db1.insert(ASNLib::buildLength(db1));
|
|
val = SS7TCAPITU::LinkedIDTag;
|
|
db1.insert(DataBlock(&val,1));
|
|
codedComp.insert(db1);
|
|
}
|
|
if (!TelEngine::null(invID)) {
|
|
val = invID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
db.insert(ASNLib::buildLength(db));
|
|
val = SS7TCAPITU::LocalTag;
|
|
db.insert(DataBlock(&val,1));
|
|
}
|
|
else {
|
|
Debug(tcap(),DebugWarn,"Missing mandatory 'localCID' information for component with index='%d' from transaction "
|
|
"with localID=%s [%p]",index,m_localID.c_str(),this);
|
|
continue;
|
|
}
|
|
break;
|
|
case ReturnResultLast:
|
|
case ReturnError:
|
|
case ReturnResultNotLast:
|
|
if (!TelEngine::null(linkID)) {
|
|
val = linkID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
db.insert(ASNLib::buildLength(db));
|
|
val = SS7TCAPITU::LocalTag;
|
|
db.insert(DataBlock(&val,1));
|
|
}
|
|
else {
|
|
Debug(tcap(),DebugWarn,"Missing mandatory 'remoteCID' information for component with index='%d' from transaction "
|
|
"with localID=%s [%p]",index,m_localID.c_str(),this);
|
|
continue;
|
|
}
|
|
break;
|
|
case Reject:
|
|
if (TelEngine::null(linkID))
|
|
linkID = invID;
|
|
if (!TelEngine::null(linkID)) {
|
|
val = linkID->toInteger();
|
|
db.append(&val,sizeof(u_int8_t));
|
|
db.insert(ASNLib::buildLength(db));
|
|
val = SS7TCAPITU::LocalTag;
|
|
db.insert(DataBlock(&val,1));
|
|
}
|
|
else
|
|
db.insert(ASNLib::encodeNull(true));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
codedComp.insert(db);
|
|
|
|
if(codedComp.length()) {
|
|
codedComp.insert(ASNLib::buildLength(codedComp));
|
|
codedComp.insert(DataBlock(&compType,1));
|
|
}
|
|
|
|
params.clearParam(compParam,'.'); // clear all params for this component
|
|
compData.insert(codedComp);
|
|
}
|
|
|
|
if (compData.length()) {
|
|
compData.insert(ASNLib::buildLength(compData));
|
|
int tag = SS7TCAPITU::ComponentPortionTag;
|
|
compData.insert(DataBlock(&tag,1));
|
|
|
|
data.insert(compData);
|
|
}
|
|
}
|
|
|
|
params.clearParam(s_tcapCompPrefix,'.');
|
|
}
|
|
|
|
void SS7TCAPTransactionITU::requestContent(NamedList& params, DataBlock &data)
|
|
{
|
|
#ifdef DEBUG
|
|
DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::requestContent() - for id=%s [%p]",m_localID.c_str(),this);
|
|
#endif
|
|
if (m_type == SS7TCAP::TC_P_Abort || m_type == SS7TCAP::TC_U_Abort)
|
|
encodePAbort(this,params,data);
|
|
else {
|
|
requestComponents(params,data);
|
|
if (dialogPresent()) {
|
|
if (TelEngine::null(params.getParam(s_tcapDialoguePduType)))
|
|
handleDialogPortion(params,true);
|
|
encodeDialogPortion(params,data);
|
|
}
|
|
}
|
|
transactionData(params);
|
|
}
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|