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"),¶ms,"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"),¶ms,"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