1 /**
2  * tcap.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
6  *
7  * Yet Another Telephony Engine - a fully featured software PBX and IVR
8  * Copyright (C) 2004-2014 Null Team
9  *
10  * This software is distributed under multiple licenses;
11  * see the COPYING file in the main directory for licensing
12  * information for this specific distribution.
13  *
14  * This use of this software may be subject to additional restrictions.
15  * See the LEGAL file in the main directory for details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include "yatesig.h"
23 #include "yateasn.h"
24 
25 
26 using namespace TelEngine;
27 
28 #ifdef DEBUG
dumpData(int debugLevel,SS7TCAP * tcap,String message,void * obj,NamedList & params,DataBlock data=DataBlock::empty ())29 static void dumpData(int debugLevel, SS7TCAP* tcap, String message, void* obj, NamedList& params,
30 		    DataBlock data = DataBlock::empty())
31 {
32     if (tcap) {
33 	String tmp;
34 	params.dump(tmp,"\r\n  ",'\'',true);
35 	String str;
36 	str.hexify(data.data(),data.length(),' ');
37 	Debug(tcap,debugLevel,"%s [%p] - \r\nparams='%s',\r\ndata='%s'",
38 	    message.safe(),obj,tmp.c_str(),str.c_str());
39     }
40 }
41 #endif
42 
~TCAPUser()43 TCAPUser::~TCAPUser()
44 {
45     Debug(this,DebugAll,"TCAPUser::~TCAPUser() [%p] - tcap user destroyed",this);
46 }
47 
destroyed()48 void TCAPUser::destroyed()
49 {
50     Debug(this,DebugAll,"TCAPUser::destroyed() [%p]",this);
51     Lock lock(m_tcapMtx);
52     if (m_tcap) {
53 	// notify SCCP OutOfService
54 	NamedList p("");
55 	m_tcap->updateUserStatus(this,SCCPManagement::UserOutOfService,p);
56 
57 	m_tcap->detach(this);
58 	Debug(this,DebugAll,"TCAPUser::~TCAPUser() [%p] - Detached from TCAP (%p,%s)",this,m_tcap,m_tcap->toString().safe());
59 	m_tcap->deref();
60 	m_tcap = 0;
61     }
62     lock.drop();
63     SignallingComponent::destroyed();
64 }
65 
attach(SS7TCAP * tcap)66 void TCAPUser::attach(SS7TCAP* tcap)
67 {
68     Lock lock(m_tcapMtx);
69 
70     if (m_tcap == tcap)
71 	return;
72     SS7TCAP* tmp = m_tcap;
73     m_tcap = tcap;
74     lock.drop();
75     DDebug(this,DebugAll,"TCAPUser::attach(tcap=%s [%p], replacing tcap=%s [%p] [%p]",(m_tcap ? m_tcap->toString().safe() : ""),m_tcap,
76 	    (tmp ? tmp->toString().c_str() : ""),tmp,this);
77     if (tmp) {
78 	tmp->detach(this);
79 	Debug(this,DebugAll,"TCAPUser::attach() - Detached from TCAP (%p,%s) [%p]",tmp,tmp->toString().safe(),this);
80 	tmp->deref();
81 	tmp = 0;
82     }
83     if (!tcap)
84 	return;
85 
86     tcap->attach(this);
87     tcap->ref();
88     Debug(this,DebugAll,"Attached to TCAP (%p,%s) [%p] tcapRefCount=%d",tcap,tcap->toString().safe(),this,tcap->refcount());
89 }
90 
tcapIndication(NamedList & params)91 bool TCAPUser::tcapIndication(NamedList& params)
92 {
93     Debug(this,DebugStub,"Please implement TCAPUser::tcapIndication()");
94     return false;
95 }
96 
managementNotify(SCCP::Type type,NamedList & params)97 bool TCAPUser::managementNotify(SCCP::Type type, NamedList& params)
98 {
99     Debug(this,DebugStub,"Please implement TCAPUser::managementNotify()");
100     return false;
101 }
102 
managementState()103 int TCAPUser::managementState()
104 {
105     return SCCPManagement::UserOutOfService;
106 }
107 
108 struct PrimitiveMapping {
109     int primitive;
110     int mappedTo;
111 };
112 
113 static bool s_extendedDbg = false;
114 static bool s_printMsgs = false;
115 static const String s_checkAddr = "tcap.checkAddress";
116 static const String s_localPC = "LocalPC";
117 static const String s_remotePC = "RemotePC";
118 static const String s_callingPA = "CallingPartyAddress";
119 static const String s_callingSSN = "CallingPartyAddress.ssn";
120 static const String s_callingRoute = "CallingPartyAddress.route";
121 static const String s_calledPA = "CalledPartyAddress";
122 static const String s_calledSSN = "CalledPartyAddress.ssn";
123 static const String s_HopCounter = "HopCounter";
124 
125 // TCAP message parameters
126 static const String s_tcapUser = "tcap.user";
127 static const String s_tcapBasicTerm = "tcap.transaction.terminationBasic";
128 static const String s_tcapEndNow = "tcap.transaction.endNow";
129 static const String s_tcapRequest = "tcap.request.type";
130 static const String s_tcapRequestError = "tcap.request.error";
131 static const String s_tcapTransPrefix = "tcap.transaction";
132 static const String s_tcapMsgType = "tcap.transaction.messageType";
133 static const String s_tcapLocalTID = "tcap.transaction.localTID";
134 static const String s_tcapRemoteTID = "tcap.transaction.remoteTID";
135 static const String s_tcapAbortCause = "tcap.transaction.abort.cause";
136 static const String s_tcapAbortInfo = "tcap.transaction.abort.information";
137 
138 static const String s_tcapDialogPrefix = "tcap.dialogPDU";
139 static const String s_tcapProtoVers = "tcap.dialogPDU.protocol-version";
140 static const String s_tcapIntAppID = "tcap.dialogPDU.integerApplicationId";
141 static const String s_tcapObjAppID = "tcap.dialogPDU.objectApplicationId";
142 static const String s_tcapIntSecID = "tcap.dialogPDU.integerSecurityId";
143 static const String s_tcapObjSecID = "tcap.dialogPDU.objectSecurityId";
144 static const String s_tcapIntConfidID = "tcap.dialogPDU.integerConfidentialityId";
145 static const String s_tcapObjConfidID = "tcap.dialogPDU.objectConfidentialityId";
146 static const String s_tcapReference = "tcap.dialogPDU.userInformation.direct-reference";
147 static const String s_tcapDataDesc = "tcap.dialogPDU.userInformation.data-descriptor";
148 static const String s_tcapEncodingContent = "tcap.dialogPDU.userInformation.encoding-contents";
149 static const String s_tcapEncodingType = "tcap.dialogPDU.userInformation.encoding-type";
150 
151 static const String s_tcapCompCount = "tcap.component.count";
152 static const String s_tcapCompPrefix = "tcap.component";
153 static const String s_tcapLocalCID = "localCID";
154 static const String s_tcapRemoteCID = "remoteCID";
155 static const String s_tcapCompType = "componentType";
156 static const String s_tcapOpCodeType = "operationCodeType";
157 static const String s_tcapOpCode = "operationCode";
158 static const String s_tcapErrCodeType = "errorCodeType";
159 static const String s_tcapErrCode = "errorCode";
160 static const String s_tcapProblemCode = "problemCode";
161 static const String s_tcapPayload = "payload";
162 
163 
populateSCCPAddress(NamedList & localAddr,NamedList & remoteAddr,NamedList & initParams,bool initLocal,bool keepPrefix=false)164 static void populateSCCPAddress(NamedList& localAddr, NamedList& remoteAddr, NamedList& initParams, bool initLocal,
165 	bool keepPrefix = false)
166 {
167     String localParam(initLocal ? s_callingPA : s_calledPA);
168     String remoteParam(initLocal ? s_calledPA : s_callingPA);
169 
170     NamedList aux("");
171     aux.copySubParams(initParams,localParam + ".");
172     if (keepPrefix) {
173 	for (unsigned int i = 0; i < aux.count(); i++) {
174 	    NamedString* p = aux.getParam(i);
175 	    if (!TelEngine::null(p)) {
176 		localAddr.setParam(remoteParam + "." +  p->name(),*p);
177 	    }
178 	}
179     }
180     else
181 	localAddr.copyParams(aux);
182     if (!TelEngine::null(initParams.getParam(s_localPC)))
183 	localAddr.copyParam(initParams,s_localPC);
184 
185     aux.clearParams();
186     aux.copySubParams(initParams,remoteParam + ".");
187     if (keepPrefix) {
188 	for (unsigned int i = 0; i < aux.count(); i++) {
189 	    NamedString* p = aux.getParam(i);
190 	    if (!TelEngine::null(p)) {
191 		remoteAddr.setParam(localParam + "." +  p->name(),*p);
192 	    }
193 	}
194     }
195     else
196 	remoteAddr.copyParams(aux);
197     if (!TelEngine::null(initParams.getParam(s_remotePC)))
198 	remoteAddr.copyParam(initParams,s_remotePC);
199 }
200 
compPrefix(String & prefix,unsigned int index,bool endSep=false)201 static void compPrefix(String& prefix, unsigned int index, bool endSep = false)
202 {
203     prefix = s_tcapCompPrefix;
204     prefix << "." << index << (endSep ? "." : "");
205 }
206 
207 /**
208  * SS7TCAP implementation
209  */
210 const TokenDict SS7TCAP::s_tcapVersion[] = {
211     {"UnknownTCAP", SS7TCAP::UnknownTCAP},
212     {"ITU-T TCAP",  SS7TCAP::ITUTCAP},
213     {"ANSI TCAP",   SS7TCAP::ANSITCAP},
214     {0,0},
215 };
216 
217 const TokenDict SS7TCAP::s_compPrimitives[] = {
218     {"Invoke",           SS7TCAP::TC_Invoke},
219     {"ResultLast",       SS7TCAP::TC_ResultLast},
220     {"U_Error",          SS7TCAP::TC_U_Error},
221     {"U_Reject",         SS7TCAP::TC_U_Reject},
222     {"R_Reject",         SS7TCAP::TC_R_Reject},
223     {"L_Reject",         SS7TCAP::TC_L_Reject},
224     {"InvokeNotLast",    SS7TCAP::TC_InvokeNotLast},
225     {"ResultNotLast",    SS7TCAP::TC_ResultNotLast},
226     {"L_Cancel",         SS7TCAP::TC_L_Cancel},
227     {"U_Cancel",         SS7TCAP::TC_U_Cancel},
228     {"TimerReset",       SS7TCAP::TC_TimerReset},
229     {0,0},
230 };
231 
232 const TokenDict SS7TCAP::s_transPrimitives[] = {
233     {"Unidirectional",             SS7TCAP::TC_Unidirectional},
234     {"Begin",                      SS7TCAP::TC_Begin},
235     {"QueryWithPerm",              SS7TCAP::TC_QueryWithPerm},
236     {"QueryWithoutPerm",           SS7TCAP::TC_QueryWithoutPerm},
237     {"Continue",                   SS7TCAP::TC_Continue},
238     {"ConversationWithPerm",       SS7TCAP::TC_ConversationWithPerm},
239     {"ConversationWithoutPerm",    SS7TCAP::TC_ConversationWithoutPerm},
240     {"End",                        SS7TCAP::TC_End},
241     {"Response",                   SS7TCAP::TC_Response},
242     {"U_Abort",                    SS7TCAP::TC_U_Abort},
243     {"P_Abort",                    SS7TCAP::TC_P_Abort},
244     {"Notice",                     SS7TCAP::TC_Notice},
245     {"Unknown",                    SS7TCAP::TC_Unknown},
246     {0,0},
247 };
248 
249 const TokenDict SS7TCAP::s_compOperClasses[] = {
250     {"reportAll",        SS7TCAP::SuccessOrFailureReport},
251     {"reportFail",       SS7TCAP::FailureOnlyReport},
252     {"reportSuccess",    SS7TCAP::SuccessOnlyReport},
253     {"reportNone",       SS7TCAP::NoReport},
254     {0,0},
255 };
256 
257 
SS7TCAP(const NamedList & params)258 SS7TCAP::SS7TCAP(const NamedList& params)
259     : SCCPUser(params),
260       m_usersMtx(true,"TCAPUsers"),
261       m_inQueueMtx(true,"TCAPPendingMsg"),
262       m_SSN(0),
263       m_defaultRemoteSSN(0),
264       m_defaultHopCounter(0),
265       m_defaultRemotePC(0),
266       m_remoteTypePC(SS7PointCode::Other),
267       m_trTimeout(300),
268       m_transactionsMtx(true,"TCAPTransactions"),
269       m_tcapType(UnknownTCAP),
270       m_idsPool(0)
271 {
272     Debug(this,DebugAll,"SS7TCAP::SS7TCAP() [%p] created",this);
273     m_recvMsgs = m_sentMsgs = m_discardMsgs = m_normalMsgs = m_abnormalMsgs = 0;
274     m_ssnStatus = SCCPManagement::UserOutOfService;
275 }
276 
~SS7TCAP()277 SS7TCAP::~SS7TCAP()
278 {
279     Debug(this,DebugAll,"SS7TCAP::~SS7TCAP() [%p] destroyed, refCount=%d, usersCount=%d",this,refcount(),m_users.count());
280     if (m_users.count()) {
281 	Debug(this,DebugCrit,"SS7TCAP destroyed while having %d user(s) still attached [%p]",m_users.count(),this);
282 	ListIterator iter(m_users);
283 	for (;;) {
284 	    TCAPUser* user = static_cast<TCAPUser*>(iter.get());
285 	    // End of iteration?
286 	    if (!user)
287 		break;
288 	    if(user->tcap())
289 		user->setTCAP(0);
290 	}
291 	m_users.setDelete(false);
292     }
293     m_transactions.clear();
294     m_inQueue.clear();
295 
296 }
297 
initialize(const NamedList * config)298 bool SS7TCAP::initialize(const NamedList* config)
299 {
300 #ifdef DEBUG
301     if(config && debugAt(DebugAll)) {
302 	String tmp;
303 	config->dump(tmp,"\r\n  ",'\'',true);
304 	Debug(this,DebugAll,"SS7TCAP::initialize([%p]) [%p] for configuration '%s'",config,this,tmp.c_str());
305     }
306 #endif
307     if (config) {
308 	// read local point code and default remote point code
309 	m_SSN = config->getIntValue(YSTRING("local_SSN"),-1);
310 	m_defaultRemoteSSN = config->getIntValue(YSTRING("default_remote_SSN"),-1);
311 	m_defaultHopCounter = config->getIntValue(YSTRING("default_hopcounter"),0);
312 	if (m_defaultHopCounter > 15 || config->getBoolValue(YSTRING("default_hopcounter")))
313 	    m_defaultHopCounter = 15;
314 
315 	const char* code = config->getValue(YSTRING("default_remote_pointcode"));
316 	m_remoteTypePC = SS7PointCode::lookup(config->getValue(YSTRING("pointcodetype"),""));
317 	if (!(m_defaultRemotePC.assign(code,m_remoteTypePC) && m_defaultRemotePC.pack(m_remoteTypePC))) {
318 	    int codeInt = config->getIntValue(YSTRING("default_remote_pointcode"));
319 	    if (!m_defaultRemotePC.unpack(m_remoteTypePC,codeInt))
320 		Debug(this,DebugMild,"SS7TCAP::initialize([%p]) [%p] - Invalid default_remote_pointcode=%s value configured",
321 		    config,this,code);
322 	}
323 
324 	m_trTimeout = config->getIntValue(YSTRING("transact_timeout"),m_trTimeout / 1000) * 1000; // seconds to miliseconds
325 	s_printMsgs = config->getBoolValue(YSTRING("print-messages"),false);
326 	s_extendedDbg = config->getBoolValue(YSTRING("extended-debug"),false);
327     }
328     bool ok = SCCPUser::initialize(config);
329     if (ok) {
330 	NamedList p("");
331 	sendSCCPNotify(p);
332 	Debug(this,DebugInfo,"SSN=%d has status='%s'[%p]",m_SSN,lookup(m_ssnStatus,SCCPManagement::broadcastType(),""),this);
333     }
334     return ok;
335 }
336 
sendData(DataBlock & data,NamedList & params)337 bool SS7TCAP::sendData(DataBlock& data, NamedList& params)
338 {
339     if (params.getBoolValue(s_callingSSN))
340 	params.setParam(s_callingSSN,String(m_SSN));
341     if (params.getBoolValue(s_checkAddr,true)) {
342 	String dpc = params.getValue(s_remotePC,"");
343 	unsigned int pc = m_defaultRemotePC.pack(m_remoteTypePC);
344 	if (dpc.null() && pc)
345 	    params.addParam(s_remotePC,String(pc));
346 	int ssn = params.getIntValue(s_calledSSN,-1);
347 	if (ssn < 0 && m_defaultRemoteSSN <= 255)
348 	    params.setParam(s_calledSSN,String(m_defaultRemoteSSN));
349 	ssn = params.getIntValue(s_callingSSN,-1);
350 	if (ssn < 0 && m_SSN <= 255) {
351 	    params.setParam(s_callingSSN,String(m_SSN));
352 	    if (!params.getParam(s_callingRoute))
353 		params.addParam(s_callingRoute,"ssn");
354 	}
355 	if (m_defaultHopCounter && !params.getParam(s_HopCounter))
356 	    params.addParam(s_HopCounter,String(m_defaultHopCounter));
357     }
358 #ifdef DEBUG
359     if (s_printMsgs && debugAt(DebugInfo))
360 	dumpData(DebugInfo,this,"Sending to SCCP : ",this,params,data);
361 #endif
362     return SCCPUser::sendData(data,params);
363 }
364 
receivedData(DataBlock & data,NamedList & params)365 HandledMSU SS7TCAP::receivedData(DataBlock& data, NamedList& params)
366 {
367     HandledMSU result;
368     if (!data.length())
369 	return result;
370 #ifdef DEBUG
371     if (s_printMsgs && debugAt(DebugInfo))
372 	dumpData(DebugInfo,this,"Received from SCCP: ",this,params,data);
373 #endif
374     unsigned int cpaSSN = params.getIntValue(s_calledSSN,0);
375     unsigned int ssn = params.getIntValue("ssn",0);
376     if (m_SSN != cpaSSN && m_SSN != ssn)
377 	return result;
378     enqueue(new SS7TCAPMessage(params,data));
379     result = HandledMSU::Accepted;
380     return result;
381 }
382 
notifyData(DataBlock & data,NamedList & params)383 HandledMSU SS7TCAP::notifyData(DataBlock& data, NamedList& params)
384 {
385     HandledMSU result;
386 #ifdef DEBUG
387     if (s_printMsgs && debugAt(DebugInfo))
388 	dumpData(DebugInfo,this,"Received notify from SCCP: ",this,params,data);
389 #endif
390     enqueue(new SS7TCAPMessage(params,data,true));
391     return result;
392 }
393 
managementNotify(SCCP::Type type,NamedList & params)394 bool SS7TCAP::managementNotify(SCCP::Type type, NamedList& params)
395 {
396     Lock lock(m_usersMtx);
397     ListIterator iter(m_users);
398     bool ok = false;
399 
400     if (type == SCCP::SubsystemStatus && m_SSN != (unsigned int)params.getIntValue("ssn")) {
401 	params.setParam("subsystem-status","UserOutOfService");
402 	return true;
403     }
404     bool inService = false;
405     for (;;) {
406 	TCAPUser* user = static_cast<TCAPUser*>(iter.get());
407 	// End of iteration?
408 	if (!user)
409 	    break;
410 	if (user->managementNotify(type,params))
411 	    ok = true;
412 	if (user->managementState() == (int) SCCPManagement::UserInService)
413 	    inService = true;
414     }
415     if (type == SCCP::SubsystemStatus)
416 	params.setParam("subsystem-status",(inService ? "UserInService" : "UserOutOfService"));
417     return ok;
418 }
419 
updateUserStatus(TCAPUser * user,SCCPManagement::LocalBroadcast status,NamedList & params)420 void SS7TCAP::updateUserStatus(TCAPUser* user, SCCPManagement::LocalBroadcast status, NamedList& params)
421 {
422     if (!user)
423 	return;
424     DDebug(this,DebugAll,"SS7TCAP::updateUserStatus(user=%s[%p],status=%d) [%p]",user->toString().c_str(),user,status,this);
425     bool notify = false;
426     Lock l(m_usersMtx);
427     SCCPManagement::LocalBroadcast tmp = m_ssnStatus;
428     switch (m_ssnStatus) {
429 	case SCCPManagement::UserOutOfService:
430 	    if (status == SCCPManagement::UserInService) {
431 		m_ssnStatus = SCCPManagement::UserInService;
432 		notify = true;
433 	    }
434 	    break;
435 	case SCCPManagement::UserInService:
436 	    if (status == SCCPManagement::UserOutOfService) {
437 		ListIterator it(m_users);
438 		for (;;) {
439 		    TCAPUser* usr = static_cast<TCAPUser*>(it.get());
440 		    // End of iteration?
441 		    if (!usr) {
442 			m_ssnStatus = SCCPManagement::UserOutOfService;
443 			notify = true;
444 			break;
445 		    }
446 		    if (usr->managementState() == (int) SCCPManagement::UserInService)
447 			break;
448 		}
449 	    }
450 	default:
451 	    break;
452     }
453 
454     if (notify) {
455 	sendSCCPNotify(params); // it always returns false, so no point in checking result
456 	Debug(this,DebugInfo,"SSN=%d changed status from '%s' to '%s' [%p]",m_SSN,
457 		  lookup(tmp,SCCPManagement::broadcastType(),""),lookup(m_ssnStatus,SCCPManagement::broadcastType(),""),this);
458     }
459 }
460 
sendSCCPNotify(NamedList & params)461 bool SS7TCAP::sendSCCPNotify(NamedList& params)
462 {
463     params.setParam(YSTRING("subsystem-status"),lookup(m_ssnStatus,SCCPManagement::broadcastType(),""));
464     params.setParam(YSTRING("ssn"),String(m_SSN));
465     if (!params.getParam(YSTRING("smi")))
466 	    params.setParam("smi","0");
467     return sccpNotify(SCCP::StatusRequest,params);
468 }
469 
attach(TCAPUser * user)470 void SS7TCAP::attach(TCAPUser* user)
471 {
472     if (!user)
473 	return;
474     DDebug(this,DebugAll,"SS7TCAP::attach(user=%s [%p]) [%p]",user->toString().safe(),user,this);
475     Lock l(m_usersMtx);
476     if (m_users.find(user))
477 	return;
478     m_users.append(user);
479     Debug(this,DebugAll,"SS7TCAP '%s'[%p] attached user=%s [%p]",toString().safe(),this,user->toString().safe(),user);
480 }
481 
detach(TCAPUser * user)482 void SS7TCAP::detach(TCAPUser* user)
483 {
484     if (!user)
485 	return;
486     DDebug(this,DebugAll,"SS7TCAP::detach(user=%s [%p]) [%p], refCount=%d",user->toString().safe(),user,this,refcount());
487     Lock l(m_usersMtx);
488     if (m_users.find(user)) {
489 	m_users.remove(user,false);
490 	Debug(this,DebugAll,"SS7TCAP '%s'[%p] detached user=%s [%p], refCount=%d",toString().safe(),this,user->toString().c_str(),user,refcount());
491     }
492 }
493 
enqueue(SS7TCAPMessage * msg)494 void SS7TCAP::enqueue(SS7TCAPMessage* msg)
495 {
496     if (!msg)
497 	return;
498     Lock lock(m_inQueueMtx);
499     m_inQueue.append(msg);
500     XDebug(this,DebugAll,"SS7TCAP::enqueue(). Enqueued transaction wrapper (%p) [%p]",msg,this);
501 }
502 
dequeue()503 SS7TCAPMessage* SS7TCAP::dequeue()
504 {
505     Lock lock(m_inQueueMtx,SignallingEngine::maxLockWait());
506     if (!lock.locked())
507 	return 0;
508     ObjList* obj = m_inQueue.skipNull();
509     if (!obj)
510 	return 0;
511     SS7TCAPMessage* msg = static_cast<SS7TCAPMessage*>(obj->get());
512     m_inQueue.remove(msg,false);
513     XDebug(this,DebugAll,"SS7TCAP::dequeue(). Dequeued transaction wrapper (%p) [%p]",msg,this);
514     return msg;
515 }
516 
allocTransactionID(String & str)517 void SS7TCAP::allocTransactionID(String& str)
518 {
519     m_transactionsMtx.lock();
520     u_int32_t tmp = m_idsPool;
521     m_idsPool++;
522     m_transactionsMtx.unlock();
523     unsigned char buff[sizeof(tmp)];
524     int len = sizeof(tmp);
525     for (int index = len - 1; index >= 0; index--) {
526 	buff[index] = tmp & 0xff;
527 	tmp >>= 8;
528     }
529     str.hexify(buff,len,' ');
530     XDebug(this,DebugAll,"SS7TCAP::allocTransactionID() - allocated new transaction ID=%s [%p]",str.c_str(),this);
531 }
532 
allocTransactionID()533 const String SS7TCAP::allocTransactionID()
534 {
535     String str;
536     allocTransactionID(str);
537     return str;
538 }
539 
sendToUser(NamedList & params)540 bool SS7TCAP::sendToUser(NamedList& params)
541 {
542     String userName = params.getValue(s_tcapUser,""); // if it has a specified user, send it to that user
543     Lock lock(m_usersMtx);
544     if (!userName.null()) {
545 	ObjList* obj = m_users.find(userName);
546 	if (!obj) {
547 	    Debug(this,DebugInfo,"SS7TCAP::sendToUser() [%p] - failed to send message with id=%s to user=%s,"
548 		" no such application",this,params.getValue(s_tcapLocalTID),userName.c_str());
549 	    return false;
550 	}
551 	TCAPUser* user = static_cast<TCAPUser*>(obj->get());
552 	if (!user) {
553 	    Debug(this,DebugInfo,"SS7TCAP::sendToUser() [%p] - failed to send message with id=%s to user,%s"
554 		" no such application",this,params.getValue(s_tcapLocalTID),userName.c_str());
555 	    return false;
556 	}
557 #ifdef DEBUG
558 	if (s_printMsgs && debugAt(DebugInfo))
559 	    dumpData(DebugInfo,this,"Sent to TCAP user: ",this,params);
560 #endif
561 	return user->tcapIndication(params);
562     }
563     else {
564 	ListIterator iter(m_users);
565 	for (;;) {
566 	    TCAPUser* user = static_cast<TCAPUser*>(iter.get());
567 	    // End of iteration?
568 	    if (!user) {
569 		Debug(this,DebugInfo,"SS7TCAP::sendToUser() [%p] - failed to send message with id=%s to any user",
570 			this,params.getValue(s_tcapLocalTID));
571 		return false;
572 	    }
573 	    if (user->tcapIndication(params)) {
574 		params.setParam(s_tcapUser,user->toString()); // set the user for this transaction
575 #ifdef DEBUG
576 		if (s_printMsgs && debugAt(DebugInfo))
577 		    dumpData(DebugInfo,this,"Sent to TCAP user: ",this,params);
578 #endif
579 		break;
580 	    }
581 	}
582     }
583     return true;
584 }
585 
status(NamedList & status)586 void SS7TCAP::status(NamedList& status)
587 {
588     status.setParam("totalIncoming",String(m_recvMsgs));
589     status.setParam("totalOutgoing",String(m_sentMsgs));
590     status.setParam("totalDiscarded",String(m_discardMsgs));
591     status.setParam("totalNormal",String(m_normalMsgs));
592     status.setParam("totalAbnormal",String(m_abnormalMsgs));
593 }
594 
userStatus(NamedList & status)595 void SS7TCAP::userStatus(NamedList& status)
596 {
597     Debug(this,DebugStub,"Please implement SS7TCAP::userStatus()");
598 }
599 
getTransaction(const String & tid)600 SS7TCAPTransaction* SS7TCAP::getTransaction(const String& tid)
601 {
602     SS7TCAPTransaction* tr = 0;
603     Lock lock(m_transactionsMtx);
604     ObjList* o = m_transactions.find(tid);
605     if (o)
606 	tr = static_cast<SS7TCAPTransaction*>(o->get());
607     if (tr && tr->ref())
608 	return tr;
609     return 0;
610 }
611 
removeTransaction(SS7TCAPTransaction * tr)612 void SS7TCAP::removeTransaction(SS7TCAPTransaction* tr)
613 {
614     Lock lock(m_transactionsMtx);
615     m_transactions.remove(tr);
616 }
617 
timerTick(const Time & when)618 void SS7TCAP::timerTick(const Time& when)
619 {
620     // first check pending received messages
621     SS7TCAPMessage* msg = dequeue();
622 
623     while (msg) {
624 	processSCCPData(msg);
625 	TelEngine::destruct(msg);
626 	//break;
627 	msg = dequeue();
628     }
629 
630     // update/handle rest of transactions
631     Lock lock(m_transactionsMtx);
632     ListIterator iter(m_transactions);
633     for (;;) {
634 	SS7TCAPTransaction* tr = static_cast<SS7TCAPTransaction*>(iter.get());
635 	// End of iteration?
636 	if (!tr)
637 	    break;
638 	if (!tr->ref())
639 	    continue;
640 	lock.drop();
641 	NamedList params("");
642 	DataBlock data;
643 	if (tr->transactionState() != SS7TCAPTransaction::Idle)
644 	    tr->checkComponents();
645 	if (tr->endNow())
646 	    tr->setState(SS7TCAPTransaction::Idle);
647 	if (tr->timedOut()) {
648 	    DDebug(this,DebugInfo,"SS7TCAP::timerTick() - transaction with id=%s(%p) timed out [%p]",tr->toString().c_str(),tr,this);
649 	    tr->updateToEnd();
650 	    buildSCCPData(params,tr);
651 	    if (!tr->basicEnd())
652 		tr->transactionData(params);
653 	    sendToUser(params);
654 	    tr->setState(SS7TCAPTransaction::Idle);
655 	}
656 
657 	if (tr->transactionState() == SS7TCAPTransaction::Idle)
658 	    removeTransaction(tr);
659 	TelEngine::destruct(tr);
660 	if (!lock.acquire(m_transactionsMtx))
661 	    break;
662     }
663 }
664 
processSCCPData(SS7TCAPMessage * msg)665 HandledMSU SS7TCAP::processSCCPData(SS7TCAPMessage* msg)
666 {
667     HandledMSU result;
668     if (!msg)
669 	return result;
670     XDebug(this,DebugAll,"SS7TCAP::processSCCPData(msg=[%p]) [%p]",msg,this);
671 
672     NamedList& msgParams = msg->msgParams();
673     DataBlock& msgData = msg->msgData();
674 
675     SS7TCAPError transactError = decodeTransactionPart(msgParams,msgData);
676     if (transactError.error() != SS7TCAPError::NoError)
677 	return handleError(transactError,msgParams,msgData);
678 
679     NamedString* trID = msgParams.getParam(s_tcapLocalTID);
680     String trType = msgParams.getValue(s_tcapRequest);
681     SS7TCAP::TCAPUserTransActions type = (SS7TCAP::TCAPUserTransActions)trType.toInteger(SS7TCAP::s_transPrimitives);
682 
683      // check if it's a notice from SCCP, switch the ids if so
684     if (msg->isNotice()) {
685 	trID = msgParams.getParam(s_tcapRemoteTID);
686 	msgParams.setParam(s_tcapRemoteTID,msgParams.getValue(s_tcapLocalTID));
687 	msgParams.setParam(s_tcapLocalTID,(TelEngine::null(trID) ? "" : *trID));
688 	type = TC_Notice;
689 	msgParams.setParam(s_tcapRequest,lookup(type,SS7TCAP::s_transPrimitives,"Notice"));
690      }
691     else
692 	incCounter(SS7TCAP::IncomingMsgs);
693 
694     SS7TCAPTransaction* tr = 0;
695     switch (type) {
696 	case SS7TCAP::TC_Unidirectional:
697 	case SS7TCAP::TC_Begin:
698 	case SS7TCAP::TC_QueryWithPerm:
699 	case SS7TCAP::TC_QueryWithoutPerm:
700 	    // if there isn't a destination ID, allocate a new one and build a transaction
701 	    if (TelEngine::null(trID)) {
702 		String newID;
703 		allocTransactionID(newID);
704 		tr = buildTransaction(type,newID,msgParams,false);
705 		tr->ref();
706 		m_transactionsMtx.lock();
707 		m_transactions.append(tr);
708 		m_transactionsMtx.unlock();
709 		msgParams.setParam(s_tcapLocalTID,newID);
710 	    }
711 	    break;
712 	case SS7TCAP::TC_Continue:
713 	case SS7TCAP::TC_ConversationWithPerm:
714 	case SS7TCAP::TC_ConversationWithoutPerm:
715 	case SS7TCAP::TC_End:
716 	case SS7TCAP::TC_Response:
717 	case SS7TCAP::TC_P_Abort:
718 	case SS7TCAP::TC_U_Abort:
719 	case SS7TCAP::TC_Notice:
720 	    if (TelEngine::null(trID)) {
721 		transactError.setError(SS7TCAPError::Transact_UnassignedTransactionID);
722 		return handleError(transactError,msgParams,msgData);
723 	    }
724 	    tr = getTransaction(*trID);
725 	    if (!tr) {
726 		transactError.setError(SS7TCAPError::Transact_UnassignedTransactionID);
727 		return handleError(transactError,msgParams,msgData);
728 	    }
729 	    transactError = tr->update((SS7TCAP::TCAPUserTransActions)type,msgParams,false);
730 	    if (transactError.error() != SS7TCAPError::NoError) {
731 		result = handleError(transactError,msgParams,msgData,tr);
732 		TelEngine::destruct(tr);
733 		return result;
734 	    }
735 	    break;
736 	default:
737 	    incCounter(SS7TCAP::DiscardedMsgs);
738 	    return result;
739     }
740     if (tr) {
741 	transactError = tr->handleData(msgParams,msgData);
742 	if (transactError.error() != SS7TCAPError::NoError) {
743 	    result = handleError(transactError,msgParams,msgData,tr);
744 	    TelEngine::destruct(tr);
745 	    return result;
746 	}
747 
748 	tr->addSCCPAddressing(msgParams,true);
749 	tr->updateState(false);
750 	if (sendToUser(msgParams)) {
751 	    tr->setUserName(msgParams.getValue(s_tcapUser));
752 	    tr->endNow(msgParams.getBoolValue(s_tcapEndNow,false));
753 
754 	    if (tr->transactionType() == SS7TCAP::TC_Unidirectional
755 		|| tr->transactionType() == SS7TCAP::TC_U_Abort
756 		|| tr->transactionType() == SS7TCAP::TC_P_Abort
757 		|| tr->transactionType() == SS7TCAP::TC_End
758 		|| tr->transactionType() == SS7TCAP::TC_Response)
759 		tr->setState(SS7TCAPTransaction::Idle);
760 	    else
761 		tr->setTransmitState(SS7TCAPTransaction::Transmitted);
762 	}
763 	else if (type != SS7TCAP::TC_Notice) {
764 	    tr->update(SS7TCAP::TC_U_Abort,msgParams,false);
765 	    buildSCCPData(msgParams,tr);
766 	    tr->setTransmitState(SS7TCAPTransaction::Transmitted);
767 	    tr->updateState(false);
768 	}
769 	else
770 	    tr->setState(SS7TCAPTransaction::Idle);
771 	TelEngine::destruct(tr);
772     }
773     result = HandledMSU::Accepted;
774     incCounter(SS7TCAP::NormalMsgs);
775     return result;
776 }
777 
userRequest(NamedList & params)778 SS7TCAPError SS7TCAP::userRequest(NamedList& params)
779 {
780 #ifdef DEBUG
781     if (s_printMsgs && debugAt(DebugInfo))
782 	dumpData(DebugInfo,this,"SS7TCAP::userRequest() - received request ",this,params);
783 #endif
784 
785     NamedString* req = params.getParam(s_tcapRequest);
786 
787     NamedString* otid = params.getParam(s_tcapLocalTID);
788     NamedString* user = params.getParam(s_tcapUser);
789     SS7TCAPError error(m_tcapType);
790     if (TelEngine::null(req)) {
791 	Debug(this,DebugInfo,"SS7TCAP::userRequest()[%p] - received a transaction request from user=%s with originating ID=%s"
792 	    " without request type, rejecting it",this,(user ? user->c_str() : ""),(otid ? otid->c_str() : ""));
793 	params.setParam(s_tcapRequestError,"missing_primitive");
794 	error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
795 	return error;
796     }
797 
798     SS7TCAPTransaction* tr = 0;
799     if (!TelEngine::null(req)) {
800 	int type = req->toInteger(SS7TCAP::s_transPrimitives);
801 	switch (type) {
802 	    case SS7TCAP::TC_Unidirectional:
803 	    case SS7TCAP::TC_Begin:
804 	    case SS7TCAP::TC_QueryWithPerm:
805 	    case SS7TCAP::TC_QueryWithoutPerm:
806 		// if otid not set, alloc one and set it
807 		if (TelEngine::null(otid)) {
808 		    params.setParam(s_tcapLocalTID,allocTransactionID());
809 		    otid = params.getParam(s_tcapLocalTID);
810 		}
811 		else {
812 		    // if set, check if we already have it
813 		    tr = getTransaction(*otid);
814 		    if (tr) {
815 			Debug(this,DebugInfo,"SS7TCAP::userRequest()[%p] - received a new transaction request from user=%s with originating ID=%s which is the ID "
816 				"of an already existing transaction, rejecting the request",this,(user ? user->c_str() : ""),otid->c_str());
817 			params.setParam(s_tcapRequestError,"allocated_id");
818 			error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
819 			TelEngine::destruct(tr);
820 			return error;
821 		    }
822 		}
823 		// create transaction
824 		tr = buildTransaction((SS7TCAP::TCAPUserTransActions)type,otid,params,true);
825 		if (!TelEngine::null(user))
826 		    tr->setUserName(user);
827 		tr->ref();
828 		m_transactionsMtx.lock();
829 		m_transactions.append(tr);
830 		m_transactionsMtx.unlock();
831 		break;
832 	    case SS7TCAP::TC_Continue:
833 	    case SS7TCAP::TC_ConversationWithPerm:
834 	    case SS7TCAP::TC_ConversationWithoutPerm:
835 	    case SS7TCAP::TC_End:
836 	    case SS7TCAP::TC_Response:
837 	    case SS7TCAP::TC_U_Abort:
838 		// find transaction and update
839 		if (!TelEngine::null(otid)) {
840 		    tr = getTransaction(*otid);
841 		    if (!tr) {
842 			params.setParam(s_tcapRequestError,"unknown_transaction");
843 			error.setError(SS7TCAPError::Transact_UnassignedTransactionID);
844 			return error;
845 		    }
846 		    error = tr->update((SS7TCAP::TCAPUserTransActions)type,params);
847 		    if (error.error() != SS7TCAPError::NoError) {
848 			TelEngine::destruct(tr);
849 			return error;
850 		    }
851 		}
852 		else {
853 		    params.setParam(s_tcapRequestError,"need_transaction_id");
854 		    error.setError(SS7TCAPError::Transact_UnassignedTransactionID);
855 		    return error;
856 		}
857 		break;
858 	    case SS7TCAP::TC_Unknown:
859 		if (!TelEngine::null(otid))
860 		    tr = getTransaction(*otid);
861 		break;
862 	    case SS7TCAP::TC_P_Abort:
863 	    case SS7TCAP::TC_Notice:
864 	    default:
865 		Debug(this,DebugAll,"SS7TCAP::userRequest() - received user request with unsuited primitive='%s' [%p]",req->c_str(),this);
866 		params.setParam(s_tcapRequestError,"wrong_primitive");
867 		error.setError(SS7TCAPError::Transact_UnrecognizedPackageType);
868 		return error;
869 	}
870     }
871     if (tr) {
872 	error = tr->handleDialogPortion(params,true);
873 	if (error.error() != SS7TCAPError::NoError) {
874 	    TelEngine::destruct(tr);
875 	    return error;
876 	}
877 	error = tr->handleComponents(params,true);
878 	if (error.error() != SS7TCAPError::NoError) {
879 	    TelEngine::destruct(tr);
880 	    return error;
881 	}
882 	if (tr->transmitState() == SS7TCAPTransaction::PendingTransmit) {
883 	    tr->updateState(true);
884 	    buildSCCPData(params,tr);
885 	    tr->setTransmitState(SS7TCAPTransaction::Transmitted);
886 	}
887 	else if (tr->transmitState() == SS7TCAPTransaction::NoTransmit)
888 	    removeTransaction(tr);
889 	TelEngine::destruct(tr);
890     }
891     return error;
892 }
893 
buildSCCPData(NamedList & params,SS7TCAPTransaction * tr)894 void SS7TCAP::buildSCCPData(NamedList& params, SS7TCAPTransaction* tr)
895 {
896     if (!tr)
897 	return;
898     DDebug(this,DebugAll,"SS7TCAP::buildSCCPData(tr=%p) for local transaction ID=%s [%p]",tr,tr->toString().c_str(),this);
899 
900     Lock l(tr);
901     bool sendOk = true;
902     int type = tr->transactionType();
903     if (type == SS7TCAP::TC_End
904 	  || type == TC_Response) {
905 	if (!tr->basicEnd()) {
906 	    sendOk = false; // prearranged end, don't send to remote Transaction End message
907 	    Debug(this,DebugAll,"SS7TCAP::buildSCCPData(tr=%p) [%p] - transaction with id=%s has set prearranged end, won't be"
908 		" sending anything to SCCP",tr,this,tr->toString().c_str());
909 	}
910     }
911 
912     if (sendOk) {
913 	DataBlock data;
914 	tr->requestContent(params,data);
915 	tr->addSCCPAddressing(params,false);
916 	encodeTransactionPart(params,data);
917 
918 	if (!sendData(data,params)) {
919 	    params.setParam("ReturnCause","Network failure");
920 	    enqueue(new SS7TCAPMessage(params,data,true));
921 	    Debug(this,DebugInfo,"SS7TCAP::buildSCCPData(tr=%p) [%p] - message for transaction with id=%s failed to be sent",
922 		tr,this,tr->toString().c_str());
923 	    return;
924 	};
925 	incCounter(SS7TCAP::OutgoingMsgs);
926     }
927 }
928 
handleError(SS7TCAPError & error,NamedList & params,DataBlock & data,SS7TCAPTransaction * tr)929 HandledMSU SS7TCAP::handleError(SS7TCAPError& error, NamedList& params, DataBlock& data, SS7TCAPTransaction* tr)
930 {
931     Debug(this,DebugInfo,"SS7TCAP::handleError(error=%s) for transaction with id=%s(%p) [%p]",error.errorName().c_str(),
932 	(tr ? tr->toString().c_str() : "unknown"),tr,this);
933     HandledMSU result = HandledMSU::Accepted;
934 
935     int type = lookup(params.getValue(s_tcapRequest,""),SS7TCAP::s_transPrimitives);
936     NamedString* rtid = params.getParam(s_tcapRemoteTID);
937     NamedString* ltid = params.getParam(s_tcapLocalTID);
938     bool buildRemAbort = false;
939     bool buildLocAbort = false;
940     switch (type) {
941 	case SS7TCAP::TC_Unidirectional:
942 	    incCounter(SS7TCAP::DiscardedMsgs);
943 	    return result; // return with rejected, meaning Discarded
944 	case SS7TCAP::TC_Begin:
945 	case SS7TCAP::TC_QueryWithPerm:
946 	case SS7TCAP::TC_QueryWithoutPerm:
947 	    if (!TelEngine::null(rtid))
948 		buildRemAbort = true;
949 	    else {
950 		// no originating ID, we don't know to whom to send the Abort, meaning we'll discard the message
951 		incCounter(SS7TCAP::DiscardedMsgs);
952 		return result;
953 	    }
954 	    break;
955 	case SS7TCAP::TC_Continue:
956 	case SS7TCAP::TC_ConversationWithPerm:
957 	case SS7TCAP::TC_ConversationWithoutPerm:
958 	    if (TelEngine::null(rtid) && TelEngine::null(ltid)) {
959 		incCounter(SS7TCAP::DiscardedMsgs);
960 		return result;
961 	    }
962 	    if (!TelEngine::null(rtid)) {
963 		buildRemAbort = true;
964 		if (!TelEngine::null(ltid))
965 		    buildLocAbort = true;
966 	    }
967 	    break;
968 	case SS7TCAP::TC_End:
969 	case SS7TCAP::TC_Response:
970 	case SS7TCAP::TC_P_Abort:
971 	case SS7TCAP::TC_U_Abort:
972 	    if (TelEngine::null(ltid)) {
973 		incCounter(SS7TCAP::DiscardedMsgs);
974 		return result;
975 	    }
976 	    else
977 		buildLocAbort = true;
978 	    break;
979 	default:
980 	    if (!TelEngine::null(rtid)) {
981 		buildRemAbort = true;
982 		if (!TelEngine::null(ltid))
983 		    buildLocAbort = true;
984 	    }
985 	    else {
986 		incCounter(SS7TCAP::DiscardedMsgs);
987 		return result;
988 	    }
989 	    break;
990     }
991 
992     if (buildLocAbort && !TelEngine::null(ltid)) { // notify user of the abort
993 	params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_P_Abort,SS7TCAP:: s_transPrimitives));
994 	params.setParam(s_tcapAbortCause,"pAbort");
995 	params.setParam(s_tcapAbortInfo,String(error.error()));
996 	if (tr) {
997 	    tr->update(SS7TCAP::TC_P_Abort,params,false);
998 	    tr->updateState();
999 	}
1000 	sendToUser(params);
1001     }
1002     if (buildRemAbort) {
1003 	// clean dataBlock
1004 	data.clear();
1005 
1006 	if (!TelEngine::null(rtid)) { // we have the remote ID, notify of abort
1007 	    NamedList addr("");
1008 	    populateSCCPAddress(addr,addr,params,false,true);
1009 	    params.copyParams(addr);
1010 
1011 	    if (error.error() != SS7TCAPError::Dialog_Abnormal) {
1012 		params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_P_Abort,SS7TCAP::s_transPrimitives));
1013 		params.setParam(s_tcapAbortCause,"pAbort");
1014 		params.setParam(s_tcapAbortInfo,String(error.error()));
1015 	    }
1016 	    else if (tr)
1017 		tr->abnormalDialogInfo(params);
1018 
1019 	    if (tcapType() == ANSITCAP)
1020 		SS7TCAPTransactionANSI::encodePAbort(tr,params,data);
1021 	    else if (tcapType() == ITUTCAP)
1022 		SS7TCAPTransactionITU::encodePAbort(tr,params,data);
1023 
1024 	    encodeTransactionPart(params,data);
1025 	    sendData(data,params);
1026 	}
1027     }
1028     if (buildRemAbort || buildLocAbort) {
1029 	incCounter(SS7TCAP::AbnormalMsgs);
1030 	result = HandledMSU::Accepted;
1031     }
1032     return result;
1033 }
1034 
1035 /**
1036  * SS7TCAPError implementation
1037  */
1038 struct TCAPError {
1039     SS7TCAPError::ErrorType errorType;
1040     u_int16_t errorCode;
1041 };
1042 
1043 static const TCAPError s_ansiErrorDefs[] = {
1044     // error                                                    fullcode
1045     { SS7TCAPError::Transact_UnrecognizedPackageType,             0x01},
1046     { SS7TCAPError::Transact_IncorrectTransactionPortion,         0x02},
1047     { SS7TCAPError::Transact_BadlyStructuredTransaction,          0x03},
1048     { SS7TCAPError::Transact_UnassignedTransactionID,             0x04},
1049     { SS7TCAPError::Transact_PermissionToReleaseProblem,          0x05},
1050     { SS7TCAPError::Transact_ResourceUnavailable,                 0x06},
1051 
1052     { SS7TCAPError::Dialog_UnrecognizedDialoguePortionID,         0x07},
1053     { SS7TCAPError::Dialog_BadlyStructuredDialoguePortion,        0x08},
1054     { SS7TCAPError::Dialog_MissingDialoguePortion,                0x09},
1055     { SS7TCAPError::Dialog_InconsistentDialoguePortion,           0x0a},
1056 
1057     // GeneralProblem
1058     { SS7TCAPError::General_UnrecognizedComponentType,            0x101},
1059     { SS7TCAPError::General_IncorrectComponentPortion,            0x102},
1060     { SS7TCAPError::General_BadlyStructuredCompPortion,           0x103},
1061     { SS7TCAPError::General_IncorrectComponentCoding,             0x104},
1062 
1063     // InvokeProblem
1064     { SS7TCAPError::Invoke_DuplicateInvokeID,                     0x201},
1065     { SS7TCAPError::Invoke_UnrecognizedOperationCode,             0x202},
1066     { SS7TCAPError::Invoke_IncorrectParameter,                    0x203},
1067     { SS7TCAPError::Invoke_UnrecognizedCorrelationID,             0x204},
1068 
1069     // ReturnResult
1070     { SS7TCAPError::Result_UnrecognisedCorrelationID,             0x301},
1071     { SS7TCAPError::Result_UnexpectedReturnResult,                0x302},
1072     { SS7TCAPError::Result_IncorrectParameter,                    0x303},
1073 
1074     // ReturnError
1075     { SS7TCAPError::Error_UnrecognisedCorrelationID,              0x401},
1076     { SS7TCAPError::Error_UnexpectedReturnError,                  0x402},
1077     { SS7TCAPError::Error_UnrecognisedError,                      0x403},
1078     { SS7TCAPError::Error_UnexpectedError,                        0x404},
1079     { SS7TCAPError::Error_IncorrectParameter,                     0x405},
1080 
1081     { SS7TCAPError::NoError,                                      0xfff},
1082 };
1083 
1084 static const TCAPError s_ituErrorDefs[] = {
1085     // error                                                    fullcode
1086     { SS7TCAPError::Transact_UnrecognizedPackageType,             0x00},
1087     { SS7TCAPError::Transact_UnassignedTransactionID,             0x01},
1088     { SS7TCAPError::Transact_BadlyStructuredTransaction,          0x02},
1089     { SS7TCAPError::Transact_IncorrectTransactionPortion,         0x03},
1090     { SS7TCAPError::Transact_ResourceUnavailable,                 0x04},
1091 
1092     { SS7TCAPError::Dialog_Abnormal,                              0x7000},
1093 
1094     // GeneralProblem
1095     { SS7TCAPError::General_UnrecognizedComponentType,            0x8000},
1096     { SS7TCAPError::General_IncorrectComponentPortion,            0x8001},
1097     { SS7TCAPError::General_BadlyStructuredCompPortion,           0x8002},
1098 
1099     // InvokeProblem
1100     { SS7TCAPError::Invoke_DuplicateInvokeID,                     0x8100},
1101     { SS7TCAPError::Invoke_UnrecognizedOperationCode,             0x8101},
1102     { SS7TCAPError::Invoke_IncorrectParameter,                    0x8102},
1103     { SS7TCAPError::Invoke_UnrecognizedCorrelationID,             0x8105},
1104     { SS7TCAPError::Invoke_ResourceLimitation,                    0x8103},
1105     { SS7TCAPError::Invoke_InitiatingRelease,                     0x8104},
1106     { SS7TCAPError::Invoke_LinkedResponseUnexpected,              0x8106},
1107     { SS7TCAPError::Invoke_UnexpectedLinkedOperation,             0x8107},
1108 
1109     // ReturnResult
1110     { SS7TCAPError::Result_UnrecognizedInvokeID,                  0x8200},
1111     { SS7TCAPError::Result_UnexpectedReturnResult,                0x8201},
1112     { SS7TCAPError::Result_IncorrectParameter,                    0x8202},
1113 
1114     // ReturnError
1115     { SS7TCAPError::Error_UnrecognizedInvokeID,                   0x8300},
1116     { SS7TCAPError::Error_UnexpectedReturnError,                  0x8301},
1117     { SS7TCAPError::Error_UnrecognisedError,                      0x8302},
1118     { SS7TCAPError::Error_UnexpectedError,                        0x8303},
1119     { SS7TCAPError::Error_IncorrectParameter,                     0x8304},
1120 
1121     { SS7TCAPError::NoError,                                      0xffff},
1122 };
1123 
1124 const TokenDict SS7TCAPError::s_errorTypes[] = {
1125     {"Transact-UnrecognizedPackageType",        SS7TCAPError::Transact_UnrecognizedPackageType},
1126     {"Transact-IncorrectTransactionPortion",    SS7TCAPError::Transact_IncorrectTransactionPortion},
1127     {"Transact-BadlyStructuredTransaction",     SS7TCAPError::Transact_BadlyStructuredTransaction},
1128     {"Transact-UnassignedTransactionID",        SS7TCAPError::Transact_UnassignedTransactionID },
1129     {"Transact-PermissionToReleaseProblem",     SS7TCAPError::Transact_PermissionToReleaseProblem},
1130     {"Transact-ResourceUnavailable",            SS7TCAPError::Transact_ResourceUnavailable},
1131 
1132     {"Dialog-UnrecognizedDialoguePortionID",    SS7TCAPError::Dialog_UnrecognizedDialoguePortionID},
1133     {"Dialog-BadlyStructuredDialoguePortion",   SS7TCAPError::Dialog_BadlyStructuredDialoguePortion},
1134     {"Dialog-MissingDialoguePortion",           SS7TCAPError::Dialog_MissingDialoguePortion},
1135     {"Dialog-InconsistentDialoguePortion",      SS7TCAPError::Dialog_InconsistentDialoguePortion},
1136     {"Dialog-Abnormal",                         SS7TCAPError::Dialog_Abnormal},
1137 
1138     {"General-UnrecognizedComponentType",       SS7TCAPError::General_UnrecognizedComponentType},
1139     {"General-IncorrectComponentPortion",       SS7TCAPError::General_IncorrectComponentPortion},
1140     {"General-BadlyStructuredCompPortion",      SS7TCAPError::General_BadlyStructuredCompPortion},
1141     {"General-IncorrectComponentCoding",        SS7TCAPError::General_IncorrectComponentCoding},
1142 
1143     {"Invoke-DuplicateInvokeID",                SS7TCAPError::Invoke_DuplicateInvokeID},
1144     {"Invoke-UnrecognizedOperationCode",        SS7TCAPError::Invoke_UnrecognizedOperationCode},
1145     {"Invoke-IncorrectParameter",               SS7TCAPError::Invoke_IncorrectParameter},
1146     {"Invoke-UnrecognizedCorrelationID",        SS7TCAPError::Invoke_UnrecognizedCorrelationID},
1147     {"Invoke-ResourceLimitation",               SS7TCAPError::Invoke_ResourceLimitation},
1148     {"Invoke-InitiatingRelease",                SS7TCAPError::Invoke_InitiatingRelease},
1149     {"Invoke-LinkedResponseUnexpected",         SS7TCAPError::Invoke_LinkedResponseUnexpected},
1150     {"Invoke-UnexpectedLinkedOperation",        SS7TCAPError::Invoke_UnexpectedLinkedOperation},
1151 
1152     {"Result-UnrecognizedInvokeID",             SS7TCAPError::Result_UnrecognizedInvokeID},
1153     {"Result-UnrecognisedCorrelationID",        SS7TCAPError::Result_UnrecognisedCorrelationID},
1154     {"Result-UnexpectedReturnResult",           SS7TCAPError::Result_UnexpectedReturnResult},
1155     {"Result-IncorrectParameter",               SS7TCAPError::Result_IncorrectParameter},
1156 
1157     {"Error-UnrecognizedInvokeID",              SS7TCAPError::Error_UnrecognizedInvokeID},
1158     {"Error-UnrecognisedCorrelationID",         SS7TCAPError::Error_UnrecognisedCorrelationID},
1159     {"Error-UnexpectedReturnError",             SS7TCAPError::Error_UnexpectedReturnError},
1160     {"Error-UnrecognisedError",                 SS7TCAPError::Error_UnrecognisedError},
1161     {"Error-UnexpectedError",                   SS7TCAPError::Error_UnexpectedError},
1162     {"Error-IncorrectParameter",                SS7TCAPError::Error_IncorrectParameter},
1163 
1164     {"NoError",                                 SS7TCAPError::NoError},
1165     {0,0},
1166 };
1167 
SS7TCAPError(SS7TCAP::TCAPType tcapType)1168 SS7TCAPError::SS7TCAPError(SS7TCAP::TCAPType tcapType)
1169     : m_tcapType(tcapType), m_error(SS7TCAPError::NoError)
1170 {
1171 }
1172 
SS7TCAPError(SS7TCAP::TCAPType tcapType,ErrorType error)1173 SS7TCAPError::SS7TCAPError(SS7TCAP::TCAPType tcapType, ErrorType error)
1174     : m_tcapType(tcapType), m_error(error)
1175 {
1176     XDebug(DebugAll,"SS7TCAPError created TCAP=%s with error=%s [%p]",lookup(tcapType,SS7TCAP::s_tcapVersion),
1177 	lookup(error,s_errorTypes),this);
1178 }
1179 
~SS7TCAPError()1180 SS7TCAPError::~SS7TCAPError()
1181 {
1182 }
1183 
errorName()1184 const String SS7TCAPError::errorName()
1185 {
1186     return lookup(m_error,s_errorTypes,"NoError");
1187 }
1188 
errorCode()1189 u_int16_t SS7TCAPError::errorCode()
1190 {
1191     const TCAPError* errDef = (m_tcapType == SS7TCAP::ANSITCAP ? s_ansiErrorDefs : s_ituErrorDefs);
1192     for (;errDef && errDef->errorType != SS7TCAPError::NoError; errDef++) {
1193 	if (errDef->errorType == m_error)
1194 	    break;
1195     }
1196     return errDef->errorCode;
1197 }
1198 
errorFromCode(SS7TCAP::TCAPType tcapType,u_int16_t code)1199 int SS7TCAPError::errorFromCode(SS7TCAP::TCAPType tcapType, u_int16_t code)
1200 {
1201     const TCAPError* errDef = (tcapType == SS7TCAP::ANSITCAP ? s_ansiErrorDefs : s_ituErrorDefs);
1202     for (;errDef && errDef->errorType != SS7TCAPError::NoError; errDef++) {
1203 	if (errDef->errorCode == code)
1204 	    break;
1205     }
1206     return errDef->errorType;
1207 }
1208 
codeFromError(SS7TCAP::TCAPType tcapType,int err)1209 u_int16_t SS7TCAPError::codeFromError(SS7TCAP::TCAPType tcapType, int err)
1210 {
1211     const TCAPError* errDef = (tcapType == SS7TCAP::ANSITCAP ? s_ansiErrorDefs : s_ituErrorDefs);
1212     for (;errDef && errDef->errorType != SS7TCAPError::NoError; errDef++) {
1213 	if (errDef->errorType == err)
1214 	    break;
1215     }
1216     return errDef->errorCode;
1217 }
1218 
1219 /**
1220  * SS7TCAPTransaction
1221  */
SS7TCAPTransaction(SS7TCAP * tcap,SS7TCAP::TCAPUserTransActions type,const String & transactID,NamedList & params,u_int64_t timeout,bool initLocal)1222 SS7TCAPTransaction::SS7TCAPTransaction(SS7TCAP* tcap, SS7TCAP::TCAPUserTransActions type,
1223 	const String& transactID, NamedList& params, u_int64_t timeout, bool initLocal)
1224     : Mutex(true,"TcapTransaction"),
1225       m_tcap(tcap), m_tcapType(SS7TCAP::UnknownTCAP), m_userName(""), m_localID(transactID), m_type(type),
1226       m_localSCCPAddr(""), m_remoteSCCPAddr(""), m_basicEnd(true), m_endNow(false), m_timeout(timeout)
1227 {
1228 
1229     DDebug(m_tcap,DebugAll,"SS7TCAPTransaction(tcap = '%s' [%p], transactID = %s) created [%p]",
1230 	    m_tcap->toString().c_str(),tcap,transactID.c_str(),this);
1231 
1232     m_remoteID = params.getValue(s_tcapRemoteTID);
1233     populateSCCPAddress(m_localSCCPAddr,m_remoteSCCPAddr,params,initLocal,false);
1234     m_endNow = params.getBoolValue(s_tcapEndNow,false);
1235     if (initLocal)
1236 	setState(PackageSent);
1237     else
1238 	setState(PackageReceived);
1239 }
1240 
~SS7TCAPTransaction()1241 SS7TCAPTransaction::~SS7TCAPTransaction()
1242 {
1243     DDebug(tcap(),DebugAll,"Transaction with ID=%s of user=%s destroyed [%p]",
1244 	   m_localID.c_str(),m_userName.c_str(),this);
1245     m_components.clear();
1246     m_tcap = 0;
1247 }
1248 
findComponent(const String & id)1249 SS7TCAPComponent* SS7TCAPTransaction::findComponent(const String& id)
1250 {
1251     SS7TCAPComponent* comp = 0;
1252     ObjList* o = m_components.find(id);
1253     if (o)
1254 	comp = static_cast<SS7TCAPComponent*>(o->get());
1255     return comp;
1256 }
1257 
update(SS7TCAP::TCAPUserTransActions type,NamedList & params,bool updateByUser)1258 SS7TCAPError SS7TCAPTransaction::update(SS7TCAP::TCAPUserTransActions type, NamedList& params, bool updateByUser)
1259 {
1260     DDebug(tcap(),DebugStub,"SS7TCAPTransaction::update() [%p], localID=%s - stub",this,m_localID.c_str());
1261     SS7TCAPError error(m_tcapType);
1262     return error;
1263 }
1264 
buildComponentError(SS7TCAPError & error,NamedList & params,DataBlock & data)1265 SS7TCAPError SS7TCAPTransaction::buildComponentError(SS7TCAPError& error, NamedList& params, DataBlock& data)
1266 {
1267     if (error.error() == SS7TCAPError::NoError)
1268 	return error;
1269     Debug(tcap(),DebugInfo,"SS7TCAPTransaction::buildComponentError(error=%s) for transaction with id=%s [%p]",error.errorName().c_str(),
1270 	toString().c_str(),this);
1271     int compCount = params.getIntValue(s_tcapCompCount,1);
1272 
1273     if (!compCount)
1274 	return error;
1275 
1276     String param;
1277     compPrefix(param,compCount,true);
1278     bool buildRej = false;
1279     NamedString* typeStr = params.getParam(param + s_tcapCompType);
1280     if (TelEngine::null(typeStr))
1281 	buildRej = true;
1282     else {
1283 	int type = typeStr->toInteger(SS7TCAP::s_compPrimitives);
1284 	NamedString* invokeID  = params.getParam(param + s_tcapRemoteCID);
1285 
1286 	switch (type) {
1287 	    case SS7TCAP::TC_ResultLast:
1288 	    case SS7TCAP::TC_ResultNotLast:
1289 	    case SS7TCAP::TC_U_Error:
1290 		if (!TelEngine::null(invokeID)) {
1291 		    SS7TCAPComponent* comp = findComponent(*invokeID);
1292 		    if (comp)
1293 			m_components.remove(comp);
1294 		}
1295 		break;
1296 	    case SS7TCAP::TC_Invoke:
1297 	    case SS7TCAP::TC_R_Reject:
1298 	    default:
1299 		break;
1300 	}
1301 	buildRej = true;
1302     }
1303 
1304     params.setParam(param + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives,"L_Reject"));
1305     params.setParam(param + s_tcapProblemCode,String(error.error()));
1306     if (buildRej) {
1307 	SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,compCount);
1308 	if (comp)
1309 	    m_components.append(comp);
1310     }
1311     return error;
1312 }
1313 
handleComponents(NamedList & params,bool updateByUser)1314 SS7TCAPError SS7TCAPTransaction::handleComponents(NamedList& params, bool updateByUser)
1315 {
1316     XDebug(tcap(),DebugAll,"SS7TCAPTransaction::handleComponents(updateByUser=%s) [%p]",String::boolText(updateByUser),this);
1317     int count = params.getIntValue(s_tcapCompCount,0);
1318     SS7TCAPError error(m_tcapType);
1319     if (!count)
1320 	return error;
1321     int index = 0;
1322     Lock l(this);
1323     while (index < count) {
1324 	index++;
1325 	String paramRoot;
1326 	compPrefix(paramRoot,index,true);
1327 
1328 	NamedString* localCID = params.getParam(paramRoot + s_tcapLocalCID);
1329 	NamedString* typeStr = params.getParam(paramRoot + s_tcapCompType);
1330 	if (TelEngine::null(typeStr))
1331 	    continue;
1332 	int type = typeStr->toInteger(SS7TCAP::s_compPrimitives);
1333 	switch (type) {
1334 	    case SS7TCAP::TC_Invoke:
1335 	    case SS7TCAP::TC_InvokeNotLast:
1336 		if (!updateByUser) {
1337 		    if (!TelEngine::null(localCID)) {
1338 			// we have a linked/correlation ID, check the state of that component
1339 			SS7TCAPComponent* linkedTo = findComponent(*localCID);
1340 			if (!linkedTo) {
1341 			    type = SS7TCAP::TC_L_Reject;
1342 			    params.setParam(paramRoot + s_tcapProblemCode,String(SS7TCAPError::Invoke_UnrecognizedCorrelationID));
1343 			}
1344 			else {
1345 			    if (linkedTo->state() != SS7TCAPComponent::OperationSent) {
1346 				type = SS7TCAP::TC_L_Reject;
1347 				params.setParam(paramRoot + s_tcapProblemCode,String(SS7TCAPError::Invoke_UnexpectedLinkedOperation));
1348 			    }
1349 			}
1350 		    }
1351 		    if (type == SS7TCAP::TC_L_Reject) {
1352 			params.setParam(paramRoot + s_tcapCompType,lookup(type,SS7TCAP::s_compPrimitives,"L_Reject"));
1353 			SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,index);
1354 			if (comp)
1355 			    m_components.append(comp);
1356 		    }
1357 		}
1358 		else {
1359 		    if (!TelEngine::null(localCID)) {
1360 			if (findComponent(*localCID)) {
1361 			    error.setError(SS7TCAPError::Invoke_DuplicateInvokeID);
1362 			    return error;
1363 			}
1364 			else {
1365 			    SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,index);
1366 			    if (comp) {
1367 				m_components.append(comp);
1368 				comp->setState(SS7TCAPComponent::OperationSent);
1369 			    }
1370 			}
1371 		    }
1372 		}
1373 		break;
1374 	    case SS7TCAP::TC_ResultLast:
1375 	    case SS7TCAP::TC_ResultNotLast:
1376 	    case SS7TCAP::TC_U_Error:
1377 		if (!updateByUser) {
1378 		    if (!TelEngine::null(localCID)) {
1379 			SS7TCAPComponent* comp = findComponent(*localCID);
1380 			if (comp)
1381 			    comp->update(params,index);
1382 			else {
1383 			    params.setParam(paramRoot + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives,"L_Reject"));
1384 			    params.setParam(paramRoot + s_tcapProblemCode,String(SS7TCAPError::Invoke_UnexpectedLinkedOperation));
1385 			    SS7TCAPComponent* comp = SS7TCAPComponent::componentFromNamedList(m_tcapType,this,params,index);
1386 			    if (comp)
1387 				m_components.append(comp);
1388 			}
1389 		    }
1390 		}
1391 		break;
1392 	    case SS7TCAP::TC_R_Reject:
1393 	    case SS7TCAP::TC_U_Reject:
1394 		if (!updateByUser) {
1395 		    params.setParam(paramRoot + s_tcapCompType,lookup(SS7TCAP::TC_R_Reject,SS7TCAP::s_compPrimitives,"R_Reject"));
1396 		    if (!TelEngine::null(localCID)) {
1397 			SS7TCAPComponent* comp = findComponent(*localCID);
1398 			if (comp)
1399 			   m_components.remove(comp);
1400 		    }
1401 		}
1402 		else if (!TelEngine::null(localCID)) {
1403 		    m_components.remove(*localCID);
1404 		}
1405 		break;
1406 	    case SS7TCAP::TC_L_Reject:
1407 	    case SS7TCAP::TC_U_Cancel:
1408 		if (updateByUser) {
1409 		    if (!TelEngine::null(localCID))
1410 			m_components.remove(*localCID);
1411 		}
1412 		break;
1413 	    case SS7TCAP::TC_TimerReset:
1414 		if (updateByUser && !TelEngine::null(localCID) && m_tcapType == SS7TCAP::ITUTCAP) {
1415 		    SS7TCAPComponent* comp = findComponent(*localCID);
1416 		    if (comp)
1417 			comp->resetTimer(params,index);
1418 		}
1419 		break;
1420 	    case SS7TCAP::TC_L_Cancel:
1421 	    default:
1422 		break;
1423 	}
1424     }
1425     DDebug(tcap(),DebugAll,"SS7TCAPTransaction::handleComponents() - transaction with localID=%s handled %d components [%p]",
1426 	m_localID.c_str(),index,this);
1427     return error;
1428 }
1429 
requestComponents(NamedList & params,DataBlock & data)1430 void SS7TCAPTransaction::requestComponents(NamedList& params, DataBlock& data)
1431 {
1432     Lock(this);
1433     unsigned int index = params.getIntValue(s_tcapCompCount);
1434     for (ObjList* o = m_components.skipNull(); o; o = o->skipNext()) {
1435 	SS7TCAPComponent* comp = static_cast<SS7TCAPComponent*>(o->get());
1436 	if (comp && comp->state() == SS7TCAPComponent::OperationPending) {
1437 	    index++;
1438 	    comp->fill(index,params);
1439 	}
1440     }
1441 #ifdef DEBUG
1442     if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
1443 	dumpData(DebugAll,tcap(),"SS7TCAPTransaction::requestComponents() preparing to encode components:",this,params,data);
1444 #endif
1445     params.setParam(s_tcapCompCount,String(index));
1446     encodeComponents(params,data);
1447 #ifdef DEBUG
1448     if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
1449 	dumpData(DebugAll,tcap(),"SS7TCAPTransaction::requestComponents()  encoded components'",this,params,data);
1450 #endif
1451 }
1452 
transactionData(NamedList & params)1453 void SS7TCAPTransaction::transactionData(NamedList& params)
1454 {
1455     Lock l(this);
1456     params.setParam(s_tcapRequest,lookup(m_type,SS7TCAP::s_transPrimitives));
1457     params.setParam(s_tcapLocalTID,m_localID);
1458     params.setParam(s_tcapRemoteTID,m_remoteID);
1459 #ifdef DEBUG
1460     if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
1461 	dumpData(DebugAll,tcap(),"SS7TCAPTransaction::transactionData() - added transaction data",this,params);
1462 #endif
1463 }
1464 
checkComponents()1465 void SS7TCAPTransaction::checkComponents()
1466 {
1467     NamedList params("");
1468     int index = 0;
1469     Lock l(this);
1470     ListIterator iter(m_components);
1471     for (;;) {
1472 	SS7TCAPComponent* comp = static_cast<SS7TCAPComponent*>(iter.get());
1473 	if (!comp)
1474 	    break;
1475 	if (comp->timedOut()) {
1476 	    XDebug(tcap(),DebugInfo,"SS7TCAPTransaction::checkComponents() - component with local ID = %s timed out in"
1477 		    " transaction with local ID = %s [%p]",comp->toString().c_str(),toString().c_str(),this);
1478 	    SS7TCAP::TCAPUserCompActions type = comp->type();
1479 	    String paramRoot = "";
1480 	    switch (type) {
1481 		case SS7TCAP::TC_Invoke:
1482 		case SS7TCAP::TC_InvokeNotLast:
1483 			if (comp->operationClass() != SS7TCAP::NoReport) {
1484 			    index++;
1485 			    comp->setType(SS7TCAP::TC_L_Cancel);
1486 			    comp->fill(index,params);
1487 			}
1488 			comp->setState(SS7TCAPComponent::Idle);
1489 		    break;
1490 		case SS7TCAP::TC_ResultLast:
1491 		case SS7TCAP::TC_U_Error:
1492 		    comp->setState(SS7TCAPComponent::Idle);
1493 		    break;
1494 		case SS7TCAP::TC_ResultNotLast:
1495 		case SS7TCAP::TC_U_Reject:
1496 		case SS7TCAP::TC_L_Reject:
1497 		case SS7TCAP::TC_R_Reject:
1498 		case SS7TCAP::TC_L_Cancel:
1499 		case SS7TCAP::TC_U_Cancel:
1500 		case SS7TCAP::TC_TimerReset:
1501 		default:
1502 		    break;
1503 	    }
1504 	}
1505 	if (comp->state() == SS7TCAPComponent::Idle)
1506 	    m_components.remove(comp);
1507     }
1508     if (params.count()) {
1509 	params.setParam(s_tcapCompCount,String(index));
1510 	transactionData(params);
1511 	params.clearParam(s_tcapRequest);
1512 	tcap()->sendToUser(params);
1513     }
1514     if (m_components.count() == 0) {// we don't have any more components
1515 	if (!m_timeout.started()) {
1516 	    m_timeout.start();
1517 	    XDebug(tcap(),DebugInfo,"SS7TCAPTransaction::checkComponents() - timer for transaction with localID=%s has been started [%p]",
1518 		toString().c_str(),this);
1519 	}
1520     }
1521 }
1522 
setTransmitState(TransactionTransmit state)1523 void SS7TCAPTransaction::setTransmitState(TransactionTransmit state)
1524 {
1525     Lock l(this);
1526     m_transmit = state;
1527     if (m_transmit == Transmitted) {
1528 	switch (m_type) {
1529 	    case SS7TCAP::TC_Unidirectional:
1530 	    case SS7TCAP::TC_P_Abort:
1531 	    case SS7TCAP::TC_U_Abort:
1532 	    case SS7TCAP::TC_Response:
1533 	    case SS7TCAP::TC_End:
1534 		m_state = Idle;
1535 		break;
1536 	    case SS7TCAP::TC_Notice:
1537 	    case SS7TCAP::TC_Begin:
1538 	    case SS7TCAP::TC_QueryWithPerm:
1539 	    case SS7TCAP::TC_QueryWithoutPerm:
1540 	    case SS7TCAP::TC_Continue:
1541 	    case SS7TCAP::TC_ConversationWithPerm:
1542 	    case SS7TCAP::TC_ConversationWithoutPerm:
1543 	    default:
1544 		break;
1545 	}
1546     }
1547 }
1548 
addSCCPAddressing(NamedList & fillParams,bool local)1549 void SS7TCAPTransaction::addSCCPAddressing(NamedList& fillParams, bool local)
1550 {
1551     String localParam(local ? s_calledPA : s_callingPA);
1552     String remoteParam(local ? s_callingPA : s_calledPA);
1553     fillParams.clearParam(s_calledPA,'.');
1554     fillParams.clearParam(s_callingPA,'.');
1555     Lock l(this);
1556     fillParams.copyParam(m_localSCCPAddr,s_localPC);
1557     for (unsigned int i = 0; i < m_localSCCPAddr.count(); i++) {
1558 	NamedString* ns = m_localSCCPAddr.getParam(i);
1559 	if (ns && *ns && !(*ns).null()) {
1560 	    const String& name = ns->name();
1561 	    if (name != s_localPC)
1562 		fillParams.setParam(localParam + "." + name,*ns);
1563 	}
1564     }
1565     fillParams.copyParam(m_remoteSCCPAddr,s_remotePC);
1566     for (unsigned int i = 0; i < m_remoteSCCPAddr.count(); i++) {
1567 	NamedString* ns = m_remoteSCCPAddr.getParam(i);
1568 	if (ns && *ns && !(*ns).null()) {
1569 	    const String& name = ns->name();
1570 	    if (name != s_remotePC)
1571 		fillParams.setParam(remoteParam + "." +  name,*ns);
1572 	}
1573     }
1574 }
1575 
handleData(NamedList & params,DataBlock & data)1576 SS7TCAPError SS7TCAPTransaction::handleData(NamedList& params, DataBlock& data)
1577 {
1578     DDebug(tcap(),DebugAll,"SS7TCAPTransaction::handleData() transactionID=%s data length=%u [%p]",m_localID.c_str(),
1579 	   data.length(),this);
1580     Lock lock(this);
1581     // in case of Abort message, check Cause Information
1582     SS7TCAPError error(m_tcapType);
1583     return error;
1584 }
1585 
updateToEnd()1586 void SS7TCAPTransaction::updateToEnd()
1587 {
1588 }
1589 
abnormalDialogInfo(NamedList & params)1590 void SS7TCAPTransaction::abnormalDialogInfo(NamedList& params)
1591 {
1592     Debug(tcap(),DebugAll,"SS7TCAPTransaction::abnormalDialogInfo() [%p]",this);
1593 }
1594 
1595 /**
1596  * SS7TCAPComponent
1597  */
1598 const TokenDict SS7TCAPComponent::s_compStates[] = {
1599     {"Idle",                SS7TCAPComponent::Idle},
1600     {"OperationPending",    SS7TCAPComponent::OperationPending},
1601     {"OperationSent",       SS7TCAPComponent::OperationSent},
1602     {"WaitForReject",       SS7TCAPComponent::WaitForReject},
1603     {0,0}
1604 };
1605 
SS7TCAPComponent(SS7TCAP::TCAPType type,SS7TCAPTransaction * trans,NamedList & params,unsigned int index)1606 SS7TCAPComponent::SS7TCAPComponent(SS7TCAP::TCAPType type, SS7TCAPTransaction* trans, NamedList& params, unsigned int index)
1607     : m_transact(trans), m_state(Idle),
1608       m_id(""), m_corrID(""), m_opClass(SS7TCAP::SuccessOrFailureReport), m_opTimer(0), m_error(type)
1609 {
1610     String paramRoot;
1611     compPrefix(paramRoot,index,true);
1612 
1613     m_type = (SS7TCAP::TCAPUserCompActions) lookup(params.getValue(paramRoot + s_tcapCompType),SS7TCAP::s_compPrimitives);
1614     m_id = params.getValue(paramRoot + s_tcapLocalCID);
1615     m_corrID = params.getValue(paramRoot + s_tcapRemoteCID);
1616 
1617     setState(OperationPending);
1618 
1619     m_opType = params.getValue(paramRoot + s_tcapOpCodeType,"");
1620     m_opCode = params.getValue(paramRoot + s_tcapOpCode,"");
1621     NamedString* opClass = params.getParam(paramRoot + "operationClass");
1622     if (!TelEngine::null(opClass))
1623 	m_opClass = (SS7TCAP::TCAPComponentOperationClass) opClass->toInteger(SS7TCAP::s_compOperClasses,SS7TCAP::SuccessOrFailureReport);
1624     m_opTimer.interval(params.getIntValue(paramRoot + "timeout",5) * 1000);
1625 
1626     m_error.setError((SS7TCAPError::ErrorType)params.getIntValue(paramRoot + s_tcapProblemCode));
1627 
1628     DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent() [%p] created for transaction='%s' [%p] with localID=%s, remoteID=%s,"
1629 	    " type=%s, class=%s",this, (m_transact ? m_transact->toString().c_str() :""),m_transact,m_id.c_str(),
1630 	    m_corrID.c_str(),lookup(m_type,SS7TCAP::s_compPrimitives),lookup(m_opClass,SS7TCAP::s_compOperClasses));
1631 }
1632 
~SS7TCAPComponent()1633 SS7TCAPComponent::~SS7TCAPComponent()
1634 {
1635     DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::~SS7TCAPComponent() - component [%p] destroyed",this);
1636     m_transact = 0;
1637 }
1638 
update(NamedList & params,unsigned int index)1639 void SS7TCAPComponent::update(NamedList& params, unsigned int index)
1640 {
1641     String paramRoot;
1642     compPrefix(paramRoot,index,false);
1643     DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::update() - update component with localID=%s [%p]",m_id.c_str(),this);
1644 
1645     m_type = (SS7TCAP::TCAPUserCompActions) lookup(params.getValue(paramRoot + "." + s_tcapCompType),SS7TCAP::s_compPrimitives);
1646     switch (m_type) {
1647 	case SS7TCAP::TC_ResultLast:
1648 	    if (m_opClass == SS7TCAP::SuccessOrFailureReport || m_opClass == SS7TCAP::SuccessOnlyReport)
1649 		setState(WaitForReject);
1650 	    else if (m_opClass == SS7TCAP::FailureOnlyReport || m_opClass == SS7TCAP::NoReport) {
1651 		// build reject component
1652 		m_type = SS7TCAP::TC_L_Reject;
1653 		params.setParam(paramRoot + "." + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives));
1654 		params.setParam(paramRoot + "." + s_tcapProblemCode,String(SS7TCAPError::Result_UnexpectedReturnResult));
1655 		m_error.setError(SS7TCAPError::Result_UnexpectedReturnResult);
1656 		setState(OperationPending);
1657 		return;
1658 	    }
1659 	    break;
1660 	case SS7TCAP::TC_ResultNotLast:
1661 	    if (m_opClass == SS7TCAP::FailureOnlyReport || m_opClass == SS7TCAP::NoReport) {
1662 		// build reject component
1663 		m_type = SS7TCAP::TC_L_Reject;
1664 		params.setParam(paramRoot + "." + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives));
1665 		params.setParam(paramRoot + "." + s_tcapProblemCode,String(SS7TCAPError::Result_UnexpectedReturnResult));
1666 		m_error.setError(SS7TCAPError::Result_UnexpectedReturnResult);
1667 		setState(OperationPending);
1668 		return;
1669 	    }
1670 	    else if (m_opClass == SS7TCAP::SuccessOnlyReport)
1671 		setState(WaitForReject);
1672 	    break;
1673 	case SS7TCAP::TC_U_Error:
1674 	    if (m_opClass == SS7TCAP::FailureOnlyReport)
1675 		setState(WaitForReject);
1676 	    else if (m_opClass == SS7TCAP::SuccessOnlyReport || m_opClass == SS7TCAP::NoReport) {
1677 		m_type = SS7TCAP::TC_L_Reject;
1678 		params.setParam(paramRoot + "." + s_tcapCompType,lookup(SS7TCAP::TC_L_Reject,SS7TCAP::s_compPrimitives));
1679 		params.setParam(paramRoot + "." + s_tcapProblemCode,String(SS7TCAPError::Error_UnexpectedReturnError));
1680 		m_error.setError(SS7TCAPError::Error_UnexpectedReturnError);
1681 		setState(OperationPending);
1682 		return;
1683 	    }
1684 	    break;
1685 	case SS7TCAP::TC_TimerReset:
1686 	default:
1687 	    break;
1688     }
1689     if (TelEngine::null(params.getParam(paramRoot + "." + s_tcapOpCode))) {
1690 	params.setParam(paramRoot + "." + s_tcapOpCode,m_opCode);
1691 	params.setParam(paramRoot + "." + s_tcapOpCodeType,m_opType);
1692     }
1693 }
1694 
componentFromNamedList(SS7TCAP::TCAPType tcapType,SS7TCAPTransaction * tr,NamedList & params,unsigned int index)1695 SS7TCAPComponent* SS7TCAPComponent::componentFromNamedList(SS7TCAP::TCAPType tcapType, SS7TCAPTransaction* tr, NamedList& params, unsigned int index)
1696 {
1697     if (!tr)
1698 	return 0;
1699 
1700     String paramRoot;
1701     compPrefix(paramRoot,index,true);
1702     NamedString* str = params.getParam(paramRoot + s_tcapLocalCID);
1703     if (TelEngine::null(str))
1704 	str = params.getParam(paramRoot + s_tcapRemoteCID);
1705     if (TelEngine::null(str))
1706 	return 0;
1707     int type = lookup(params.getValue(paramRoot + s_tcapCompType),SS7TCAP::s_compPrimitives);
1708     // we allow building Reject components that have been built by Component layer or Invokes requested by local user
1709     if (type != SS7TCAP::TC_Invoke && type != SS7TCAP::TC_InvokeNotLast && type != SS7TCAP::TC_L_Reject
1710 	&& type != SS7TCAP::TC_U_Reject && type != SS7TCAP::TC_R_Reject)
1711 	return 0;
1712 
1713     SS7TCAPComponent* comp = new SS7TCAPComponent(tcapType,tr,params,index);
1714     return comp;
1715 }
1716 
setState(TCAPComponentState state)1717 void SS7TCAPComponent::setState(TCAPComponentState state)
1718 {
1719 #ifdef DEBUG
1720     if (m_transact && m_transact->tcap() && s_extendedDbg)
1721 	DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::setState(%s), locaID=%s remoteID=%s [%p]",lookup(state,s_compStates),
1722 		m_id.c_str(),m_corrID.c_str(),this);
1723 #endif
1724     m_state = state;
1725     m_opTimer.stop();
1726     if (!(state == Idle || state == OperationPending))
1727 	m_opTimer.start();
1728 }
1729 
fill(unsigned int index,NamedList & fillIn)1730 void SS7TCAPComponent::fill(unsigned int index, NamedList& fillIn)
1731 {
1732 #ifdef DEBUG
1733     if (m_transact && m_transact->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
1734 	DDebug(m_transact->tcap(),DebugAll,"SS7TCAPComponent::fill() - component with localID=%s,remoteID=%s of transaction=%s "
1735 	    "fill for index=%u [%p]",m_id.c_str(),m_corrID.c_str(),m_transact->toString().c_str(),index,this);
1736 #endif
1737     String paramRoot;
1738     compPrefix(paramRoot,index,true);
1739 
1740     fillIn.setParam(paramRoot + s_tcapLocalCID,m_id);
1741     fillIn.setParam(paramRoot + s_tcapRemoteCID,m_corrID);
1742     fillIn.setParam(paramRoot + s_tcapCompType,lookup(m_type,SS7TCAP::s_compPrimitives,"Unknown"));
1743 
1744     if (m_error.error() != SS7TCAPError::NoError) {
1745 	if (m_type == SS7TCAP::TC_U_Error)
1746 	    fillIn.setParam(paramRoot + s_tcapErrCode,String(m_error.error()));
1747 	else if (m_type == SS7TCAP::TC_L_Reject || m_type == SS7TCAP::TC_U_Reject || m_type == SS7TCAP::TC_R_Reject)
1748 	    fillIn.setParam(paramRoot + s_tcapProblemCode,String(m_error.error()));
1749     }
1750     if (m_type == SS7TCAP::TC_L_Cancel) {
1751 	fillIn.setParam(paramRoot + s_tcapOpCode,m_opCode);
1752 	fillIn.setParam(paramRoot + s_tcapOpCodeType,m_opType);
1753     }
1754     if (m_type == SS7TCAP::TC_U_Reject || m_type == SS7TCAP::TC_R_Reject || m_type == SS7TCAP::TC_L_Reject)
1755 	setState(Idle);
1756 }
1757 
resetTimer(NamedList & params,unsigned int index)1758 void SS7TCAPComponent::resetTimer(NamedList& params, unsigned int index)
1759 {
1760     DDebug(m_transact->tcap(),DebugInfo,"SS7TCAPComponent::resetTimer() [%p]",this);
1761     String paramRoot;
1762     compPrefix(paramRoot,index,false);
1763     if (state() == OperationSent)
1764 	m_opTimer.start();
1765     params.clearParam(paramRoot,'.');
1766 }
1767 
1768 // class SS7TCAPANSI
1769 
1770 static u_int8_t s_tcapProtoVersion = 0x04;
1771 
1772 static const PrimitiveMapping s_componentsANSIMap[] = {
1773     {SS7TCAP::TC_Invoke,              SS7TCAPTransactionANSI::InvokeLast},
1774     {SS7TCAP::TC_ResultLast,          SS7TCAPTransactionANSI::ReturnResultLast},
1775     {SS7TCAP::TC_U_Error,             SS7TCAPTransactionANSI::ReturnError},
1776     {SS7TCAP::TC_U_Reject,            SS7TCAPTransactionANSI::Reject},
1777     {SS7TCAP::TC_R_Reject,            SS7TCAPTransactionANSI::Reject},
1778     {SS7TCAP::TC_L_Reject,            SS7TCAPTransactionANSI::Reject},
1779     {SS7TCAP::TC_InvokeNotLast,       SS7TCAPTransactionANSI::InvokeNotLast},
1780     {SS7TCAP::TC_ResultNotLast,       SS7TCAPTransactionANSI::ReturnResultNotLast},
1781     {SS7TCAP::TC_L_Cancel,            SS7TCAPTransactionANSI::Local},
1782     {SS7TCAP::TC_U_Cancel,            SS7TCAPTransactionANSI::Local},
1783     {SS7TCAP::TC_TimerReset,          SS7TCAPTransactionANSI::Local},
1784 };
1785 
1786 static const PrimitiveMapping s_transANSIMap[] = {
1787     {SS7TCAP::TC_Unidirectional,              SS7TCAPTransactionANSI::Unidirectional},
1788     {SS7TCAP::TC_QueryWithPerm,               SS7TCAPTransactionANSI::QueryWithPermission},
1789     {SS7TCAP::TC_QueryWithoutPerm,            SS7TCAPTransactionANSI::QueryWithoutPermission},
1790     {SS7TCAP::TC_Begin,                       SS7TCAPTransactionANSI::QueryWithPermission}, // on receiving a ITU_T Begin, we'll map it to ANSI QueryWithPermission
1791     {SS7TCAP::TC_ConversationWithPerm,        SS7TCAPTransactionANSI::ConversationWithPermission},
1792     {SS7TCAP::TC_ConversationWithoutPerm,     SS7TCAPTransactionANSI::ConversationWithoutPermission},
1793     {SS7TCAP::TC_Continue,                    SS7TCAPTransactionANSI::ConversationWithPermission},
1794     {SS7TCAP::TC_Response,                    SS7TCAPTransactionANSI::Response},
1795     {SS7TCAP::TC_End,                         SS7TCAPTransactionANSI::Response},
1796     {SS7TCAP::TC_U_Abort,                     SS7TCAPTransactionANSI::Abort},
1797     {SS7TCAP::TC_P_Abort,                     SS7TCAPTransactionANSI::Abort},
1798     {SS7TCAP::TC_Notice,                      SS7TCAPTransactionANSI::Unknown},
1799     {SS7TCAP::TC_Unknown,                     SS7TCAPTransactionANSI::Unknown},
1800 };
1801 
mapCompPrimitivesANSI(int primitive,int comp=-1)1802 static const PrimitiveMapping* mapCompPrimitivesANSI(int primitive, int comp = -1)
1803 {
1804     const PrimitiveMapping* map = s_componentsANSIMap;
1805     for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
1806 	if (primitive != -1) {
1807 	    if (map->primitive == primitive )
1808 		break;
1809 	}
1810 	else if (comp != -1)
1811 	    if (map->mappedTo == comp)
1812 		break;
1813     }
1814     return map;
1815 }
1816 
mapTransPrimitivesANSI(int primitive,int trans=-1)1817 static const PrimitiveMapping* mapTransPrimitivesANSI(int primitive, int trans = -1)
1818 {
1819     const PrimitiveMapping* map = s_transANSIMap;
1820     for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
1821 	if (primitive != -1) {
1822 	    if (map->primitive == primitive )
1823 		break;
1824 	}
1825 	else if (trans != -1)
1826 	    if (map->mappedTo == trans)
1827 		break;
1828     }
1829     return map;
1830 }
1831 
primitiveToTransactANSI(String primitive,SS7TCAP::TCAPUserTransActions primitiveType=SS7TCAP::TC_Unknown)1832 static const SS7TCAPTransactionANSI::ANSITransactionType primitiveToTransactANSI(String primitive,
1833 	SS7TCAP::TCAPUserTransActions primitiveType = SS7TCAP::TC_Unknown)
1834 {
1835     SS7TCAPTransactionANSI::ANSITransactionType type = SS7TCAPTransactionANSI::Unknown;
1836 
1837     if (!primitive.null())
1838 	primitiveType = (SS7TCAP::TCAPUserTransActions)primitive.toInteger(SS7TCAP::s_transPrimitives);
1839 
1840     const PrimitiveMapping* map = mapTransPrimitivesANSI(primitiveType);
1841     if (map)
1842 	type = (SS7TCAPTransactionANSI::ANSITransactionType)map->mappedTo;
1843     return type;
1844 }
1845 
SS7TCAPANSI(const NamedList & params)1846 SS7TCAPANSI::SS7TCAPANSI(const NamedList& params)
1847     : SignallingComponent(params.safe("SS7TCAPANSI"),&params,"ss7-tcap-ansi"),
1848       SS7TCAP(params)
1849 {
1850     String tmp;
1851     params.dump(tmp,"\r\n  ",'\'',true);
1852     DDebug(this,DebugAll,"SS7TCAPANSI::SS7TCAPANSI(%s)",tmp.c_str());
1853     setTCAPType(SS7TCAP::ANSITCAP);
1854 }
1855 
~SS7TCAPANSI()1856 SS7TCAPANSI::~SS7TCAPANSI()
1857 {
1858     DDebug(this,DebugAll,"SS7TCAPANSI::~SS7TCAPANSI() [%p] destroyed with %d transactions, refCount=%d",
1859 		this,m_transactions.count(),refcount());
1860 }
1861 
buildTransaction(SS7TCAP::TCAPUserTransActions type,const String & transactID,NamedList & params,bool initLocal)1862 SS7TCAPTransaction* SS7TCAPANSI::buildTransaction(SS7TCAP::TCAPUserTransActions type, const String& transactID, NamedList& params,
1863 	bool initLocal)
1864 {
1865     return new SS7TCAPTransactionANSI(this,type,transactID,params,m_trTimeout,initLocal);
1866 }
1867 
decodeTransactionPart(NamedList & params,DataBlock & data)1868 SS7TCAPError SS7TCAPANSI::decodeTransactionPart(NamedList& params, DataBlock& data)
1869 {
1870     SS7TCAPError error(SS7TCAP::ANSITCAP);
1871     if (data.length() < 2)  // should find out which is the minimal TCAP message length
1872 	return error;
1873 
1874     // decode message type
1875     u_int8_t msgType = data[0];
1876     data.cut(-1);
1877 
1878     const PrimitiveMapping* map = mapTransPrimitivesANSI(-1,msgType);
1879     if (map) {
1880 	String type = lookup(map->primitive,SS7TCAP::s_transPrimitives,"Unknown");
1881 	params.setParam(s_tcapRequest,type);
1882     }
1883 
1884     // decode message length
1885     unsigned int len = ASNLib::decodeLength(data);
1886     if (len != data.length())
1887 	return error;
1888     // decode transaction IDs, start with Transaction Identifier
1889     u_int8_t tag = data[0];
1890     if (tag != TransactionIDTag) {// 0xc7
1891 	error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
1892 	return error; // check it
1893     }
1894     data.cut(-1);
1895 
1896     // if we'll detect an error, it should be a BadlyStructuredTransaction error
1897     error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
1898 
1899     len = ASNLib::decodeLength(data);
1900     if (len > data.length() || data.length() < len || (len != 0 && len != 4 && len != 8))
1901 	return error;
1902 
1903     // transaction IDs shall be decoded according to message type
1904     String tid1, tid2;
1905     if (len  > 0 ) {
1906 	tid1.hexify(data.data(),4,' ');
1907 	data.cut(-4);
1908 	if (len == 8) {
1909 	    tid2.hexify(data.data(),4,' ');
1910 	    data.cut(-4);
1911 	}
1912     }
1913     switch (msgType) {
1914 	case SS7TCAPTransactionANSI::Unidirectional:
1915 	    if (len != 0)
1916 		return error;
1917 	    break;
1918 	case SS7TCAPTransactionANSI::QueryWithPermission:
1919 	case SS7TCAPTransactionANSI::QueryWithoutPermission:
1920 	    if (len != 4)
1921 		return error;
1922 	    params.setParam(s_tcapRemoteTID,tid1);
1923 	    break;
1924 	case SS7TCAPTransactionANSI::Response:
1925 	case SS7TCAPTransactionANSI::Abort:
1926 	    if (len != 4)
1927 		return error;
1928 	    params.setParam(s_tcapLocalTID,tid1);
1929 	    break;
1930 	case SS7TCAPTransactionANSI::ConversationWithPermission:
1931 	case SS7TCAPTransactionANSI::ConversationWithoutPermission:
1932 	    if (len != 8)
1933 		return error;
1934 	    params.setParam(s_tcapRemoteTID,tid1);
1935 	    params.setParam(s_tcapLocalTID,tid2);
1936 	    break;
1937 	default:
1938 	    error.setError(SS7TCAPError::Transact_UnrecognizedPackageType);
1939 	    return error;
1940     };
1941 
1942 #ifdef DEBUG
1943     if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
1944 	dumpData(DebugAll,this,"SS7TCAPANSI::decodeTransactionPart() finished",this,params,data);
1945 #endif
1946 
1947     error.setError(SS7TCAPError::NoError);
1948     return error;
1949 }
1950 
encodeTransactionPart(NamedList & params,DataBlock & data)1951 void SS7TCAPANSI::encodeTransactionPart(NamedList& params, DataBlock& data)
1952 {
1953 #ifdef DEBUG
1954     if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
1955 	dumpData(DebugAll,this,"SS7TCAPANSI::encodeTransactionPart() - to be encoded",this,params,data);
1956 #endif
1957 
1958     int msgType = primitiveToTransactANSI(params.getValue(s_tcapRequest));
1959 
1960     const String& otid = params[s_tcapLocalTID];
1961     const String& dtid = params[s_tcapRemoteTID];
1962 
1963     String ids;
1964     switch (msgType) {
1965 	case SS7TCAPTransactionANSI::Unidirectional:
1966 	    break;
1967 	case SS7TCAPTransactionANSI::QueryWithPermission:
1968 	case SS7TCAPTransactionANSI::QueryWithoutPermission:
1969 	    ids = otid;
1970 	    break;
1971 	case SS7TCAPTransactionANSI::Response:
1972 	case SS7TCAPTransactionANSI::Abort:
1973 	    ids = dtid;
1974 	    break;
1975 	case SS7TCAPTransactionANSI::ConversationWithPermission:
1976 	case SS7TCAPTransactionANSI::ConversationWithoutPermission:
1977 	    ids << otid << " " << dtid;
1978 	    break;
1979 	default:
1980 	    break;
1981     };
1982 
1983     DataBlock db;
1984     db.unHexify(ids.c_str(),ids.length(),' ');
1985     db.insert(ASNLib::buildLength(db));
1986     int tag = TransactionIDTag;
1987     db.insert(DataBlock(&tag,1));
1988 
1989     data.insert(db);
1990     data.insert(ASNLib::buildLength(data));
1991     data.insert(DataBlock(&msgType,1));
1992 }
1993 
1994 /**
1995  * SS7TCAPTransactionANSI implementation
1996  */
1997 const TokenDict SS7TCAPTransactionANSI::s_ansiTransactTypes[] = {
1998     {"Unidirectional",                SS7TCAPTransactionANSI::Unidirectional},
1999     {"QueryWithPermission",           SS7TCAPTransactionANSI::QueryWithPermission},
2000     {"QueryWithoutPermission",        SS7TCAPTransactionANSI::QueryWithoutPermission},
2001     {"Response",                      SS7TCAPTransactionANSI::Response},
2002     {"ConversationWithPermission",    SS7TCAPTransactionANSI::ConversationWithPermission},
2003     {"ConversationWithoutPermission", SS7TCAPTransactionANSI::ConversationWithoutPermission},
2004     {"Abort",                         SS7TCAPTransactionANSI::Abort},
2005     {0,0},
2006 };
2007 
SS7TCAPTransactionANSI(SS7TCAP * tcap,SS7TCAP::TCAPUserTransActions type,const String & transactID,NamedList & params,u_int64_t timeout,bool initLocal)2008 SS7TCAPTransactionANSI::SS7TCAPTransactionANSI(SS7TCAP* tcap, SS7TCAP::TCAPUserTransActions type,
2009 	const String& transactID, NamedList& params, u_int64_t timeout, bool initLocal)
2010     : SS7TCAPTransaction(tcap,type,transactID,params,timeout,initLocal),
2011       m_prevType(type)
2012 {
2013     DDebug(tcap,DebugAll,"SS7TCAPTransactionANSI[%p] created with type='%s' and localID='%s'",this,
2014 	    lookup(type,SS7TCAP::s_transPrimitives),m_localID.c_str());
2015 }
2016 
~SS7TCAPTransactionANSI()2017 SS7TCAPTransactionANSI::~SS7TCAPTransactionANSI()
2018 {
2019     DDebug(tcap(),DebugAll,"Transaction with ID=%s of user=%s destroyed, TCAP refcount=%d [%p]",
2020 	   m_localID.c_str(),m_userName.c_str(),tcap()->refcount(),this);
2021 }
2022 
handleData(NamedList & params,DataBlock & data)2023 SS7TCAPError SS7TCAPTransactionANSI::handleData(NamedList& params, DataBlock& data)
2024 {
2025     XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::handleData() transactionID=%s data length=%u [%p]",m_localID.c_str(),
2026 	   data.length(),this);
2027     Lock lock(this);
2028     // decode DialogPortion
2029     SS7TCAPError error = decodeDialogPortion(params,data);
2030     if (error.error() != SS7TCAPError::NoError)
2031 	return error;
2032     error = handleDialogPortion(params,false);
2033     if (error.error() != SS7TCAPError::NoError)
2034 	return error;
2035 
2036     // in case of Abort message, check Cause Information
2037     String msg = params.getValue(s_tcapMsgType);
2038     if (msg.toInteger(s_ansiTransactTypes) == Abort) {
2039 	error = decodePAbort(this,params,data);
2040 	if (error.error() != SS7TCAPError::NoError)
2041 	    return error;
2042     }
2043     // decodeComponents
2044     error = decodeComponents(params,data);
2045     if (error.error() != SS7TCAPError::NoError)
2046 	buildComponentError(error,params,data);
2047 
2048     error = handleComponents(params,false);
2049     return error;
2050 }
2051 
update(SS7TCAP::TCAPUserTransActions type,NamedList & params,bool updateByUser)2052 SS7TCAPError SS7TCAPTransactionANSI::update(SS7TCAP::TCAPUserTransActions type, NamedList& params, bool updateByUser)
2053 {
2054     DDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::update() [%p], localID=%s - update to type=%s initiated by %s",this,m_localID.c_str(),
2055 	lookup(type,SS7TCAP::s_transPrimitives,"Unknown"), (updateByUser ? "user" : "remote"));
2056 #ifdef DEBUG
2057     if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
2058 	dumpData(DebugAll,tcap(),"SS7TCAPTransactionANSI::update() with",this,params);
2059 #endif
2060     Lock l(this);
2061     SS7TCAPError error(SS7TCAP::ANSITCAP);
2062     switch (type) {
2063 	case SS7TCAP::TC_Begin:
2064 	case SS7TCAP::TC_QueryWithPerm:
2065 	case SS7TCAP::TC_QueryWithoutPerm:
2066 	case SS7TCAP::TC_Unidirectional:
2067 	    Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
2068 		    this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
2069 		    lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
2070 	    params.setParam(s_tcapRequestError,"invalid_update");
2071 	    params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
2072 	    error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
2073 	    return error;
2074 
2075 	case SS7TCAP::TC_End:
2076 	case SS7TCAP::TC_Response:
2077 	    if (m_type == SS7TCAP::TC_QueryWithoutPerm || m_type == SS7TCAP::TC_ConversationWithoutPerm) {
2078 		params.setParam(s_tcapRequestError,"invalid_update");
2079 		params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
2080 		error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
2081 		return error;
2082 	    }
2083 	    else {
2084 		if (!m_basicEnd)
2085 		    // prearranged end, no need to transmit to remote end
2086 		    m_transmit = NoTransmit;
2087 		else
2088 		    m_transmit = PendingTransmit;
2089 		m_type = type;
2090 	    }
2091 	    break;
2092 	case SS7TCAP::TC_Continue:
2093 	case SS7TCAP::TC_ConversationWithPerm:
2094 	case SS7TCAP::TC_ConversationWithoutPerm:
2095 	    if (m_type == SS7TCAP::TC_End || m_type == SS7TCAP::TC_Response) {
2096 		params.setParam(s_tcapRequestError,"invalid_update");
2097 		params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
2098 		error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
2099 		return error;
2100 	    }
2101 	    else {
2102 		m_remoteID = params.getValue(s_tcapRemoteTID);
2103 		m_type = type;
2104 		m_transmit = PendingTransmit;
2105 	    }
2106 	    break;
2107 	case SS7TCAP::TC_Notice:
2108 	case SS7TCAP::TC_P_Abort:
2109 	    if (updateByUser) {
2110 		Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
2111 		    this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
2112 		    lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
2113 		params.setParam(s_tcapRequestError,"invalid_update");
2114 		params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
2115 		error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
2116 		return error;
2117 	    }
2118 	case SS7TCAP::TC_U_Abort:
2119 	    if (!updateByUser && String("pAbort") == params.getValue(s_tcapAbortCause))
2120 		m_type = SS7TCAP::TC_P_Abort;
2121 	    else
2122 		m_type = type;
2123 	    m_transmit = PendingTransmit;
2124 	    break;
2125 	default:
2126 	    break;
2127     }
2128 
2129     populateSCCPAddress(m_localSCCPAddr,m_remoteSCCPAddr,params,updateByUser);
2130     if (updateByUser) {
2131 	setState(PackageSent);
2132 	m_basicEnd = params.getBoolValue(s_tcapBasicTerm,true);
2133 	m_endNow = params.getBoolValue(s_tcapEndNow,false);
2134     }
2135     else
2136 	setState(PackageReceived);
2137     if (m_timeout.started()) {
2138 	m_timeout.stop();
2139 	XDebug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::update() [%p], localID=%s - timeout timer has been stopped",this,m_localID.c_str());
2140     }
2141     return error;
2142 }
2143 
decodeDialogPortion(NamedList & params,DataBlock & data)2144 SS7TCAPError SS7TCAPTransactionANSI::decodeDialogPortion(NamedList& params, DataBlock& data)
2145 {
2146     XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::decodeDialogPortion() for transaction with localID=%s [%p]",
2147 	m_localID.c_str(),this);
2148 
2149     SS7TCAPError error(SS7TCAP::ANSITCAP);
2150 
2151     u_int8_t tag = data[0];
2152     // dialog is not present
2153     if (tag != SS7TCAPANSI::DialogPortionTag) // 0xf9
2154 	return error;
2155     data.cut(-1);
2156 
2157     // dialog portion is present, decode dialog length
2158     int len = ASNLib::decodeLength(data);
2159     if (len < 0 || len > (int)data.length()) {
2160 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2161 	return error;
2162     }
2163 
2164     tag = data[0];
2165     // check for protocol version
2166     if (data[0] == SS7TCAPANSI::ProtocolVersionTag) { //0xda
2167 	data.cut(-1);
2168 	// decode protocol version
2169 	u_int8_t proto;
2170 	len = ASNLib::decodeUINT8(data,&proto,false);
2171 	if (len != 1) {
2172 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2173 	    return error;
2174 	}
2175 	params.setParam(s_tcapProtoVers,String(proto));
2176     }
2177 
2178     tag = data[0];
2179     // check for Application Context
2180     if (tag == SS7TCAPANSI::IntApplicationContextTag || tag == SS7TCAPANSI::OIDApplicationContextTag) { // 0xdb , 0xdc
2181 	data.cut(-1);
2182 	 if (tag == SS7TCAPANSI::IntApplicationContextTag) { //0xdb
2183 	    u_int64_t val = 0;
2184 	    len = ASNLib::decodeInteger(data,val,sizeof(int),false);
2185 	    if (len < 0) {
2186 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2187 		return error;
2188 	    }
2189 	    params.setParam(s_tcapIntAppID,String((int)val));
2190 	}
2191 	if (tag == SS7TCAPANSI::OIDApplicationContextTag) { // oxdc
2192 	    ASNObjId oid;
2193 	    len = ASNLib::decodeOID(data,&oid,false);
2194 	    if (len < 0) {
2195 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2196 		return error;
2197 	    }
2198 	    params.setParam(s_tcapObjAppID,oid.toString());
2199 	}
2200     }
2201 
2202     // check for user information
2203     tag = data[0];
2204     if (tag == SS7TCAPANSI::UserInformationTag) {// 0xfd
2205 	data.cut(-1);
2206 	len = ASNLib::decodeLength(data);
2207 	if (len < 0) {
2208 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2209 	    return error;
2210 	}
2211 
2212 	tag = data[0];
2213 	if (tag != SS7TCAPANSI::ExternalTag) {
2214 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2215 	    return error;
2216 	}
2217 	data.cut(-1);
2218 
2219 	len = ASNLib::decodeLength(data);
2220 	if (len < 0 || len > (int)data.length()) {
2221 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2222 	    return error;
2223 	}
2224 	// direct Reference
2225 	tag = data[0];
2226 	if (tag == SS7TCAPANSI::DirectReferenceTag) { // 0x06
2227 	    data.cut(-1);
2228 	    ASNObjId oid;
2229 	    len = ASNLib::decodeOID(data,&oid,false);
2230 	    if (len < 0) {
2231 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2232 		return error;
2233 	    }
2234 	    params.setParam(s_tcapReference,oid.toString());
2235 	}
2236 	// data Descriptor
2237 	tag = data[0];
2238 	if (tag == SS7TCAPANSI::DataDescriptorTag) { // 0x07
2239 	    data.cut(-1);
2240 	    String str;
2241 	    int type;
2242 	    len = ASNLib::decodeString(data,&str,&type,false);
2243 	    if (len < 0) {
2244 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2245 		return error;
2246 	    }
2247 	    params.setParam(s_tcapDataDesc,str);
2248 	}
2249 	// encoding
2250 	tag = data[0];
2251 	if (tag == SS7TCAPANSI::SingleASNTypePEncTag || tag == SS7TCAPANSI::SingleASNTypeCEncTag ||
2252 	    tag == SS7TCAPANSI::OctetAlignEncTag || tag == SS7TCAPANSI::ArbitraryEncTag) {
2253 	    data.cut(-1);
2254 	    len = ASNLib::decodeLength(data);
2255 	    if (len < 0) {
2256 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2257 		return error;
2258 	    }
2259 	    DataBlock d((void*)data.data(0,len),len);
2260 	    data.cut(-len);
2261 
2262 	    // put encoding context in hexified form
2263 	    String dataHexified;
2264 	    dataHexified.hexify(d.data(),d.length(),' ');
2265 	    params.setParam(s_tcapEncodingContent,dataHexified);
2266 	    // put encoding identifier
2267 	    switch (tag) {
2268 		case SS7TCAPANSI::SingleASNTypePEncTag: // 0x80
2269 		    params.setParam(s_tcapEncodingType,"single-ASN1-type-primitive");
2270 		    break;
2271 		case SS7TCAPANSI::SingleASNTypeCEncTag: // 0xa0
2272 		    params.setParam(s_tcapEncodingType,"single-ASN1-type-contructor");
2273 		    break;
2274 		case SS7TCAPANSI::OctetAlignEncTag:     // 0x81
2275 		    params.setParam(s_tcapEncodingType,"octet-aligned");
2276 		    break;
2277 		case SS7TCAPANSI::ArbitraryEncTag:      // 0x82
2278 		    params.setParam(s_tcapEncodingType,"arbitrary");
2279 		    break;
2280 		default:
2281 		    break;
2282 	    }
2283 	}
2284     }
2285 
2286     // check for security context
2287     tag = data[0];
2288     if (tag == SS7TCAPANSI::IntSecurityContextTag || tag == SS7TCAPANSI::OIDSecurityContextTag) {
2289 	data.cut(-1);
2290 	if (tag == SS7TCAPANSI::IntSecurityContextTag) { //0x80
2291 	    int val = 0;
2292 	    len = ASNLib::decodeINT32(data,&val,false);
2293 	    if (len < 0) {
2294 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2295 		return error;
2296 	    }
2297 	    params.setParam(s_tcapIntSecID,String(val));
2298 	}
2299 	if (tag == SS7TCAPANSI::OIDSecurityContextTag) { // 0x81
2300 	    ASNObjId oid;
2301 	    len = ASNLib::decodeOID(data,&oid,false);
2302 	    if (len < 0) {
2303 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2304 		return error;
2305 	    }
2306 	    params.setParam(s_tcapObjSecID,oid.toString());
2307 	}
2308     }
2309 
2310     // check for Confidentiality information
2311     tag = data[0];
2312     if (tag == SS7TCAPANSI::ConfidentialityTag) { // 0xa2
2313 	data.cut(-1);
2314 	len = ASNLib::decodeLength(data);
2315 	if (len < 0) {
2316 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2317 	    return error;
2318 	}
2319 	tag = data[0];
2320 	if (tag == SS7TCAPANSI::IntSecurityContextTag || tag == SS7TCAPANSI::OIDSecurityContextTag) {
2321 	    data.cut(-1);
2322 	    if (tag == SS7TCAPANSI::IntSecurityContextTag) { //0x80
2323 		int val = 0;
2324 		len = ASNLib::decodeINT32(data,&val,false);
2325 		if (len < 0) {
2326 		    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2327 		    return error;
2328 		}
2329 		params.setParam(s_tcapIntConfidID,String(val));
2330 	    }
2331 	    if (tag == SS7TCAPANSI::OIDSecurityContextTag) { // 0x81
2332 		ASNObjId oid;
2333 		len = ASNLib::decodeOID(data,&oid,false);
2334 		if (len < 0) {
2335 		    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
2336 		    return error;
2337 		}
2338 		params.setParam(s_tcapObjConfidID,oid.toString());
2339 	    }
2340 	}
2341     }
2342 #ifdef DEBUG
2343      if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
2344 	 dumpData(DebugAll,tcap(),"SS7TCAPTransactionANSI::decodeDialogPortion() - decoded dialog portion",this,params,data);
2345 #endif
2346     return error;
2347 }
2348 
encodeDialogPortion(NamedList & params,DataBlock & data)2349 void SS7TCAPTransactionANSI::encodeDialogPortion(NamedList& params, DataBlock& data)
2350 {
2351     XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::encodeDialogPortion() for transaction with localID=%s [%p]",m_localID.c_str(),this);
2352 
2353     DataBlock dialogData;
2354     int tag;
2355 
2356     // encode confidentiality information
2357     NamedString* val = params.getParam(s_tcapIntConfidID);
2358     NamedString* oidStr = params.getParam(s_tcapObjConfidID);
2359     ASNObjId oid;
2360 
2361     if (!TelEngine::null(val) && !TelEngine::null(oidStr)) {
2362 	// parameter error, encoding of this portion skipped
2363 	Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::encodeDialogPortion() - skipping encoding of Confidentiality Information,"
2364 	      " both IntegerConfidentialityAlgorithmID=%s and ObjectIDConfidentialityID=%s specified, can't pick one",
2365 	      val->c_str(),oidStr->c_str());
2366     }
2367     else {
2368 	if (!TelEngine::null(val)) {
2369 	    DataBlock db = ASNLib::encodeInteger(val->toInteger(),false);
2370 	    db.insert(ASNLib::buildLength(db));
2371 	    tag = SS7TCAPANSI::IntSecurityContextTag;
2372 	    db.insert(DataBlock(&tag,1));
2373 
2374 	    dialogData.insert(db);
2375 	}
2376 	else if (!TelEngine::null(oidStr)) {
2377 	    oid = *oidStr;
2378 	    DataBlock db = ASNLib::encodeOID(oid,false);
2379 	    db.insert(ASNLib::buildLength(db));
2380 	    tag = SS7TCAPANSI::OIDSecurityContextTag;
2381 	    db.insert(DataBlock(&tag,1));
2382 
2383 	    dialogData.insert(db);
2384 	}
2385 	if (dialogData.length()) {
2386 	    dialogData.insert(ASNLib::buildLength(dialogData));
2387 	    tag = SS7TCAPANSI::ConfidentialityTag;
2388 	    dialogData.insert(DataBlock(&tag,1));
2389 	}
2390     }
2391     // encode security information
2392     val = params.getParam(s_tcapIntSecID);
2393     oidStr = params.getParam(s_tcapObjSecID);
2394 
2395     if (!TelEngine::null(val) && !TelEngine::null(oidStr)) {
2396 	// parameter error, encoding of this portion skipped
2397 	Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::encodeDialogPortion() - skipping encoding of Security Context Information,"
2398 	      " both IntegerSecurityContext=%s and ObjectIDSecurityContext=%s specified, can't pick one",
2399 	      val->c_str(),oid.toString().c_str());
2400     }
2401     else if (!TelEngine::null(val)) {
2402 	DataBlock db = ASNLib::encodeInteger(val->toInteger(),false);
2403 	db.insert(ASNLib::buildLength(db));
2404 	tag = SS7TCAPANSI::IntSecurityContextTag;
2405 	db.insert(DataBlock(&tag,1));
2406 
2407 	dialogData.insert(db);
2408     }
2409     else if (!TelEngine::null(oidStr)) {
2410 	oid = *oidStr;
2411 	DataBlock db = ASNLib::encodeOID(oid,false);
2412 	db.insert(ASNLib::buildLength(db));
2413 	tag = SS7TCAPANSI::OIDSecurityContextTag;
2414 	db.insert(DataBlock(&tag,1));
2415 
2416 	dialogData.insert(db);
2417     }
2418 
2419     // encode user information
2420     DataBlock userInfo;
2421     val = params.getParam(s_tcapEncodingType);
2422     if (!TelEngine::null(val)) {
2423 	if (*val == "single-ASN1-type-primitive")
2424 	    tag = SS7TCAPANSI::SingleASNTypePEncTag;
2425 	else if (*val == "single-ASN1-type-contructor")
2426 	    tag = SS7TCAPANSI::SingleASNTypeCEncTag;
2427 	else if (*val == "octet-aligned")
2428 	    tag = SS7TCAPANSI::OctetAlignEncTag;
2429 	else if (*val == "arbitrary")
2430 	    tag = SS7TCAPANSI::ArbitraryEncTag;
2431 
2432 	val = params.getParam(s_tcapEncodingContent);
2433 	if (val) {
2434 	    DataBlock db;
2435 	    db.unHexify(val->c_str(),val->length(),' ');
2436 	    db.insert(ASNLib::buildLength(db));
2437 	    db.insert(DataBlock(&tag,1));
2438 
2439 	    userInfo.insert(db);
2440 	}
2441     }
2442     val = params.getParam(s_tcapDataDesc);
2443     if (!TelEngine::null(val)) {
2444 	DataBlock db = ASNLib::encodeString(*val,ASNLib::PRINTABLE_STR,false);
2445 	db.insert(ASNLib::buildLength(db));
2446 	tag = SS7TCAPANSI::DataDescriptorTag;
2447 	db.insert(DataBlock(&tag,1));
2448 
2449 	userInfo.insert(db);
2450     }
2451     val = params.getParam(s_tcapReference);
2452     if (!TelEngine::null(val)) {
2453 	oid = *val;
2454 	DataBlock db = ASNLib::encodeOID(oid,false);
2455 	db.insert(ASNLib::buildLength(db));
2456 	tag = SS7TCAPANSI::DirectReferenceTag;
2457 	db.insert(DataBlock(&tag,1));
2458 
2459 	userInfo.insert(db);
2460     }
2461 
2462     if (userInfo.length()) {
2463 	userInfo.insert(ASNLib::buildLength(userInfo));
2464 	tag = SS7TCAPANSI::ExternalTag;
2465 	userInfo.insert(DataBlock(&tag,1));
2466 	userInfo.insert(ASNLib::buildLength(userInfo));
2467 	tag = SS7TCAPANSI::UserInformationTag;
2468 	userInfo.insert(DataBlock(&tag,1));
2469 
2470 	dialogData.insert(userInfo);
2471     }
2472 
2473     // Aplication context
2474     val = params.getParam(s_tcapIntAppID);
2475     oidStr = params.getParam(s_tcapObjAppID);
2476     if (!TelEngine::null(val) && !TelEngine::null(oidStr)) {
2477 	// parameter error, encoding of this portion skipped
2478 	Debug(tcap(),DebugInfo,"SS7TCAPTransactionANSI::encodeDialogPortion() - skipping encoding of Application Context Information,"
2479 	    " both IntegerApplicationID=%s and ObjectApplicationID=%s specified, can't pick one",val->c_str(),oid.toString().c_str());
2480     }
2481     else if (!TelEngine::null(val)) {
2482 	DataBlock db = ASNLib::encodeInteger(val->toInteger(),false);
2483 	db.insert(ASNLib::buildLength(db));
2484 	tag = SS7TCAPANSI::IntApplicationContextTag;
2485 	db.insert(DataBlock(&tag,1));
2486 
2487 	dialogData.insert(db);
2488     }
2489     else if (!TelEngine::null(oidStr)) {
2490 	oid = *oidStr;
2491 	DataBlock db = ASNLib::encodeOID(oid,false);
2492 	db.insert(ASNLib::buildLength(db));
2493 	tag = SS7TCAPANSI::OIDApplicationContextTag;
2494 	db.insert(DataBlock(&tag,1));
2495 
2496 	dialogData.insert(db);
2497     }
2498 
2499     val = params.getParam(s_tcapProtoVers);
2500     if (!TelEngine::null(val)) {
2501 	u_int8_t proto = val->toInteger();
2502 	DataBlock db  = ASNLib::encodeInteger(proto,false);
2503 	db.insert(ASNLib::buildLength(db));
2504 	tag = SS7TCAPANSI::ProtocolVersionTag;
2505 	db.insert(DataBlock(&tag,1));
2506 	dialogData.insert(db);
2507     }
2508 
2509     if (dialogData.length()) {
2510 	dialogData.insert(ASNLib::buildLength(dialogData));
2511 	tag = SS7TCAPANSI::DialogPortionTag;
2512 	dialogData.insert(DataBlock(&tag,1));
2513     }
2514 
2515     data.insert(dialogData);
2516     params.clearParam(s_tcapDialogPrefix,'.');
2517 #ifdef DEBUG
2518      if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
2519 	 dumpData(DebugAll,tcap(),"SS7TCAPTransactionANSI::encodeDialogPortion() - encoded dialog portion",this,params,data);
2520 #endif
2521 }
2522 
decodePAbort(SS7TCAPTransaction * tr,NamedList & params,DataBlock & data)2523 SS7TCAPError SS7TCAPTransactionANSI::decodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
2524 {
2525     u_int8_t tag = data[0];
2526     SS7TCAPError error(SS7TCAP::ANSITCAP);
2527     if (tag == SS7TCAPANSI::PCauseTag || tag == SS7TCAPANSI::UserAbortPTag ||  tag == SS7TCAPANSI::UserAbortCTag) {
2528 	SS7TCAPError error(SS7TCAP::ANSITCAP);
2529 	data.cut(-1);
2530 	if (tag == SS7TCAPANSI::PCauseTag) {
2531 	    u_int8_t pCode = 0;
2532 	    int len = ASNLib::decodeUINT8(data,&pCode,false);
2533 	    if (len != 1) {
2534 		error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
2535 		return error;
2536 	    }
2537 	    params.setParam(s_tcapAbortCause,"pAbort");
2538 	    params.setParam(s_tcapAbortInfo,String(SS7TCAPError::errorFromCode(SS7TCAP::ANSITCAP,pCode)));
2539 	}
2540 	else {
2541 	    int len = ASNLib::decodeLength(data);
2542 	    if (len < 0) {
2543 		error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
2544 		return error;
2545 	    }
2546 	    String str;
2547 	    str.hexify(data.data(0,len),len,' ');
2548 	    data.cut(-len);
2549 	    params.setParam(s_tcapAbortCause,(tag == SS7TCAPANSI::UserAbortPTag ? "userAbortP" : "userAbortC"));
2550 	    params.setParam(s_tcapAbortInfo,str);
2551 	    if (tr)
2552 		tr->setTransactionType(SS7TCAP::TC_U_Abort);
2553 	}
2554 #ifdef DEBUG
2555      if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
2556 	 dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionANSI::decodePAbort() - decoded Abort info",tr,params,data);
2557 #endif
2558     }
2559     return error;
2560 }
2561 
encodePAbort(SS7TCAPTransaction * tr,NamedList & params,DataBlock & data)2562 void SS7TCAPTransactionANSI::encodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
2563 {
2564     NamedString* pAbortCause = params.getParam(s_tcapAbortCause);
2565     DataBlock db;
2566     if (!TelEngine::null(pAbortCause)) {
2567 	int tag = 0;
2568 	if (*pAbortCause == "pAbort") {
2569 	    tag = SS7TCAPANSI::PCauseTag;
2570 	    u_int16_t pCode = SS7TCAPError::codeFromError(SS7TCAP::ANSITCAP,params.getIntValue(s_tcapAbortInfo));
2571 	    if (pCode) {
2572 		db.append(ASNLib::encodeInteger(pCode,false));
2573 		db.insert(ASNLib::buildLength(db));
2574 	    }
2575 	}
2576 	else if (*pAbortCause == "userAbortP" || *pAbortCause == "userAbortC") {
2577 	    NamedString* info = params.getParam(s_tcapAbortInfo);
2578 	    if (!TelEngine::null(info))
2579 		db.unHexify(info->c_str(),info->length(),' ');
2580 	    db.insert(ASNLib::buildLength(db));
2581 	    if (*pAbortCause == "userAbortP")
2582 		tag = SS7TCAPANSI::UserAbortPTag;
2583 	    else
2584 		tag = SS7TCAPANSI::UserAbortCTag;
2585 	}
2586 	if (db.length())
2587 	    db.insert(DataBlock(&tag,1));
2588     }
2589     if (db.length()) {
2590 	data.insert(db);
2591 	params.clearParam(s_tcapAbortCause);
2592 	params.clearParam(s_tcapAbortInfo);
2593     }
2594 #ifdef DEBUG
2595      if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
2596 	 dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionANSI::encodePAbort() - encoded Abort info",tr,params,data);
2597 #endif
2598 }
2599 
requestContent(NamedList & params,DataBlock & data)2600 void SS7TCAPTransactionANSI::requestContent(NamedList& params, DataBlock& data)
2601 {
2602 #ifdef DEBUG
2603     if (s_extendedDbg)
2604 	DDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::requestContent() for transaction with id=%s [%p]",m_localID.c_str(),this);
2605 #endif
2606     if (m_type == SS7TCAP::TC_P_Abort || m_type == SS7TCAP::TC_U_Abort)
2607 	encodePAbort(this,params,data);
2608     else
2609 	requestComponents(params,data);
2610     encodeDialogPortion(params,data);
2611     transactionData(params);
2612 }
2613 
updateToEnd()2614 void SS7TCAPTransactionANSI::updateToEnd()
2615 {
2616     if (transactionType() == SS7TCAP::TC_QueryWithoutPerm || transactionType() == SS7TCAP::TC_ConversationWithoutPerm)
2617 	setTransactionType(SS7TCAP::TC_U_Abort);
2618     else
2619 	setTransactionType(SS7TCAP::TC_Response);
2620 }
2621 
decodeComponents(NamedList & params,DataBlock & data)2622 SS7TCAPError SS7TCAPTransactionANSI::decodeComponents(NamedList& params, DataBlock& data)
2623 {
2624     XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::decodeComponents() [%p] - data length=%u",this,data.length());
2625 
2626     SS7TCAPError error(SS7TCAP::ANSITCAP);
2627     if (!data.length()) {
2628 	params.setParam(s_tcapCompCount,"0");
2629 	return error;
2630     }
2631 
2632     u_int8_t tag = data[0];
2633     if (tag != SS7TCAPANSI::ComponentPortionTag) { // 0xe8
2634 	error.setError(SS7TCAPError::General_IncorrectComponentPortion);
2635 	return error;
2636     }
2637     data.cut(-1);
2638 
2639     // decode length of component portion
2640     int len = ASNLib::decodeLength(data);
2641     bool checkEoC = (len == ASNLib::IndefiniteForm);
2642     if (!checkEoC && (len < 0 || len != (int)data.length())) { // the length of the remaining data should be the same as the decoded length()
2643 	error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2644 	return error;
2645     }
2646 
2647     unsigned int compCount = 0;
2648     while (data.length()) {
2649 	if (checkEoC && ASNLib::matchEOC(data) > 0)
2650 	    break;
2651 	compCount++;
2652 	// decode component type
2653 	u_int8_t compType = data[0];
2654 	data.cut(-1);
2655 
2656 	// verify component length
2657 	len = ASNLib::decodeLength(data);
2658 	if (len < 0 || len > (int)data.length()) {
2659 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2660 	    break;
2661 	}
2662 
2663 	// decode component IDs, start with ComponentsIDs identifier
2664 	tag = data[0];
2665 	if (tag != SS7TCAPANSI::ComponentsIDsTag) {// 0xcf
2666 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2667 	    break;
2668 	}
2669 	data.cut(-1);
2670 
2671 	// obtain component ID(s)
2672 	u_int16_t compIDs;
2673 	len = ASNLib::decodeUINT16(data,&compIDs,false);
2674 	if (len < 0) {
2675 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2676 	    break;
2677 	}
2678 
2679 	String compParam;
2680 	compPrefix(compParam,compCount,false);
2681 	// comp IDs shall be decoded according to component type
2682 	switch (compType) {
2683 	    case InvokeLast:
2684 	    case InvokeNotLast:
2685 		if (len == 1)
2686 		    params.setParam(compParam + "." + s_tcapRemoteCID,String(compIDs));
2687 		else if (len == 2) {
2688 		    params.setParam(compParam + "." + s_tcapRemoteCID,String(compIDs >> 8));
2689 		    params.setParam(compParam + "." + s_tcapLocalCID,String((u_int8_t)compIDs));
2690 		}
2691 		else {
2692 		    params.setParam(compParam + "." + s_tcapRemoteCID,"");
2693 		    params.setParam(compParam + "." + s_tcapLocalCID,"");
2694 		}
2695 		break;
2696 	    case ReturnResultLast:
2697 	    case ReturnError:
2698 	    case Reject:
2699 	    case ReturnResultNotLast:
2700 		if (len != 1)
2701 		    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2702 		else
2703 		    params.setParam(compParam + "." + s_tcapLocalCID,String(compIDs));
2704 		break;
2705 	    default:
2706 		error.setError(SS7TCAPError::General_UnrecognizedComponentType);
2707 		break;
2708 	}
2709 	const PrimitiveMapping* map = mapCompPrimitivesANSI(-1,compType);
2710 	if (!map) {
2711 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2712 	    break;
2713 	}
2714 	params.setParam(compParam + "." + s_tcapCompType,lookup(map->primitive,SS7TCAP::s_compPrimitives,"Unknown"));
2715 
2716 	if (error.error() != SS7TCAPError::NoError)
2717 	    break;
2718 
2719 	// decode Operation Code
2720 	tag = data[0];
2721 	if (tag == SS7TCAPANSI::OperationNationalTag || tag == SS7TCAPANSI::OperationPrivateTag) {
2722 	    data.cut(-1);
2723 
2724 	    int opCode = 0;
2725 	    len = ASNLib::decodeINT32(data,&opCode,false);
2726 	    if (tag == SS7TCAPANSI::OperationNationalTag) {
2727 		if (len != 2) {
2728 		    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2729 		    break;
2730 		}
2731 		params.setParam(compParam + "." + s_tcapOpCodeType,"national");
2732 	    }
2733 	    if (tag == SS7TCAPANSI::OperationPrivateTag)
2734 		params.setParam(compParam + "." + s_tcapOpCodeType,"private");
2735 	    params.setParam(compParam + "." + s_tcapOpCode,String(opCode));
2736 	}
2737 
2738 	// decode  Error Code
2739 	tag = data[0];
2740 	if (tag == SS7TCAPANSI::ErrorNationalTag || tag == SS7TCAPANSI::ErrorPrivateTag) { // 0xd3, 0xd4
2741 	    data.cut(-1);
2742 
2743 	    int errCode = 0;
2744 	    len = ASNLib::decodeINT32(data,&errCode,false);
2745 	    if (len < 0 || (tag == SS7TCAPANSI::ErrorNationalTag && len != 1)) {
2746 		error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2747 		break;
2748 	    }
2749 	    if (tag == SS7TCAPANSI::ErrorNationalTag)
2750 		params.setParam(compParam + "." + s_tcapErrCodeType,"national");
2751 	    else
2752 		params.setParam(compParam + "." + s_tcapErrCodeType,"private");
2753 	    params.setParam(compParam + "." + s_tcapErrCode,String(errCode));
2754 	}
2755 
2756 	// decode Problem
2757 	tag = data[0];
2758 	if (tag == SS7TCAPANSI::ProblemCodeTag) { // 0xd5
2759 	    data.cut(-1);
2760 	    u_int16_t problemCode = 0;
2761 	    len = ASNLib::decodeUINT16(data,&problemCode,false);
2762 	    if (len != 2) {
2763 		error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2764 		break;
2765 	    }
2766 	    params.setParam(compParam + "." + s_tcapProblemCode,String(SS7TCAPError::errorFromCode(tcap()->tcapType(),problemCode)));
2767 	}
2768 	// decode Parameters (Set or Sequence) as payload
2769 	tag = data[0];
2770 	String dataHexified = "";
2771 	if (tag == SS7TCAPANSI::ParameterSetTag || tag == SS7TCAPANSI::ParameterSeqTag) { // 0xf2 0x30
2772 		data.cut(-1);
2773 		len = ASNLib::decodeLength(data);
2774 		if (len < 0 || len > (int)data.length()) {
2775 		    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
2776 		    break;
2777 		}
2778 		DataBlock d((void*)data.data(0,len),len);
2779 		data.cut(-len);
2780 		d.insert(ASNLib::buildLength(d));
2781 		d.insert(DataBlock(&tag,1));
2782 		dataHexified.hexify(d.data(),d.length(),' ');
2783 	    }
2784 	params.setParam(compParam,dataHexified);
2785     }
2786 
2787     params.setParam(s_tcapCompCount,String(compCount));
2788 #ifdef DEBUG
2789     if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
2790 	dumpData(DebugAll,tcap(),"Finished decoding message",this,params,data);
2791 #endif
2792     return error;
2793 }
2794 
encodeComponents(NamedList & params,DataBlock & data)2795 void SS7TCAPTransactionANSI::encodeComponents(NamedList& params, DataBlock& data)
2796 {
2797     XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::encodeComponents() for transaction with localID=%s [%p]",m_localID.c_str(),this);
2798 
2799     int componentCount = params.getIntValue(s_tcapCompCount,0);
2800     DataBlock compData;
2801     if (componentCount) {
2802 	int index = componentCount + 1;
2803 
2804 	while (--index) {
2805 	    DataBlock codedComp;
2806 	    // encode parameters
2807 	    String compParam;
2808 	    compPrefix(compParam,index,false);
2809 	    // Component Type
2810 	    NamedString* value = params.getParam(compParam + "." + s_tcapCompType);
2811 	    if (TelEngine::null(value))
2812 		continue;
2813 	    int compPrimitive = lookup(*value,SS7TCAP::s_compPrimitives);
2814 	    const PrimitiveMapping* map = mapCompPrimitivesANSI(compPrimitive,-1);
2815 	    if (!map)
2816 		continue;
2817 	    int compType = map->mappedTo;
2818 	    String payloadHex = params.getValue(compParam,"");
2819 	    if (!payloadHex.null()) {
2820 		DataBlock payload;
2821 		payload.unHexify(payloadHex.c_str(),payloadHex.length(),' ');
2822 		//payload.insert(ASNLib::buildLength(payload));
2823 		codedComp.insert(payload);
2824 	    }
2825 
2826 	    // encode Problem only if Reject
2827 	    if (compType == Reject) {
2828 		value = params.getParam(compParam + "." + s_tcapProblemCode);
2829 		if (!TelEngine::null(value)) {
2830 		    u_int16_t code = SS7TCAPError::codeFromError(tcap()->tcapType(),value->toInteger());
2831 		    DataBlock db = ASNLib::encodeInteger(code,false);
2832 		    // should check that encoded length is 2
2833 		    if (db.length() < 2) {
2834 			code = 0;
2835 			db.insert(DataBlock(&code,1));
2836 		    }
2837 		    db.insert(ASNLib::buildLength(db));
2838 		    int tag = SS7TCAPANSI::ProblemCodeTag;
2839 		    db.insert(DataBlock(&tag,1));
2840 		    codedComp.insert(db);
2841 		}
2842 	    }
2843 
2844 	    // encode  Error Code only if ReturnError
2845 	    if (compType == ReturnError) {
2846 		value = params.getParam(compParam + "." + s_tcapErrCodeType);
2847 		if (!TelEngine::null(value)) {
2848 		    int errCode = params.getIntValue(compParam + "." + s_tcapErrCode,0);
2849 		    DataBlock db = ASNLib::encodeInteger(errCode,false);
2850 		    db.insert(ASNLib::buildLength(db));
2851 
2852 		    int tag = 0;
2853 		    if (*value == "national")
2854 			tag = SS7TCAPANSI::ErrorNationalTag;
2855 		    else if (*value == "private")
2856 			tag = SS7TCAPANSI::ErrorPrivateTag;
2857 		    db.insert(DataBlock(&tag,1));
2858 		    codedComp.insert(db);
2859 		}
2860 	    }
2861 
2862 	    // encode Operation Code only if Invoke
2863 	    if (compType == InvokeLast ||
2864 		compType == InvokeNotLast) {
2865 		value = params.getParam(compParam + "." + s_tcapOpCodeType);
2866 		if (!TelEngine::null(value)) {
2867 		    int opCode = params.getIntValue(compParam + "." + s_tcapOpCode,0);
2868 		    DataBlock db = ASNLib::encodeInteger(opCode,false);
2869 		    int tag = 0;
2870 		    if (*value == "national") {
2871 			tag = SS7TCAPANSI::OperationNationalTag;
2872 			if (db.length() < 2) {
2873 			    opCode = 0;
2874 			    db.insert(DataBlock(&opCode,1));
2875 			}
2876 		    }
2877 		    else if (*value == "private")
2878 			tag = SS7TCAPANSI::OperationPrivateTag;
2879 		    db.insert(ASNLib::buildLength(db));
2880 		    db.insert(DataBlock(&tag,1));
2881 		    codedComp.insert(db);
2882 		}
2883 	    }
2884 	    NamedString* invID = params.getParam(compParam + "." + s_tcapLocalCID);
2885 	    NamedString* corrID = params.getParam(compParam + "." + s_tcapRemoteCID);
2886 	    DataBlock db;
2887 	    u_int8_t val = 0;
2888 	    switch (compType) {
2889 		case InvokeLast:
2890 		case InvokeNotLast:
2891 		    if (!TelEngine::null(invID)) {
2892 			val = invID->toInteger();
2893 			db.append(&val,sizeof(u_int8_t));
2894 			if (!TelEngine::null(corrID)) {
2895 			    val = corrID->toInteger();
2896 			    db.append(&val,sizeof(u_int8_t));
2897 			}
2898 		    }
2899 		    else {
2900 			if (!TelEngine::null(corrID)) {
2901 			    val = corrID->toInteger();
2902 			    db.append(&val,sizeof(u_int8_t));
2903 			}
2904 		    }
2905 		    break;
2906 		case ReturnResultLast:
2907 		case ReturnError:
2908 		case Reject:
2909 		case ReturnResultNotLast:
2910 		    val = corrID->toInteger();
2911 		    db.append(&val,sizeof(u_int8_t));
2912 		    break;
2913 		default:
2914 		    break;
2915 	    }
2916 
2917 	    db.insert(ASNLib::buildLength(db));
2918 	    int tag = SS7TCAPANSI::ComponentsIDsTag;
2919 	    db.insert(DataBlock(&tag,1));
2920 	    codedComp.insert(db);
2921 	    codedComp.insert(ASNLib::buildLength(codedComp));
2922 	    codedComp.insert(DataBlock(&compType,1));
2923 
2924 	    params.clearParam(compParam,'.'); // clear all params for this component
2925 	    compData.insert(codedComp);
2926 	}
2927     }
2928 
2929     compData.insert(ASNLib::buildLength(compData));
2930     int tag = SS7TCAPANSI::ComponentPortionTag;
2931     compData.insert(DataBlock(&tag,1));
2932 
2933     data.insert(compData);
2934     params.clearParam(s_tcapCompPrefix,'.');
2935 }
2936 
handleDialogPortion(NamedList & params,bool byUser)2937 SS7TCAPError SS7TCAPTransactionANSI::handleDialogPortion(NamedList& params, bool byUser)
2938 {
2939     XDebug(tcap(),DebugAll,"SS7TCAPTransactionANSI::handleDialogPortion() [%p]",this);
2940 
2941     SS7TCAPError err(SS7TCAP::ANSITCAP);
2942 
2943     NamedList dialog("");
2944     Lock l(this);
2945     switch (m_type) {
2946 	case SS7TCAP::TC_Begin:
2947 	case SS7TCAP::TC_QueryWithPerm:
2948 	case SS7TCAP::TC_QueryWithoutPerm:
2949 	case SS7TCAP::TC_Unidirectional:
2950 	    if (!byUser) {
2951 		int protoVersion = params.getIntValue(s_tcapProtoVers);
2952 		if (protoVersion) { // there is a Dialog portion
2953 		    if ((protoVersion & s_tcapProtoVersion ) != s_tcapProtoVersion)
2954 			params.setParam(s_tcapProtoVers,String(s_tcapProtoVersion));
2955 		}
2956 	    }
2957 	    else {
2958 		dialog.copyParams(params,s_tcapDialogPrefix,'.');
2959 		if (dialog.count())
2960 		    params.setParam(s_tcapProtoVers,String(s_tcapProtoVersion));
2961 	    }
2962 	    return err;
2963 	case SS7TCAP::TC_End:
2964 	case SS7TCAP::TC_Response:
2965 	    dialog.copyParams(params,s_tcapDialogPrefix,'.');
2966 	    if (dialog.count() && m_prevType != SS7TCAP::TC_Begin && m_prevType != SS7TCAP::TC_QueryWithPerm) {
2967 		err.setError(SS7TCAPError::Dialog_InconsistentDialoguePortion);
2968 		return err;
2969 	    }
2970 	    break;
2971 	case SS7TCAP::TC_Continue:
2972 	case SS7TCAP::TC_ConversationWithPerm:
2973 	case SS7TCAP::TC_ConversationWithoutPerm:
2974 	    dialog.copyParams(params,s_tcapDialogPrefix,'.');
2975 	    if (dialog.count() && m_prevType != SS7TCAP::TC_Begin && m_prevType != SS7TCAP::TC_QueryWithPerm
2976 		    && m_prevType != SS7TCAP::TC_QueryWithoutPerm) {
2977 		err.setError(SS7TCAPError::Dialog_InconsistentDialoguePortion);
2978 		return err;
2979 	    }
2980 	    break;
2981 	case SS7TCAP::TC_Notice:
2982 	case SS7TCAP::TC_P_Abort:
2983 	    break;
2984 	case SS7TCAP::TC_U_Abort:
2985 	    break;
2986 	default:
2987 	    break;
2988     }
2989 
2990     return err;
2991 }
2992 
updateState(bool byUser)2993 void SS7TCAPTransactionANSI::updateState(bool byUser)
2994 {
2995     switch (m_type) {
2996 	case SS7TCAP::TC_Begin:
2997 	case SS7TCAP::TC_QueryWithPerm:
2998 	case SS7TCAP::TC_QueryWithoutPerm:
2999 	case SS7TCAP::TC_Continue:
3000 	case SS7TCAP::TC_ConversationWithPerm:
3001 	case SS7TCAP::TC_ConversationWithoutPerm:
3002 	    (byUser ? setState(SS7TCAPTransaction::PackageSent) : setState(SS7TCAPTransaction::PackageReceived));
3003 	    break;
3004 	case SS7TCAP::TC_End:
3005 	case SS7TCAP::TC_U_Abort:
3006 	case SS7TCAP::TC_P_Abort:
3007 	case SS7TCAP::TC_Response:
3008 	case SS7TCAP::TC_Unidirectional:
3009 	    setState(Idle);
3010 	    break;
3011 	case SS7TCAP::TC_Notice:
3012 	case SS7TCAP::TC_Unknown:
3013 	default:
3014 	    break;
3015     }
3016 }
3017 
3018 /**
3019  * ITU-T SS7 TCAP implementation
3020  */
3021 
3022 static const int s_ituTCAPProto = 1;
3023 static const String s_tcapDialogueID = "tcap.dialogPDU.dialog-as-id";
3024 static const String s_tcapDialogueAppCtxt = "tcap.dialogPDU.application-context-name";
3025 static const String s_tcapDialoguePduType = "tcap.dialogPDU.dialog-pdu-type";
3026 static const String s_tcapDialogueAbrtSrc = "tcap.dialogPDU.abort-source";
3027 static const String s_tcapDialogueResult = "tcap.dialogPDU.result";
3028 static const String s_tcapDialogueDiag = "tcap.dialogPDU.result-source-diagnostic";
3029 static const String s_unstructDialogueOID = "0.0.17.773.1.2.1";
3030 static const String s_structDialogueOID = "0.0.17.773.1.1.1";
3031 
3032 static const PrimitiveMapping s_componentsITUMap[] = {
3033     {SS7TCAP::TC_Invoke,              SS7TCAPTransactionITU::Invoke},
3034     {SS7TCAP::TC_ResultLast,          SS7TCAPTransactionITU::ReturnResultLast},
3035     {SS7TCAP::TC_U_Error,             SS7TCAPTransactionITU::ReturnError},
3036     {SS7TCAP::TC_U_Reject,            SS7TCAPTransactionITU::Reject},
3037     {SS7TCAP::TC_R_Reject,            SS7TCAPTransactionITU::Reject},
3038     {SS7TCAP::TC_L_Reject,            SS7TCAPTransactionITU::Reject},
3039     {SS7TCAP::TC_InvokeNotLast,       SS7TCAPTransactionITU::Invoke},
3040     {SS7TCAP::TC_ResultNotLast,       SS7TCAPTransactionITU::ReturnResultNotLast},
3041     {SS7TCAP::TC_L_Cancel,            SS7TCAPTransactionITU::Local},
3042     {SS7TCAP::TC_U_Cancel,            SS7TCAPTransactionITU::Local},
3043     {SS7TCAP::TC_TimerReset,          SS7TCAPTransactionITU::Local},
3044     {SS7TCAP::TC_Unknown,             SS7TCAPTransactionITU::Unknown},
3045 };
3046 
3047 static const PrimitiveMapping s_transITUMap[] = {
3048     {SS7TCAP::TC_Unidirectional,              SS7TCAPTransactionITU::Unidirectional},
3049     {SS7TCAP::TC_Begin,                       SS7TCAPTransactionITU::Begin},
3050     {SS7TCAP::TC_QueryWithPerm,               SS7TCAPTransactionITU::Begin},
3051     {SS7TCAP::TC_QueryWithoutPerm,            SS7TCAPTransactionITU::Begin},
3052     {SS7TCAP::TC_Continue,                    SS7TCAPTransactionITU::Continue},
3053     {SS7TCAP::TC_ConversationWithPerm,        SS7TCAPTransactionITU::Continue},
3054     {SS7TCAP::TC_ConversationWithoutPerm,     SS7TCAPTransactionITU::Continue},
3055     {SS7TCAP::TC_End,                         SS7TCAPTransactionITU::End},
3056     {SS7TCAP::TC_Response,                    SS7TCAPTransactionITU::End},
3057     {SS7TCAP::TC_U_Abort,                     SS7TCAPTransactionITU::Abort},
3058     {SS7TCAP::TC_P_Abort,                     SS7TCAPTransactionITU::Abort},
3059     {SS7TCAP::TC_Notice,                      SS7TCAPTransactionITU::Unknown},
3060     {SS7TCAP::TC_Unknown,                     SS7TCAPTransactionITU::Unknown},
3061 };
3062 
mapCompPrimitivesITU(int primitive,int comp=-1)3063 static const PrimitiveMapping* mapCompPrimitivesITU(int primitive, int comp = -1)
3064 {
3065     const PrimitiveMapping* map = s_componentsITUMap;
3066     for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
3067 	if (primitive != -1) {
3068 	    if (map->primitive == primitive )
3069 		break;
3070 	}
3071 	else if (comp != -1)
3072 	    if (map->mappedTo == comp)
3073 		break;
3074     }
3075     return map;
3076 }
3077 
mapTransPrimitivesITU(int primitive,int trans=-1)3078 static const PrimitiveMapping* mapTransPrimitivesITU(int primitive, int trans = -1)
3079 {
3080     const PrimitiveMapping* map = s_transITUMap;
3081     for (; map->primitive != SS7TCAP::TC_Unknown; map++) {
3082 	if (primitive != -1) {
3083 	    if (map->primitive == primitive )
3084 		break;
3085 	}
3086 	else if (trans != -1)
3087 	    if (map->mappedTo == trans)
3088 		break;
3089     }
3090     return map;
3091 }
3092 
SS7TCAPITU(const NamedList & params)3093 SS7TCAPITU::SS7TCAPITU(const NamedList& params)
3094     : SignallingComponent(params.safe("SS7TCAPITU"),&params,"ss7-tcap-itu"),
3095       SS7TCAP(params)
3096 {
3097     String tmp;
3098     params.dump(tmp,"\r\n  ",'\'',true);
3099     DDebug(this,DebugAll,"SS7TCAPITU::SS7TCAPITU(%s)",tmp.c_str());
3100     setTCAPType(SS7TCAP::ITUTCAP);
3101 }
3102 
~SS7TCAPITU()3103 SS7TCAPITU::~SS7TCAPITU()
3104 {
3105     DDebug(this,DebugAll,"SS7TCAPITU::~SS7TCAPITU() [%p] destroyed with %d transactions, refCount=%d",
3106 	this,m_transactions.count(),refcount());
3107 }
3108 
buildTransaction(SS7TCAP::TCAPUserTransActions type,const String & transactID,NamedList & params,bool initLocal)3109 SS7TCAPTransaction* SS7TCAPITU::buildTransaction(SS7TCAP::TCAPUserTransActions type, const String& transactID, NamedList& params,
3110 	bool initLocal)
3111 {
3112     return new SS7TCAPTransactionITU(this,type,transactID,params,m_trTimeout,initLocal);
3113 }
3114 
decodeTransactionPart(NamedList & params,DataBlock & data)3115 SS7TCAPError SS7TCAPITU::decodeTransactionPart(NamedList& params, DataBlock& data)
3116 {
3117     SS7TCAPError error(SS7TCAP::ITUTCAP);
3118     if (data.length() < 2)
3119 	return error;
3120 
3121     // decode message type
3122     u_int8_t msgType = data[0];
3123     data.cut(-1);
3124 
3125     const PrimitiveMapping* map = mapTransPrimitivesITU(-1,msgType);
3126     if (map) {
3127 	String type = lookup(map->primitive,SS7TCAP::s_transPrimitives,"Unknown");
3128 	params.setParam(s_tcapRequest,type);
3129     }
3130 
3131     // decode message length
3132     int len = ASNLib::decodeLength(data);
3133     if (len != (int)data.length()) {
3134 	error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
3135 	return error;
3136     }
3137 
3138     // decode transaction ids
3139     bool decodeOTID = false;
3140     bool decodeDTID = false;
3141     switch (map->mappedTo) {
3142 	case SS7TCAPTransactionITU::Unidirectional:
3143 	    return error;
3144 	case SS7TCAPTransactionITU::Begin:
3145 	    decodeOTID = true;
3146 	    break;
3147 	case SS7TCAPTransactionITU::End:
3148 	case SS7TCAPTransactionITU::Abort:
3149 	    decodeDTID = true;
3150 	    break;
3151 	case SS7TCAPTransactionITU::Continue:
3152 	    decodeOTID = true;
3153 	    decodeDTID = true;
3154 	    break;
3155 	default:
3156 	    error.setError(SS7TCAPError::Transact_UnrecognizedPackageType);
3157 	    return error;
3158     }
3159 
3160     u_int8_t tag = data[0];
3161     String str;
3162     if (decodeOTID) {
3163 	// check for originating ID
3164 	if (tag != OriginatingIDTag) {// 0x48
3165 	    error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
3166 	    return error;
3167 	}
3168 	data.cut(-1);
3169 
3170 	len = ASNLib::decodeLength(data);
3171 	if (len < 1 || len > 4 || len > (int)data.length()) {
3172 	    error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
3173 	    return error;
3174 	}
3175 	str.hexify(data.data(),len,' ');
3176 	data.cut(-len);
3177 	params.setParam(s_tcapRemoteTID,str);
3178     }
3179 
3180     tag = data[0];
3181     if (decodeDTID) {
3182 	// check for originating ID
3183 	if (tag != DestinationIDTag) {// 0x49
3184 	    error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
3185 	    return error;
3186 	}
3187 	data.cut(-1);
3188 
3189 	len = ASNLib::decodeLength(data);
3190 	if (len < 1 || len > 4 || len > (int)data.length()) {
3191 	    error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
3192 	    return error;
3193 	}
3194 	str.hexify(data.data(),len,' ');
3195 	data.cut(-len);
3196 	params.setParam(s_tcapLocalTID,str);
3197     }
3198 
3199 #ifdef DEBUG
3200     if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
3201 	dumpData(DebugAll,this,"SS7TCAPITU::decodeTransactionPart() finished",this,params,data);
3202 #endif
3203 
3204     error.setError(SS7TCAPError::NoError);
3205     return error;
3206 }
3207 
encodeTransactionPart(NamedList & params,DataBlock & data)3208 void SS7TCAPITU::encodeTransactionPart(NamedList& params, DataBlock& data)
3209 {
3210     String msg = params.getValue(s_tcapRequest);
3211     const PrimitiveMapping* map = mapTransPrimitivesITU(msg.toInteger(SS7TCAP::s_transPrimitives),-1);
3212     if (!map)
3213 	return;
3214 
3215     u_int8_t msgType = map->mappedTo;
3216     NamedString* val = 0;
3217     u_int8_t tag;
3218     bool encDTID = false;
3219     bool encOTID = false;
3220 
3221     switch (msgType) {
3222 	case SS7TCAPTransactionITU::Unidirectional:
3223 	    break;
3224 	case SS7TCAPTransactionITU::Begin:
3225 	    encOTID = true;
3226 	    break;
3227 	case SS7TCAPTransactionITU::End:
3228 	case SS7TCAPTransactionITU::Abort:
3229 	    encDTID = true;
3230 	    break;
3231 	case SS7TCAPTransactionITU::Continue:
3232 	    encOTID = true;
3233 	    encDTID = true;
3234 	    break;
3235 	default:
3236 	    break;
3237     }
3238 
3239     if (encDTID) {
3240 	val = params.getParam(s_tcapRemoteTID);
3241 	if (!TelEngine::null(val)) {
3242 	    // destination TID
3243 	    DataBlock db;
3244 	    db.unHexify(val->c_str(),val->length(),' ');
3245 	    db.insert(ASNLib::buildLength(db));
3246 	    tag = DestinationIDTag;
3247 	    db.insert(DataBlock(&tag,1));
3248 	    data.insert(db);
3249 	}
3250     }
3251     if (encOTID) {
3252 	val = params.getParam(s_tcapLocalTID);
3253 	if (!TelEngine::null(val)) {
3254 	    // origination id
3255 	    DataBlock db;
3256 	    db.unHexify(val->c_str(),val->length(),' ');
3257 	    db.insert(ASNLib::buildLength(db));
3258 	    tag = OriginatingIDTag;
3259 	    db.insert(DataBlock(&tag,1));
3260 	    data.insert(db);
3261 	}
3262     }
3263 
3264     data.insert(ASNLib::buildLength(data));
3265     data.insert(DataBlock(&msgType,1));
3266 }
3267 
3268 /**
3269  * ITU-T SS7 TCAP transaction implementation
3270  */
3271 const TokenDict SS7TCAPTransactionITU::s_dialogPDUs[] = {
3272     {"AARQ",    SS7TCAPTransactionITU::AARQDialogTag},
3273     {"AARE",    SS7TCAPTransactionITU::AAREDialogTag},
3274     {"ABRT",    SS7TCAPTransactionITU::ABRTDialogTag},
3275     {0,0},
3276 };
3277 
3278 const TokenDict SS7TCAPTransactionITU::s_resultPDUValues[] = {
3279     {"accepted",                                       SS7TCAPTransactionITU::ResultAccepted},
3280     {"reject-permanent",                               SS7TCAPTransactionITU::ResultRejected},
3281     {"user-null",                                      SS7TCAPTransactionITU::DiagnosticUserNull},
3282     {"user-no-reason-given",                           SS7TCAPTransactionITU::DiagnosticUserNoReason},
3283     {"user-application-context-name-not-supported",    SS7TCAPTransactionITU::DiagnosticUserAppCtxtNotSupported},
3284     {"provider-null",                                  SS7TCAPTransactionITU::DiagnosticProviderNull},
3285     {"provider-no-reason-given",                       SS7TCAPTransactionITU::DiagnosticProviderNoReason},
3286     {"provider-no-common-dialogue-portion",            SS7TCAPTransactionITU::DiagnosticProviderNoCommonDialog},
3287     {"dialogue-service-user",                          SS7TCAPTransactionITU::AbortSourceUser},
3288     {"dialogue-service-provider",                      SS7TCAPTransactionITU::AbortSourceProvider},
3289     {0,0},
3290 };
3291 
SS7TCAPTransactionITU(SS7TCAP * tcap,SS7TCAP::TCAPUserTransActions type,const String & transactID,NamedList & params,u_int64_t timeout,bool initLocal)3292 SS7TCAPTransactionITU::SS7TCAPTransactionITU(SS7TCAP* tcap, SS7TCAP::TCAPUserTransActions type,
3293 	const String& transactID, NamedList& params, u_int64_t timeout, bool initLocal)
3294     : SS7TCAPTransaction(tcap,type,transactID,params,timeout,initLocal)
3295 {
3296     DDebug(m_tcap,DebugAll,"SS7TCAPTransactionITU(tcap = '%s' [%p], transactID = %s, timeout=" FMT64 " ) created [%p]",
3297 	    m_tcap->toString().c_str(),tcap,transactID.c_str(),timeout,this);
3298 }
3299 
3300 
~SS7TCAPTransactionITU()3301 SS7TCAPTransactionITU::~SS7TCAPTransactionITU()
3302 {
3303     DDebug(tcap(),DebugAll,"Transaction with ID=%s of user=%s destroyed [%p]",
3304 	   m_localID.c_str(),m_userName.c_str(),this);
3305 }
3306 
handleData(NamedList & params,DataBlock & data)3307 SS7TCAPError SS7TCAPTransactionITU::handleData(NamedList& params, DataBlock& data)
3308 {
3309     DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::handleData() transactionID=%s data length=%u [%p]",m_localID.c_str(),
3310 	   data.length(),this);
3311     Lock lock(this);
3312     // in case of Abort message, check Cause Information
3313     SS7TCAPError error(SS7TCAP::ITUTCAP);
3314 
3315     if (m_type == SS7TCAP::TC_P_Abort) {
3316 	error = decodePAbort(this,params,data);
3317 	if (error.error() != SS7TCAPError::NoError)
3318 	    return error;
3319     }
3320     else if (testForDialog(data)) {
3321 	// decode DialogPortion
3322 	error = decodeDialogPortion(params,data);
3323 	if (error.error() != SS7TCAPError::NoError)
3324 	    return error;
3325     }
3326     error = handleDialogPortion(params,false);
3327     if (error.error() != SS7TCAPError::NoError)
3328 	return error;
3329 
3330     // decodeComponents
3331     error = decodeComponents(params,data);
3332      if (error.error() != SS7TCAPError::NoError)
3333 	buildComponentError(error,params,data);
3334 
3335     error = handleComponents(params,false);
3336     return error;
3337 }
3338 
testForDialog(DataBlock & data)3339 bool SS7TCAPTransactionITU::testForDialog(DataBlock& data)
3340 {
3341     return (data.length() && data[0] == SS7TCAPITU::DialogPortionTag);
3342 }
3343 
updateState(bool byUser)3344 void SS7TCAPTransactionITU::updateState(bool byUser)
3345 {
3346     switch (m_type) {
3347 	case SS7TCAP::TC_Begin:
3348 	case SS7TCAP::TC_QueryWithPerm:
3349 	case SS7TCAP::TC_QueryWithoutPerm:
3350 	    break;
3351 	case SS7TCAP::TC_Continue:
3352 	case SS7TCAP::TC_ConversationWithPerm:
3353 	case SS7TCAP::TC_ConversationWithoutPerm:
3354 	    setState(Active);
3355 	    break;
3356 	case SS7TCAP::TC_End:
3357 	case SS7TCAP::TC_U_Abort:
3358 	case SS7TCAP::TC_P_Abort:
3359 	case SS7TCAP::TC_Response:
3360 	case SS7TCAP::TC_Unidirectional:
3361 	    setState(Idle);
3362 	    break;
3363 	case SS7TCAP::TC_Notice:
3364 	case SS7TCAP::TC_Unknown:
3365 	default:
3366 	    break;
3367     }
3368 }
3369 
update(SS7TCAP::TCAPUserTransActions type,NamedList & params,bool updateByUser)3370 SS7TCAPError SS7TCAPTransactionITU::update(SS7TCAP::TCAPUserTransActions type, NamedList& params, bool updateByUser)
3371 {
3372    DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::update() [%p], localID=%s - update to type=%s by %s",this,m_localID.c_str(),
3373 	lookup(type,SS7TCAP::s_transPrimitives,"Unknown"), (updateByUser ? "user" : "remote"));
3374 #ifdef DEBUG
3375     if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
3376 	dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::update() with",this,params);
3377 #endif
3378 
3379     Lock l(this);
3380     SS7TCAPError error(SS7TCAP::ITUTCAP);
3381     switch (type) {
3382 	case SS7TCAP::TC_Begin:
3383 	case SS7TCAP::TC_QueryWithPerm:
3384 	case SS7TCAP::TC_QueryWithoutPerm:
3385 	case SS7TCAP::TC_Unidirectional:
3386 	    Debug(tcap(),DebugInfo,"SS7TCAPTransactionITU::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
3387 		    this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
3388 		    lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
3389 	    params.setParam(s_tcapRequestError,"invalid_update");
3390 	    params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
3391 	    error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
3392 	    return error;
3393 
3394 	case SS7TCAP::TC_End:
3395 	case SS7TCAP::TC_Response:
3396 	    m_type = type;
3397 	    if (m_state == PackageReceived) {
3398 		m_basicEnd = params.getBoolValue(s_tcapBasicTerm,m_basicEnd);
3399 		if (!m_basicEnd)
3400 		    // prearranged end, no need to transmit to remote end
3401 		    m_transmit = NoTransmit;
3402 		else
3403 		    m_transmit = PendingTransmit;
3404 	    }
3405 	    else if (m_state == PackageSent) {
3406 		if(!updateByUser)
3407 		    m_transmit = PendingTransmit;
3408 		else
3409 		    m_transmit = NoTransmit;
3410 	    }
3411 	    else if (m_state == Active) {
3412 		if(!updateByUser)
3413 		    m_transmit = PendingTransmit;
3414 		else {
3415 		    m_basicEnd = params.getBoolValue(s_tcapBasicTerm,m_basicEnd);
3416 		    if (!m_basicEnd)
3417 			// prearranged end, no need to transmit to remote end
3418 			m_transmit = NoTransmit;
3419 		    else
3420 			m_transmit = PendingTransmit;
3421 		}
3422 	    }
3423 	    break;
3424 	case SS7TCAP::TC_Continue:
3425 	case SS7TCAP::TC_ConversationWithPerm:
3426 	case SS7TCAP::TC_ConversationWithoutPerm:
3427 	    if (m_state == PackageSent)
3428 		m_remoteID = params.getValue(s_tcapRemoteTID);
3429 	    m_type = type;
3430 	    m_transmit = PendingTransmit;
3431 	    break;
3432 	case SS7TCAP::TC_Notice:
3433 	    m_type = type;
3434 	    if (updateByUser) {
3435 		Debug(tcap(),DebugInfo,"SS7TCAPTransactionITU::update() [%p], localID=%s - invalid update: trying to update from type=%s to type=%s",
3436 		    this,m_localID.c_str(),lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"),
3437 		    lookup(type,SS7TCAP::s_transPrimitives,"Unknown"));
3438 		params.setParam(s_tcapRequestError,"invalid_update");
3439 		params.setParam("tcap.request.error.currentState",lookup(m_type,SS7TCAP::s_transPrimitives,"Unknown"));
3440 		error.setError(SS7TCAPError::Transact_IncorrectTransactionPortion);
3441 		return error;
3442 	    }
3443 	    break;
3444 	case SS7TCAP::TC_P_Abort:
3445 	case SS7TCAP::TC_U_Abort:
3446 	    m_type = type;
3447 	    if (m_state == PackageReceived)
3448 		m_transmit = PendingTransmit;
3449 	    else if (m_state == PackageSent) {
3450 		if (!updateByUser) {
3451 		    if (String("pAbort") == params.getValue(s_tcapAbortCause))
3452 			m_type = SS7TCAP::TC_P_Abort;
3453 		    else
3454 			m_type = SS7TCAP::TC_P_Abort;
3455 		    m_transmit = PendingTransmit;
3456 		}
3457 		else
3458 		    m_transmit = NoTransmit;
3459 	    }
3460 	    else if (m_state == Active) {
3461 		if (!updateByUser) {
3462 		    if (String("pAbort") == params.getValue(s_tcapAbortCause))
3463 			m_type = SS7TCAP::TC_P_Abort;
3464 		    else
3465 			m_type = SS7TCAP::TC_P_Abort;
3466 		}
3467 		m_transmit = PendingTransmit;
3468 	    }
3469 	    break;
3470 	default:
3471 	    break;
3472     }
3473 
3474     populateSCCPAddress(m_localSCCPAddr,m_remoteSCCPAddr,params,updateByUser);
3475     m_basicEnd = params.getBoolValue(s_tcapBasicTerm,true);
3476     m_endNow = params.getBoolValue(s_tcapEndNow,m_endNow);
3477 
3478     if (m_timeout.started()) {
3479 	m_timeout.stop();
3480 	XDebug(tcap(),DebugInfo,"SS7TCAPTransactionITU::update() [%p], localID=%s - timeout timer has been stopped",this,m_localID.c_str());
3481     }
3482     return error;
3483 }
3484 
handleDialogPortion(NamedList & params,bool byUser)3485 SS7TCAPError SS7TCAPTransactionITU::handleDialogPortion(NamedList& params, bool byUser)
3486 {
3487     DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::handleDialogPortion() [%p]",this);
3488 
3489     SS7TCAPError error(SS7TCAP::ITUTCAP);
3490 
3491     NamedString* diagPDU = params.getParam(s_tcapDialoguePduType);
3492     NamedString* appCtxt = params.getParam(s_tcapDialogueAppCtxt);
3493     int protoVers = params.getIntValue(s_tcapProtoVers,s_ituTCAPProto,0);
3494 
3495     Lock l(this);
3496     switch (m_type) {
3497 	case SS7TCAP::TC_Unidirectional:
3498 	    if (byUser) {
3499 		// check for context name, if not present no AUDT
3500 		if (TelEngine::null(appCtxt))
3501 		    return error;
3502 		m_appCtxt = *appCtxt;
3503 		// build AUDT.
3504 		params.setParam(s_tcapDialogueID,s_unstructDialogueOID.toString());
3505 		if (protoVers)
3506 		    params.setParam(s_tcapProtoVers,String(protoVers));
3507 		params.setParam(s_tcapDialoguePduType,lookup(AARQDialogTag,s_dialogPDUs));
3508 	    }
3509 	    else {
3510 		// check to be AUDT
3511 		if (TelEngine::null(diagPDU) || !protoVers)
3512 		    return error;
3513 		if (diagPDU->toInteger(s_dialogPDUs) != AARQDialogTag || s_ituTCAPProto != protoVers)
3514 		    error.setError(SS7TCAPError::Dialog_Abnormal);
3515 	    }
3516 	    break;
3517 	case SS7TCAP::TC_Begin:
3518 	case SS7TCAP::TC_QueryWithPerm:
3519 	case SS7TCAP::TC_QueryWithoutPerm:
3520 	    if (byUser) {
3521 		if (TelEngine::null(appCtxt))
3522 		    break;
3523 		m_appCtxt = *appCtxt;
3524 		// build AARQ
3525 		params.setParam(s_tcapDialogueID,s_structDialogueOID);
3526 		if (protoVers)
3527 		    params.setParam(s_tcapProtoVers,String(protoVers));
3528 		params.setParam(s_tcapDialoguePduType,lookup(AARQDialogTag,s_dialogPDUs));
3529 	    }
3530 	    else {
3531 		if (TelEngine::null(diagPDU) || !protoVers)
3532 		    break;
3533 		// check to be AARQ and that it has context
3534 		if (diagPDU->toInteger(s_dialogPDUs) != AARQDialogTag || TelEngine::null(appCtxt)) {
3535 		    error.setError(SS7TCAPError::Dialog_Abnormal);
3536 		    break;
3537 		}
3538 		// check proto version, if not 1, build AARE - no common dialogue version, return err to build abort
3539 		if (s_ituTCAPProto != protoVers) {
3540 		    params.clearParam(s_tcapDialogPrefix,'.');
3541 		    params.setParam(s_tcapDialogueID,s_structDialogueOID);
3542 		    params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
3543 		    params.setParam(s_tcapDialogueResult,lookup(ResultRejected,s_resultPDUValues));
3544 		    params.setParam(s_tcapDialogueDiag,lookup(DiagnosticProviderNoCommonDialog,s_resultPDUValues));
3545 		    error.setError(SS7TCAPError::Dialog_Abnormal);
3546 		    break;
3547 		}
3548 		m_appCtxt = *appCtxt;
3549 	    }
3550 	    break;
3551 	case SS7TCAP::TC_End:
3552 	case SS7TCAP::TC_Response:
3553 	    if (byUser) {
3554 		if (!basicEnd() || transactionState() != PackageReceived || m_appCtxt.null()) {
3555 		    params.clearParam(s_tcapDialogPrefix,'.');
3556 		    break;
3557 		}
3558 		if (TelEngine::null(appCtxt))
3559 		    params.setParam(s_tcapDialogueAppCtxt,m_appCtxt);
3560 		// build AARE with result=accepted, result-source-diagnostic=null / dialog-service-user(null)
3561 		params.setParam(s_tcapDialogueID,s_structDialogueOID);
3562 		if (protoVers)
3563 		    params.setParam(s_tcapProtoVers,String(protoVers));
3564 		params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
3565 		params.setParam(s_tcapDialogueResult,lookup(ResultAccepted,s_resultPDUValues));
3566 		if (!params.getParam(s_tcapDialogueDiag))
3567 		    params.addParam(s_tcapDialogueDiag,lookup(DiagnosticUserNoReason,s_resultPDUValues));
3568 	    }
3569 	    else {
3570 		// page 51 q.774
3571 		// dialog info ?
3572 		// => yes => AC MODE ? = no, discard components. TC-p-abort to TCU , terminate transaction
3573 		//			= yes, check correct AARE, incorrect => TC-P-Abort to user, send TC_END to user otherwise
3574 		// => no =? AC MODE ? = no, send TC_END to user (continue processing)
3575 		// 			= yes, TC-p-abort to TCU , terminate transaction
3576 		if (transactionState() != PackageSent && !TelEngine::null(diagPDU)) {
3577 		    error.setError(SS7TCAPError::Dialog_Abnormal);
3578 		    break;
3579 		}
3580 		if (!TelEngine::null(appCtxt)) {
3581 		    if (m_appCtxt.null())
3582 			error.setError(SS7TCAPError::Dialog_Abnormal);
3583 		    else {
3584 			if (TelEngine::null(diagPDU) || diagPDU->toInteger(s_dialogPDUs) != AAREDialogTag)
3585 			    error.setError(SS7TCAPError::Dialog_Abnormal);
3586 		    }
3587 		}
3588 		else {
3589 		    if (!m_appCtxt.null() && transactionState() != Active)
3590 			error.setError(SS7TCAPError::Dialog_Abnormal);
3591 		}
3592 	    }
3593 	    break;
3594 	case SS7TCAP::TC_Continue:
3595 	case SS7TCAP::TC_ConversationWithPerm:
3596 	case SS7TCAP::TC_ConversationWithoutPerm:
3597 	    if (byUser) {
3598 		if (transactionState() != PackageReceived || TelEngine::null(appCtxt)) {
3599 		    params.clearParam(s_tcapDialogPrefix,'.');
3600 		    break;
3601 		}
3602 		// build AARE
3603 		m_appCtxt = *appCtxt;
3604 		params.setParam(s_tcapDialogueID,s_structDialogueOID);
3605 		if (protoVers)
3606 		    params.setParam(s_tcapProtoVers,String(protoVers));
3607 		params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
3608 		params.setParam(s_tcapDialogueResult,lookup(ResultAccepted,s_resultPDUValues));
3609 		if (!params.getParam(s_tcapDialogueDiag))
3610 		    params.addParam(s_tcapDialogueDiag,lookup(DiagnosticUserNoReason,s_resultPDUValues));
3611 	    }
3612 	    else {
3613 		// dialog info?
3614 		// yes => AC MODE? => yes, Check AARE
3615 		//		   = > no, discard, build P Abort with ABRT apdu
3616 		// no => AC MODE? => no, send to user / continue processing
3617 		//		  => yes, build U_Abort with ABRT apdu
3618 		if (transactionState() == PackageReceived)
3619 		    break;
3620 		if (!TelEngine::null(appCtxt)) {
3621 		    if (m_appCtxt.null())
3622 			error.setError(SS7TCAPError::Dialog_Abnormal);
3623 		    else {
3624 			if (TelEngine::null(diagPDU) || diagPDU->toInteger(s_dialogPDUs) != AAREDialogTag)
3625 			    error.setError(SS7TCAPError::Dialog_Abnormal);
3626 		    }
3627 		}
3628 		else {
3629 		    if (!m_appCtxt.null() && transactionState() == PackageSent)
3630 			error.setError(SS7TCAPError::Dialog_Abnormal);
3631 		}
3632 	    }
3633 	    break;
3634 	case SS7TCAP::TC_Notice:
3635 	case SS7TCAP::TC_P_Abort:
3636 	    break;
3637 	case SS7TCAP::TC_U_Abort:
3638 	    if (byUser) {
3639 		if (m_appCtxt.null())
3640 		    break;
3641 		params.setParam(s_tcapDialogueID,s_structDialogueOID);
3642 		if (protoVers)
3643 		    params.setParam(s_tcapProtoVers,String(protoVers));
3644 		if (transactionState() == PackageReceived ) {
3645 		    NamedString* abrtReason = params.getParam(s_tcapDialogueDiag);
3646 		    if (!TelEngine::null(abrtReason) && (abrtReason->toInteger(s_resultPDUValues) == DiagnosticUserAppCtxtNotSupported ||
3647 			abrtReason->toInteger(s_resultPDUValues) == DiagnosticProviderNoCommonDialog)) {
3648 			// build AARE
3649 			if (TelEngine::null(appCtxt))
3650 			    params.setParam(s_tcapDialogueAppCtxt,m_appCtxt);
3651 			params.setParam(s_tcapDialoguePduType,lookup(AAREDialogTag,s_dialogPDUs));
3652 			params.setParam(s_tcapDialogueResult,lookup(ResultRejected,s_resultPDUValues));
3653 		    }
3654 		    else {
3655 			// build ABRT
3656 			params.setParam(s_tcapDialoguePduType,lookup(ABRTDialogTag,s_dialogPDUs));
3657 			params.setParam(s_tcapDialogueAbrtSrc,lookup(AbortSourceUser,s_resultPDUValues));
3658 		    }
3659 		}
3660 		else if (transactionState() == Active) {
3661 		    if (TelEngine::null(params.getParam(s_tcapDialogueAbrtSrc)))
3662 			params.setParam(s_tcapDialogueAbrtSrc,lookup(AbortSourceUser,s_resultPDUValues));
3663 		    params.setParam(s_tcapDialoguePduType,lookup(ABRTDialogTag,s_dialogPDUs));
3664 		}
3665 	    }
3666 	    else {
3667 		// state initsent/active
3668 		if (!TelEngine::null(m_appCtxt)) {
3669 		    NamedString* diagID = params.getParam(s_tcapDialogueID);
3670 		    NamedString* pdu = params.getParam(s_tcapDialoguePduType);
3671 		    if (!TelEngine::null(diagID) && !TelEngine::null(pdu)) {
3672 			if (s_structDialogueOID == *diagID && (pdu->toInteger(s_dialogPDUs) == AAREDialogTag
3673 			    || pdu->toInteger(s_dialogPDUs) == ABRTDialogTag)) {
3674 
3675 			    if (pdu->toInteger() == AAREDialogTag) {
3676 				NamedString* diag = params.getParam(s_tcapDialogueDiag);
3677 				if (transactionState() == PackageSent && !TelEngine::null(diag) &&
3678 				    diag->toInteger(s_resultPDUValues) != DiagnosticProviderNoCommonDialog) {
3679 				    params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_P_Abort,SS7TCAP::s_transPrimitives));
3680 				    params.setParam(s_tcapAbortCause,"pAbort");
3681 				    m_transmit = PendingTransmit;
3682 				}
3683 				else
3684 				    error.setError(SS7TCAPError::Dialog_Abnormal);
3685 			    }
3686 			    else {
3687 				NamedString* src = params.getParam(s_tcapDialogueAbrtSrc);
3688 				if (!TelEngine::null(src) && src->toInteger(s_resultPDUValues) != AbortSourceUser)
3689 				    error.setError(SS7TCAPError::Dialog_Abnormal);
3690 			    }
3691 			}
3692 			else
3693 			    error.setError(SS7TCAPError::Dialog_Abnormal);
3694 		    }
3695 		    else
3696 			error.setError(SS7TCAPError::Dialog_Abnormal);
3697 		}
3698 		else {
3699 		    if (!TelEngine::null(appCtxt))
3700 			error.setError(SS7TCAPError::Dialog_Abnormal);
3701 		}
3702 	    }
3703 	    break;
3704 	default:
3705 	    break;
3706     }
3707 
3708 #ifdef DEBUG
3709     if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
3710 	dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::handleDialogPortion()",this,params,DataBlock::empty());
3711 #endif
3712     return error;
3713 }
3714 
abnormalDialogInfo(NamedList & params)3715 void SS7TCAPTransactionITU::abnormalDialogInfo(NamedList& params)
3716 {
3717     params.setParam(s_tcapRequest,lookup(SS7TCAP::TC_U_Abort,SS7TCAP::s_transPrimitives));
3718     params.setParam(s_tcapAbortCause,"uAbort");
3719     params.setParam(s_tcapDialogueID,s_structDialogueOID);
3720     params.setParam(s_tcapDialoguePduType,
3721 	lookup(SS7TCAPTransactionITU::ABRTDialogTag,SS7TCAPTransactionITU::s_dialogPDUs));
3722     params.setParam(s_tcapDialogueAbrtSrc,
3723 	lookup(SS7TCAPTransactionITU::AbortSourceProvider,SS7TCAPTransactionITU::s_resultPDUValues));
3724 }
3725 
encodePAbort(SS7TCAPTransaction * tr,NamedList & params,DataBlock & data)3726 void SS7TCAPTransactionITU::encodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
3727 {
3728     NamedString* pAbortCause = params.getParam(s_tcapAbortCause);
3729     DataBlock db;
3730     if (!TelEngine::null(pAbortCause)) {
3731 	int tag = 0;
3732 	if (*pAbortCause == "pAbort") {
3733 	    tag = SS7TCAPITU::PCauseTag;
3734 	    u_int8_t pCode = SS7TCAPError::codeFromError(SS7TCAP::ITUTCAP,params.getIntValue(s_tcapAbortInfo));
3735 	    if (pCode) {
3736 		db.append(ASNLib::encodeInteger(pCode,false));
3737 		db.insert(ASNLib::buildLength(db));
3738 		db.insert(DataBlock(&tag,1));
3739 	    }
3740 	}
3741 	else if (*pAbortCause == "uAbort") {
3742 	    if (tr)
3743 		tr->encodeDialogPortion(params,data);
3744 	}
3745     }
3746     if (db.length())
3747 	data.insert(db);
3748 
3749 #ifdef DEBUG
3750      if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
3751 	 dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionITU::encodePAbort() - encoded Abort info",tr,params,data);
3752 #endif
3753 }
3754 
decodePAbort(SS7TCAPTransaction * tr,NamedList & params,DataBlock & data)3755 SS7TCAPError SS7TCAPTransactionITU::decodePAbort(SS7TCAPTransaction* tr, NamedList& params, DataBlock& data)
3756 {
3757     u_int8_t tag = data[0];
3758     SS7TCAPError error(SS7TCAP::ITUTCAP);
3759     if (!tr)
3760 	return error;
3761     SS7TCAPTransactionITU* tri = static_cast<SS7TCAPTransactionITU*>(tr);
3762     if (!tri)
3763 	return error;
3764     if (tag == SS7TCAPITU::PCauseTag) {
3765 	data.cut(-1);
3766 	u_int8_t pCode = 0;
3767 	int len = ASNLib::decodeUINT8(data,&pCode,false);
3768 	if (len != 1) {
3769 	    error.setError(SS7TCAPError::Transact_BadlyStructuredTransaction);
3770 	    return error;
3771 	}
3772 	params.setParam(s_tcapAbortCause,"pAbort");
3773 	params.setParam(s_tcapAbortInfo,String(SS7TCAPError::errorFromCode(SS7TCAP::ITUTCAP,pCode)));
3774     }
3775     else if (tri->testForDialog(data))  {
3776 	error = tri->decodeDialogPortion(params,data);
3777 	if (error.error() != SS7TCAPError::NoError)
3778 	    return error;
3779 	params.setParam(s_tcapAbortCause,"uAbort");
3780     }
3781 #ifdef DEBUG
3782      if (tr && tr->tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
3783 	 dumpData(DebugAll,tr->tcap(),"SS7TCAPTransactionITU::decodePAbort() - decoded Abort info",tr,params,data);
3784 #endif
3785     return error;
3786 }
3787 
updateToEnd()3788 void SS7TCAPTransactionITU::updateToEnd()
3789 {
3790     setTransactionType(SS7TCAP::TC_End);
3791     if (transactionState() == PackageSent)
3792 	m_basicEnd = false;
3793 }
3794 
decodeDialogPortion(NamedList & params,DataBlock & data)3795 SS7TCAPError SS7TCAPTransactionITU::decodeDialogPortion(NamedList& params, DataBlock& data)
3796 {
3797     DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::decodeDialogPortion() for transaction with localID=%s [%p]",
3798     m_localID.c_str(),this);
3799 
3800     SS7TCAPError error(SS7TCAP::ITUTCAP);
3801 
3802     u_int8_t tag = data[0];
3803     // dialog is not present
3804     if (tag != SS7TCAPITU::DialogPortionTag) // 0x6b
3805 	return error;
3806     data.cut(-1);
3807 
3808     // dialog portion is present, decode dialog length
3809     int len = ASNLib::decodeLength(data);
3810     if (len < 0 || len > (int)data.length()) {
3811 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3812 	return error;
3813     }
3814 
3815     tag = data[0];
3816     if (tag != SS7TCAPITU::ExternalTag) {// 0x28
3817 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3818 	return error;
3819     }
3820     data.cut(-1);
3821 
3822     len = ASNLib::decodeLength(data);
3823     if (len < 0 || len > (int)data.length()) {
3824 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3825 	return error;
3826     }
3827 
3828     // decode dialog-as-id
3829     ASNObjId oid;
3830     len = ASNLib::decodeOID(data,&oid,true);
3831     if (len < 0) {
3832 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3833 	return error;
3834     }
3835     params.setParam(s_tcapDialogueID,oid.toString());
3836 
3837     // remove Encoding Tag
3838     tag = data[0];
3839     if (tag != SS7TCAPITU::SingleASNTypeCEncTag) {// 0xa0
3840 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3841 	return error;
3842     }
3843     data.cut(-1);
3844 
3845     len = ASNLib::decodeLength(data);
3846     if (len < 0 || len > (int)data.length()) {
3847 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3848 	return error;
3849     }
3850 
3851     int dialogPDU = data[0]; // should be DialoguePDU type tag
3852     if (dialogPDU != AARQDialogTag && dialogPDU != AAREDialogTag && dialogPDU != ABRTDialogTag)  {// 0x60 0x61 0x64
3853 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3854 	return error;
3855     }
3856     data.cut(-1);
3857     params.setParam(s_tcapDialoguePduType,lookup(dialogPDU,s_dialogPDUs));
3858 
3859     len = ASNLib::decodeLength(data);
3860     if (len < 0 || len > (int)data.length()) {
3861 	error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3862 	return error;
3863     }
3864 
3865     // check for protocol version or abort-source
3866     if (data[0] == SS7TCAPITU::ProtocolVersionTag) { //0x80 bitstring
3867 	data.cut(-1);
3868 	if (dialogPDU != ABRTDialogTag) {
3869 	    // decode protocol version
3870 	    String proto;
3871 	    len = ASNLib::decodeBitString(data,&proto,false);
3872 	    if (len != 1) {
3873 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3874 		return error;
3875 	    }
3876 	    params.setParam(s_tcapProtoVers,proto);
3877 	}
3878 	else {
3879 	    u_int8_t abrtSrc = 0xff;
3880 	    len = ASNLib::decodeUINT8(data,&abrtSrc,false);
3881 	    int code = 0x30 | abrtSrc;
3882 	    params.setParam(s_tcapDialogueAbrtSrc,lookup(code,s_resultPDUValues));
3883 	}
3884     }
3885 
3886     // check for Application Context Tag  length OID tag length
3887     if (data[0] == SS7TCAPITU::ApplicationContextTag) { // 0xa1
3888 	data.cut(-1);
3889 	len = ASNLib::decodeLength(data);
3890 	if (len < 0 || len > (int)data.length()) {
3891 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3892 	    return error;
3893 	}
3894 	ASNObjId oid;
3895 	len = ASNLib::decodeOID(data,&oid,true);
3896 	if (len < 0) {
3897 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3898 	    return error;
3899 	}
3900 	params.setParam(s_tcapDialogueAppCtxt,oid.toString());
3901     }
3902 
3903     if (data[0] == ResultTag) {
3904 	data.cut(-1);
3905 	len = ASNLib::decodeLength(data);
3906 	if (len < 0 || len > (int)data.length()) {
3907 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3908 	    return error;
3909 	}
3910 	u_int8_t res = 0xff;
3911 	len = ASNLib::decodeUINT8(data,&res,true);
3912 	params.setParam(s_tcapDialogueResult,lookup(res,s_resultPDUValues));
3913     }
3914 
3915     if (data[0] == ResultDiagnosticTag) {
3916 	data.cut(-1);
3917 	len = ASNLib::decodeLength(data);
3918 	if (data[0] == ResultDiagnosticUserTag || data[0]== ResultDiagnosticProviderTag) {
3919 	    tag = data[0];
3920 	    data.cut(-1);
3921 	    len = ASNLib::decodeLength(data);
3922 	    if (len < 0 || len > (int)data.length()) {
3923 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3924 		return error;
3925 	    }
3926 	    u_int8_t res = 0xff;
3927 	    len = ASNLib::decodeUINT8(data,&res,true);
3928 	    if (tag == ResultDiagnosticUserTag) {
3929 		int code = 0x10 | res;
3930 		params.setParam(s_tcapDialogueDiag,lookup(code,s_resultPDUValues));
3931 	    }
3932 	    else {
3933 		int code = 0x20 | res;
3934 		params.setParam(s_tcapDialogueDiag,lookup(code,s_resultPDUValues));
3935 	    }
3936 	}
3937     }
3938     // check for user information
3939     if (data[0] == SS7TCAPITU::UserInformationTag) {// 0xfd
3940 	data.cut(-1);
3941 	len = ASNLib::decodeLength(data);
3942 	if (len < 0) {
3943 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3944 	    return error;
3945 	}
3946 
3947 	tag = data[0];
3948 	if (tag != SS7TCAPITU::ExternalTag) {
3949 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3950 	    return error;
3951 	}
3952 	data.cut(-1);
3953 
3954 	len = ASNLib::decodeLength(data);
3955 	if (len < 0 || len > (int)data.length()) {
3956 	    error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3957 	    return error;
3958 	}
3959 
3960 	// direct Reference
3961 	tag = data[0];
3962 	if (tag == SS7TCAPITU::DirectReferenceTag) { // 0x06
3963 	    data.cut(-1);
3964 	    ASNObjId oid;
3965 	    len = ASNLib::decodeOID(data,&oid,false);
3966 	    if (len < 0) {
3967 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3968 		return error;
3969 	    }
3970 	    params.setParam(s_tcapReference,oid.toString());
3971 	}
3972 
3973 	// data Descriptor
3974 	tag = data[0];
3975 	if (tag == SS7TCAPITU::DataDescriptorTag) { // 0x07
3976 	    data.cut(-1);
3977 	    String str;
3978 	    int type;
3979 	    len = ASNLib::decodeString(data,&str,&type,false);
3980 	    if (len < 0) {
3981 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3982 		return error;
3983 	    }
3984 	    params.setParam(s_tcapDataDesc,str);
3985 	}
3986 
3987 	// encoding
3988 	tag = data[0];
3989 	if (tag == SS7TCAPITU::SingleASNTypePEncTag || tag == SS7TCAPITU::SingleASNTypeCEncTag ||
3990 	    tag == SS7TCAPITU::OctetAlignEncTag || tag == SS7TCAPITU::ArbitraryEncTag) {
3991 	    data.cut(-1);
3992 	    len = ASNLib::decodeLength(data);
3993 	    if (len < 0) {
3994 		error.setError(SS7TCAPError::Dialog_BadlyStructuredDialoguePortion);
3995 		return error;
3996 	    }
3997 	    DataBlock d((void*)data.data(0,len),len);
3998 	    data.cut(-len);
3999 
4000 	    // put encoding context in hexified form
4001 	    String dataHexified;
4002 	    dataHexified.hexify(d.data(),d.length(),' ');
4003 	    params.setParam(s_tcapEncodingContent,dataHexified);
4004 	    // put encoding identifier
4005 	    switch (tag) {
4006 		case SS7TCAPITU::SingleASNTypePEncTag: // 0x80
4007 		    params.setParam(s_tcapEncodingType,"single-ASN1-type-primitive");
4008 		    break;
4009 		case SS7TCAPITU::SingleASNTypeCEncTag: // 0xa0
4010 		    params.setParam(s_tcapEncodingType,"single-ASN1-type-contructor");
4011 		    break;
4012 		case SS7TCAPITU::OctetAlignEncTag:     // 0x81
4013 		    params.setParam(s_tcapEncodingType,"octet-aligned");
4014 		    break;
4015 		case SS7TCAPITU::ArbitraryEncTag:      // 0x82
4016 		    params.setParam(s_tcapEncodingType,"arbitrary");
4017 		    break;
4018 		default:
4019 		    break;
4020 	    }
4021 	}
4022     }
4023 #ifdef DEBUG
4024      if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
4025 	 dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::decodeDialogPortion() - decoded dialog portion",this,params,data);
4026 #endif
4027     return error;
4028 }
4029 
encodeDialogPortion(NamedList & params,DataBlock & data)4030 void SS7TCAPTransactionITU::encodeDialogPortion(NamedList& params, DataBlock& data)
4031 {
4032     DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::encodeDialogPortion() for transaction with localID=%s [%p]",
4033 		m_localID.c_str(),this);
4034 
4035     DataBlock dialogData;
4036     int tag;
4037 
4038     NamedString* typeStr = params.getParam(s_tcapDialoguePduType);
4039     if (TelEngine::null(typeStr))
4040 	return;
4041     u_int8_t pduType = typeStr->toInteger(s_dialogPDUs);
4042 
4043     // encode user information
4044     DataBlock userInfo;
4045     NamedString* val = params.getParam(s_tcapEncodingType);
4046     if (!TelEngine::null(val)) {
4047 	if (*val == "single-ASN1-type-primitive")
4048 	    tag = SS7TCAPITU::SingleASNTypePEncTag;
4049 	else if (*val == "single-ASN1-type-contructor")
4050 	    tag = SS7TCAPITU::SingleASNTypeCEncTag;
4051 	else if (*val == "octet-aligned")
4052 	    tag = SS7TCAPITU::OctetAlignEncTag;
4053 	else if (*val == "arbitrary")
4054 	    tag = SS7TCAPITU::ArbitraryEncTag;
4055 
4056 	val = params.getParam(s_tcapEncodingContent);
4057 	if (val) {
4058 	    DataBlock db;
4059 	    db.unHexify(val->c_str(),val->length(),' ');
4060 	    db.insert(ASNLib::buildLength(db));
4061 	    db.insert(DataBlock(&tag,1));
4062 	    userInfo.insert(db);
4063 	}
4064     }
4065     val = params.getParam(s_tcapDataDesc);
4066     if (!TelEngine::null(val)) {
4067 	DataBlock db = ASNLib::encodeString(*val,ASNLib::PRINTABLE_STR,false);
4068 	db.insert(ASNLib::buildLength(db));
4069 	tag = SS7TCAPITU::DataDescriptorTag;
4070 	db.insert(DataBlock(&tag,1));
4071 	userInfo.insert(db);
4072     }
4073     val = params.getParam(s_tcapReference);
4074     if (!TelEngine::null(val)) {
4075 	ASNObjId oid = *val;
4076 	DataBlock db = ASNLib::encodeOID(oid,false);
4077 	db.insert(ASNLib::buildLength(db));
4078 	tag = SS7TCAPITU::DirectReferenceTag;
4079 	db.insert(DataBlock(&tag,1));
4080 	userInfo.insert(db);
4081     }
4082 
4083     if (userInfo.length()) {
4084 	userInfo.insert(ASNLib::buildLength(userInfo));
4085 	tag = SS7TCAPITU::ExternalTag;
4086 	userInfo.insert(DataBlock(&tag,1));
4087 	userInfo.insert(ASNLib::buildLength(userInfo));
4088 	tag = SS7TCAPITU::UserInformationTag;
4089 	userInfo.insert(DataBlock(&tag,1));
4090 	dialogData.insert(userInfo);
4091     }
4092 
4093     switch (pduType) {
4094 	case AAREDialogTag:
4095 	    val = params.getParam(s_tcapDialogueDiag);
4096 	    if (!TelEngine::null(val)) {
4097 		u_int16_t code = val->toInteger(s_resultPDUValues);
4098 		DataBlock db = ASNLib::encodeInteger(code % 0x10,true);
4099 		db.insert(ASNLib::buildLength(db));
4100 		if ((code & 0x10) == 0x10)
4101 		    tag = ResultDiagnosticUserTag;
4102 		else
4103 		    tag = ResultDiagnosticProviderTag;
4104 		db.insert(DataBlock(&tag,1));
4105 		db.insert(ASNLib::buildLength(db));
4106 		tag = ResultDiagnosticTag;
4107 		db.insert(DataBlock(&tag,1));
4108 		dialogData.insert(db);
4109 	    }
4110 
4111 	    val = params.getParam(s_tcapDialogueResult);
4112 	    if (!TelEngine::null(val)) {
4113 		u_int8_t res = val->toInteger(s_resultPDUValues);
4114 		DataBlock db = ASNLib::encodeInteger(res,true);
4115 		db.insert(ASNLib::buildLength(db));
4116 		tag = ResultTag;
4117 		db.insert(DataBlock(&tag,1));
4118 		dialogData.insert(db);
4119 	    }
4120 	case AARQDialogTag:
4121 	    // Application context
4122 	    val = params.getParam(s_tcapDialogueAppCtxt);
4123 	    if (!TelEngine::null(val)) {
4124 		ASNObjId oid = *val;
4125 		DataBlock db = ASNLib::encodeOID(oid,true);
4126 		db.insert(ASNLib::buildLength(db));
4127 		tag = SS7TCAPITU::ApplicationContextTag;
4128 		db.insert(DataBlock(&tag,1));
4129 		dialogData.insert(db);
4130 	    }
4131 	    val = params.getParam(s_tcapProtoVers);
4132 	    if (!TelEngine::null(val) && (val->toInteger() > 0)) {
4133 		DataBlock db = ASNLib::encodeBitString(*val,false);
4134 		db.insert(ASNLib::buildLength(db));
4135 		tag = SS7TCAPITU::ProtocolVersionTag;
4136 		db.insert(DataBlock(&tag,1));
4137 		dialogData.insert(db);
4138 	    }
4139 	    break;
4140 	case ABRTDialogTag:
4141 	    val = params.getParam(s_tcapDialogueAbrtSrc);
4142 	    if (!TelEngine::null(val)) {
4143 		u_int8_t code = val->toInteger(s_resultPDUValues) % 0x30;
4144 		DataBlock db = ASNLib::encodeInteger(code,false);
4145 		db.insert(ASNLib::buildLength(db));
4146 		tag = SS7TCAPITU::ProtocolVersionTag;
4147 		db.insert(DataBlock(&tag,1));
4148 		dialogData.insert(db);
4149 	    }
4150 	    break;
4151 	default:
4152 	    return;
4153     }
4154 
4155     dialogData.insert(ASNLib::buildLength(dialogData));
4156     dialogData.insert(DataBlock(&pduType,1));
4157     dialogData.insert(ASNLib::buildLength(dialogData));
4158     tag = SS7TCAPITU::SingleASNTypeCEncTag;
4159     dialogData.insert(DataBlock(&tag,1));
4160 
4161     val = params.getParam(s_tcapDialogueID);
4162     if (TelEngine::null(val))
4163 	return;
4164 
4165     ASNObjId oid = *val;
4166     dialogData.insert(ASNLib::encodeOID(oid,true));
4167     dialogData.insert(ASNLib::buildLength(dialogData));
4168     tag = SS7TCAPITU::ExternalTag;
4169     dialogData.insert(DataBlock(&tag,1));
4170     dialogData.insert(ASNLib::buildLength(dialogData));
4171     tag = SS7TCAPITU::DialogPortionTag;
4172     dialogData.insert(DataBlock(&tag,1));
4173 
4174     data.insert(dialogData);
4175     params.clearParam(s_tcapDialogPrefix,'.');
4176 #ifdef DEBUG
4177      if (s_printMsgs && s_extendedDbg && debugAt(DebugAll))
4178 	 dumpData(DebugAll,tcap(),"SS7TCAPTransactionITU::encodeDialogPortion() - encoded dialog portion",this,params,data);
4179 #endif
4180 }
4181 
decodeComponents(NamedList & params,DataBlock & data)4182 SS7TCAPError SS7TCAPTransactionITU::decodeComponents(NamedList& params, DataBlock& data)
4183 {
4184     XDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::decodeComponents() [%p] - data length=%u",this,data.length());
4185 
4186     SS7TCAPError error(SS7TCAP::ITUTCAP);
4187     if (!data.length()) {
4188 	params.setParam(s_tcapCompCount,"0");
4189 	return error;
4190     }
4191 
4192     u_int8_t tag = data[0];
4193     if (tag != SS7TCAPITU::ComponentPortionTag) { // 0x6c
4194 	error.setError(SS7TCAPError::General_IncorrectComponentPortion);
4195 	return error;
4196     }
4197     data.cut(-1);
4198 
4199     // decode length of component portion
4200     int len = ASNLib::decodeLength(data);
4201     bool checkEoC = (len == ASNLib::IndefiniteForm);
4202     if (!checkEoC && (len < 0 || len != (int)data.length())) { // the length of the remaining data should be the same as the decoded length
4203 	error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4204 	return error;
4205     }
4206 
4207     unsigned int compCount = 0;
4208     while (data.length()) {
4209 	if (checkEoC && ASNLib::matchEOC(data) > 0)
4210 	    break;
4211 	compCount++;
4212 	// decode component type
4213 	u_int8_t compType = data[0];
4214 	data.cut(-1);
4215 
4216 	// verify component length
4217 	len = ASNLib::decodeLength(data);
4218 	if (len < 0 || len > (int)data.length()) {
4219 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4220 	    break;
4221 	}
4222 	unsigned int initLength = data.length();
4223 	unsigned int compLength = len;
4224 
4225 	// decode invoke id
4226 	u_int16_t compID;
4227 	tag = data[0];
4228 	bool notDeriv = false;
4229 	if (tag != SS7TCAPITU::LocalTag) {// 0x02
4230 	    if (compType == Reject) {
4231 		ASNLib::decodeNull(data,true);
4232 		notDeriv = true;
4233 	    }
4234 	    else {
4235 		error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4236 		break;
4237 	    }
4238 	} else {
4239 	    data.cut(-1);
4240 
4241 	    // obtain component ID(s)
4242 	    len = ASNLib::decodeUINT16(data,&compID,false);
4243 	    if (len < 0) {
4244 		error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4245 		break;
4246 	    }
4247 	}
4248 	String compParam;
4249 	compPrefix(compParam,compCount,false);
4250 	// comp IDs shall be decoded according to component type
4251 	switch (compType) {
4252 	    case Invoke:
4253 		params.setParam(compParam + "." + s_tcapRemoteCID,String(compID));
4254 		if (data[0] == SS7TCAPITU::LinkedIDTag) {
4255 		    data.cut(-1);
4256 		    u_int16_t linkID;
4257 		    len = ASNLib::decodeUINT16(data,&linkID,false);
4258 		    if (len < 0) {
4259 			error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4260 			break;
4261 		    }
4262 		    params.setParam(compParam + "." + s_tcapLocalCID,String(compID));
4263 		}
4264 		break;
4265 	    case ReturnResultLast:
4266 	    case ReturnError:
4267 	    case Reject:
4268 	    case ReturnResultNotLast:
4269 		if (notDeriv)
4270 		    params.setParam(compParam + "." + s_tcapLocalCID,"");
4271 		else
4272 		    params.setParam(compParam + "." + s_tcapLocalCID,String(compID));
4273 		break;
4274 	    default:
4275 		error.setError(SS7TCAPError::General_UnrecognizedComponentType);
4276 		break;
4277 	}
4278 
4279 	const PrimitiveMapping* map = mapCompPrimitivesITU(-1,compType);
4280 	if (!map) {
4281 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4282 	    break;
4283 	}
4284 	params.setParam(compParam + "." +  s_tcapCompType,lookup(map->primitive,SS7TCAP::s_compPrimitives,"Unknown"));
4285 
4286 	if (error.error() != SS7TCAPError::NoError) {
4287 	    break;
4288 	}
4289 
4290 	// decode Operation Code
4291 	if (compType == Invoke ||
4292 	    compType == ReturnResultLast ||
4293 	    compType == ReturnResultNotLast) {
4294 	    tag = data[0];
4295 	    if (tag == SS7TCAPITU::ParameterSeqTag) {
4296 		data.cut(-1);
4297 		len = ASNLib::decodeLength(data);
4298 	    }
4299 	    tag = data[0];
4300 	    if (tag == SS7TCAPITU::LocalTag) {
4301 		data.cut(-1);
4302 		int opCode = 0;
4303 		len = ASNLib::decodeINT32(data,&opCode,false);
4304 		params.setParam(compParam +"." + s_tcapOpCodeType,"local");
4305 		params.setParam(compParam + "." + s_tcapOpCode,String(opCode));
4306 	    }
4307 	    else if (tag == SS7TCAPITU::GlobalTag) {
4308 		data.cut(-1);
4309 		ASNObjId obj;
4310 		len = ASNLib::decodeOID(data,&obj,false);
4311 		params.setParam(compParam + "." + s_tcapOpCodeType,"global");
4312 		params.setParam(compParam + "." + s_tcapOpCode,obj.toString());
4313 	    }
4314 	    else if (compType == Invoke) {
4315 		error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4316 		break;
4317 	    }
4318 	}
4319 
4320 	// decode  Error Code
4321 	if (compType == ReturnError) {
4322 	    tag = data[0];
4323 	    if (tag == SS7TCAPITU::LocalTag) {
4324 		data.cut(-1);
4325 		int opCode = 0;
4326 		len = ASNLib::decodeINT32(data,&opCode,false);
4327 		params.setParam(compParam + "." + s_tcapErrCodeType,"local");
4328 		params.setParam(compParam + "." + s_tcapErrCode,String(opCode));
4329 	    }
4330 	    else if (tag == SS7TCAPITU::GlobalTag) {
4331 		data.cut(-1);
4332 		ASNObjId obj;
4333 		len = ASNLib::decodeOID(data,&obj,false);
4334 		params.setParam(compParam + "." + s_tcapErrCodeType,"global");
4335 		params.setParam(compParam + "." + s_tcapErrCode,obj.toString());
4336 	    }
4337 	    else {
4338 		error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4339 		break;
4340 	    }
4341 	}
4342 
4343 	// decode Problem
4344 	if (compType == Reject) {
4345 	    tag = data[0];
4346 	    data.cut(-1);
4347 	    u_int16_t problemCode = 0x0 | (tag << 8);
4348 	    u_int8_t code = 0;
4349 	    len = ASNLib::decodeUINT8(data,&code,false);
4350 	    problemCode |= code;
4351 	    params.setParam(compParam + "." + s_tcapProblemCode,String(SS7TCAPError::errorFromCode(tcap()->tcapType(),problemCode)));
4352 	}
4353 	else {
4354 	// decode Parameters (Set or Sequence) as payload
4355 	    int payloadLen = data.length() - (initLength - compLength);
4356 	    DataBlock d((void*)data.data(0,payloadLen),payloadLen);
4357 	    data.cut(-payloadLen);
4358 	    String dataHexified = "";
4359 	    dataHexified.hexify(d.data(),d.length(),' ');
4360 	    params.setParam(compParam,dataHexified);
4361 	}
4362 	if (initLength - data.length() != compLength) { // check we consumed the announced component length
4363 	    error.setError(SS7TCAPError::General_BadlyStructuredCompPortion);
4364 	    break;
4365 	}
4366     }
4367 
4368     params.setParam(s_tcapCompCount,String(compCount));
4369 #ifdef DEBUG
4370     if (tcap() && s_printMsgs && s_extendedDbg && debugAt(DebugAll))
4371 	dumpData(DebugAll,tcap(),"Finished decoding message",this,params,data);
4372 #endif
4373     return error;
4374 }
4375 
encodeComponents(NamedList & params,DataBlock & data)4376 void SS7TCAPTransactionITU::encodeComponents(NamedList& params, DataBlock& data)
4377 {
4378     XDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::encodeComponents() for transaction with localID=%s [%p]",m_localID.c_str(),this);
4379 
4380     int componentCount = params.getIntValue(s_tcapCompCount,0);
4381     DataBlock compData;
4382     if (componentCount) {
4383 	int index = componentCount + 1;
4384 
4385 	while (--index) {
4386 	    DataBlock codedComp;
4387 	    // encode parameters
4388 	    String compParam;
4389 	    compPrefix(compParam,index,false);
4390 	    // Component Type
4391 	    int compPrimitive = lookup(params.getValue(compParam + "." + s_tcapCompType,"Unknown"),SS7TCAP::s_compPrimitives);
4392 	    const PrimitiveMapping* map = mapCompPrimitivesITU(compPrimitive,-1);
4393 	    if (!map)
4394 		continue;
4395 	    int compType = map->mappedTo;
4396 
4397 	    NamedString* value = 0;
4398 	    bool hasPayload = false;
4399 	    if (compType == Reject) {
4400 		value = params.getParam(compParam + "." + s_tcapProblemCode);
4401 		if (!TelEngine::null(value)) {
4402 		    u_int16_t codeErr = SS7TCAPError::codeFromError(tcap()->tcapType(),(SS7TCAPError::ErrorType)value->toInteger());
4403 		    u_int8_t problemTag = (codeErr & 0xff00) >> 8;
4404 		    u_int8_t code = codeErr & 0x000f;
4405 		    DataBlock db(DataBlock(&code,1));
4406 		    db.insert(ASNLib::buildLength(db));
4407 		    db.insert(DataBlock(&problemTag,1));
4408 		    codedComp.insert(db);
4409 		}
4410 		else {
4411 		    Debug(tcap(),DebugWarn,"Missing mandatory 'problemCode' information for component with index='%d' from transaction "
4412 			    "with localID=%s [%p]",index,m_localID.c_str(),this);
4413 		    continue;
4414 		}
4415 	    }
4416 	    else {
4417 		NamedString* payloadHex = params.getParam(compParam);
4418 		if (!TelEngine::null(payloadHex)) {
4419 		    DataBlock payload;
4420 		    payload.unHexify(payloadHex->c_str(),payloadHex->length(),' ');
4421 		    codedComp.insert(payload);
4422 		    hasPayload = true;
4423 		}
4424 	    }
4425 	    // encode  Error Code only if ReturnError
4426 	    if (compType == ReturnError) {
4427 		value = params.getParam(compParam + "." + s_tcapErrCodeType);
4428 		if (!TelEngine::null(value)) {
4429 		    int tag = 0;
4430 		    DataBlock db;
4431 		    if (*value == "local") {
4432 			tag = SS7TCAPITU::LocalTag;
4433 			int errCode = params.getIntValue(compParam + "." + s_tcapErrCode,0);
4434 			db = ASNLib::encodeInteger(errCode,false);
4435 			db.insert(ASNLib::buildLength(db));
4436 		    }
4437 		    else if (*value == "global") {
4438 			tag = SS7TCAPITU::GlobalTag;
4439 			ASNObjId oid = String(params.getValue(compParam + "." + s_tcapErrCode));
4440 			db = ASNLib::encodeOID(oid,false);
4441 			db.insert(ASNLib::buildLength(db));
4442 		    }
4443 		    db.insert(DataBlock(&tag,1));
4444 		    codedComp.insert(db);
4445 		}
4446 		else {
4447 		    Debug(tcap(),DebugWarn,"Missing mandatory 'errorCodeType' information for component with index='%d' from transaction "
4448 			    "with localID=%s [%p]",index,m_localID.c_str(),this);
4449 		    continue;
4450 		}
4451 	    }
4452 
4453 	    // encode Operation Code only if Invoke
4454 	    if (compType == Invoke ||
4455 		compType == ReturnResultNotLast ||
4456 		compType == ReturnResultLast) {
4457 		value = params.getParam(compParam + "." + s_tcapOpCodeType);
4458 		if (!TelEngine::null(value)) {
4459 		    int tag = 0;
4460 		    DataBlock db;
4461 		    if (*value == "local") {
4462 			int opCode = params.getIntValue(compParam + "." + s_tcapOpCode,0);
4463 			db = ASNLib::encodeInteger(opCode,true);
4464 		    }
4465 		    else if (*value == "global") {
4466 			ASNObjId oid(params.getValue(compParam + "." + s_tcapOpCode));
4467 			db = ASNLib::encodeOID(oid,true);
4468 			//db.insert(ASNLib::buildLength(db));
4469 		    }
4470 		    codedComp.insert(db);
4471 		    if (compType != Invoke) {
4472 			tag = SS7TCAPITU::ParameterSeqTag;
4473 			codedComp.insert(ASNLib::buildLength(codedComp));
4474 			codedComp.insert(DataBlock(&tag,1));
4475 		    }
4476 		}
4477 		else {
4478 		    if (compType == Invoke || hasPayload) {
4479 			Debug(tcap(),DebugWarn,"Missing mandatory 'operationCodeType' information for component with index='%d' from transaction "
4480 			    "with localID=%s [%p]",index,m_localID.c_str(),this);
4481 			continue;
4482 		    }
4483 		}
4484 	    }
4485 
4486 	    NamedString* invID = params.getParam(compParam + "." + s_tcapLocalCID);
4487 	    NamedString* linkID = params.getParam(compParam + "." + s_tcapRemoteCID);
4488 	    DataBlock db;
4489 	    u_int8_t val = 0;
4490 	    switch (compType) {
4491 		case Invoke:
4492 		    if (!TelEngine::null(linkID)) {
4493 			val = linkID->toInteger();
4494 			DataBlock db1;
4495 			db1.append(&val,sizeof(u_int8_t));
4496 			db1.insert(ASNLib::buildLength(db1));
4497 			val = SS7TCAPITU::LinkedIDTag;
4498 			db1.insert(DataBlock(&val,1));
4499 			codedComp.insert(db1);
4500 		    }
4501 		    if (!TelEngine::null(invID)) {
4502 			val = invID->toInteger();
4503 			db.append(&val,sizeof(u_int8_t));
4504 			db.insert(ASNLib::buildLength(db));
4505 			val = SS7TCAPITU::LocalTag;
4506 			db.insert(DataBlock(&val,1));
4507 		    }
4508 		    else {
4509 			Debug(tcap(),DebugWarn,"Missing mandatory 'localCID' information for component with index='%d' from transaction "
4510 			    "with localID=%s [%p]",index,m_localID.c_str(),this);
4511 			continue;
4512 		    }
4513 		    break;
4514 		case ReturnResultLast:
4515 		case ReturnError:
4516 		case ReturnResultNotLast:
4517 		    if (!TelEngine::null(linkID)) {
4518 			val = linkID->toInteger();
4519 			db.append(&val,sizeof(u_int8_t));
4520 			db.insert(ASNLib::buildLength(db));
4521 			val = SS7TCAPITU::LocalTag;
4522 			db.insert(DataBlock(&val,1));
4523 		    }
4524 		    else {
4525 			Debug(tcap(),DebugWarn,"Missing mandatory 'remoteCID' information for component with index='%d' from transaction "
4526 			    "with localID=%s [%p]",index,m_localID.c_str(),this);
4527 			continue;
4528 		    }
4529 		    break;
4530 		case Reject:
4531 		    if (TelEngine::null(linkID))
4532 			linkID = invID;
4533 		    if (!TelEngine::null(linkID)) {
4534 			val = linkID->toInteger();
4535 			db.append(&val,sizeof(u_int8_t));
4536 			db.insert(ASNLib::buildLength(db));
4537 			val = SS7TCAPITU::LocalTag;
4538 			db.insert(DataBlock(&val,1));
4539 		    }
4540 		    else
4541 			db.insert(ASNLib::encodeNull(true));
4542 		    break;
4543 		default:
4544 		    break;
4545 	    }
4546 	    codedComp.insert(db);
4547 
4548 	    if(codedComp.length()) {
4549 		codedComp.insert(ASNLib::buildLength(codedComp));
4550 		codedComp.insert(DataBlock(&compType,1));
4551 	    }
4552 
4553 	    params.clearParam(compParam,'.'); // clear all params for this component
4554 	    compData.insert(codedComp);
4555 	}
4556 
4557 	if (compData.length()) {
4558 	    compData.insert(ASNLib::buildLength(compData));
4559 	    int tag = SS7TCAPITU::ComponentPortionTag;
4560 	    compData.insert(DataBlock(&tag,1));
4561 
4562 	    data.insert(compData);
4563 	}
4564     }
4565 
4566     params.clearParam(s_tcapCompPrefix,'.');
4567 }
4568 
requestContent(NamedList & params,DataBlock & data)4569 void SS7TCAPTransactionITU::requestContent(NamedList& params, DataBlock &data)
4570 {
4571 #ifdef DEBUG
4572     DDebug(tcap(),DebugAll,"SS7TCAPTransactionITU::requestContent() - for id=%s [%p]",m_localID.c_str(),this);
4573 #endif
4574     if (m_type == SS7TCAP::TC_P_Abort || m_type == SS7TCAP::TC_U_Abort)
4575 	encodePAbort(this,params,data);
4576     else {
4577 	requestComponents(params,data);
4578 	if (dialogPresent()) {
4579 	    if (TelEngine::null(params.getParam(s_tcapDialoguePduType)))
4580 		handleDialogPortion(params,true);
4581 	    encodeDialogPortion(params,data);
4582 	}
4583     }
4584     transactionData(params);
4585 }
4586 
4587 /* vi: set ts=8 sw=4 sts=4 noet: */
4588