Added posibility to set maximum data size that can be transported on a specific route.
Improved SCCP segmentation process. The SCCP now detects the maximum amount of data that can fit in a SCCP message. Implemented SCCP message change procedures. git-svn-id: http://yate.null.ro/svn/yate/trunk@4828 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
c736a1e35f
commit
beb1cd1225
|
@ -504,19 +504,37 @@
|
|||
;netindicator=national
|
||||
|
||||
; route: string: Build a destination route for the SS7 network
|
||||
; The format of this option is pointcodetype,label,priority
|
||||
; The format of this option is pointcodetype,label,priority,shift,size
|
||||
; This parameter can be repeated to build multiple destination routes
|
||||
; The network will notify the router about its destination(s) and priority
|
||||
;
|
||||
; If not specified the priority is 100. A zero priority creates an adjacent route
|
||||
; Example: route=ITU,2-2-2,100
|
||||
;
|
||||
; Shift SLS right shift when selecting linkset.
|
||||
; For example for 2 links shift = 1.
|
||||
; A value of 8 or higher disables load balancing.
|
||||
;
|
||||
; Size represents the maximum data size that can be transported on this route.
|
||||
; The default vaue is 272 -> maximum MSU size on TDM.
|
||||
; If the route can transport more data, a value up to 3904 should be set to
|
||||
; avoid SCCP message fragmentation.
|
||||
;
|
||||
; Example: route=ITU,2-2-2,100,1,272
|
||||
;route=
|
||||
|
||||
; adjacent: string: Build an adjacent route for the SS7 network (A, E and F links)
|
||||
; The format of this option is pointcodetype,label
|
||||
; The format of this option is pointcodetype,label,size
|
||||
; This parameter can be repeated to declare multiple adjacent routers
|
||||
; The network will notify the router about its destination(s) and priority
|
||||
;
|
||||
; The priority is always zero so an adjacent route will always match first.
|
||||
; Example: adjacent=ANSI,40-50-60
|
||||
;
|
||||
; Size represents the maximum data size that can be transported on this route.
|
||||
; The default vaue is 272 -> maximum MSU size on TDM.
|
||||
; If the route can transport more data, a value up to 3904 should be set to
|
||||
; avoid SCCP message fragmentation
|
||||
;
|
||||
; Example: adjacent=ANSI,40-50-60,272
|
||||
;adjacent=
|
||||
|
||||
; local: string: Declare a local pointcode for the SS7 network
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
|
||||
using namespace TelEngine;
|
||||
|
||||
#define MAX_TDM_DATA_SIZE 272
|
||||
#define MAX_SIGTRAN_DATA_SIZE 3904 // Maximum ANSI LUDT(SCCP) length
|
||||
|
||||
static const TokenDict s_dict_control[] = {
|
||||
{ "show", SS7MTP3::Status },
|
||||
{ "pause", SS7MTP3::Pause },
|
||||
|
@ -181,6 +184,7 @@ bool SS7Layer3::buildRoutes(const NamedList& params)
|
|||
continue;
|
||||
unsigned int prio = 0;
|
||||
unsigned int shift = 0;
|
||||
unsigned int maxLength = MAX_TDM_DATA_SIZE;
|
||||
bool local = false;
|
||||
if (ns->name() == YSTRING("local"))
|
||||
local = true;
|
||||
|
@ -200,14 +204,27 @@ bool SS7Layer3::buildRoutes(const NamedList& params)
|
|||
obj = obj->skipNext();
|
||||
if (!(obj && pc.assign(obj->get()->toString(),type)))
|
||||
break;
|
||||
if (prio) {
|
||||
if (!(obj = obj->skipNext()))
|
||||
break;
|
||||
if (prio) {
|
||||
prio = obj->get()->toString().toInteger(prio);
|
||||
obj = obj->skipNext();
|
||||
if (obj)
|
||||
shift = obj->get()->toString().toInteger(0);
|
||||
}
|
||||
if (!(obj = obj->skipNext()) || local)
|
||||
break;
|
||||
maxLength = obj->get()->toString().toInteger(maxLength);
|
||||
if (maxLength < MAX_TDM_DATA_SIZE) {
|
||||
Debug(this,DebugNote,"MaxDataLength is too small %d. Setting it to %d",
|
||||
maxLength,MAX_TDM_DATA_SIZE);
|
||||
maxLength = MAX_TDM_DATA_SIZE;
|
||||
}
|
||||
if (maxLength > MAX_SIGTRAN_DATA_SIZE) {
|
||||
Debug(this,DebugNote,"MaxDataLength is too big %d. Setting it to %d",
|
||||
maxLength,MAX_SIGTRAN_DATA_SIZE);
|
||||
maxLength = MAX_SIGTRAN_DATA_SIZE;
|
||||
}
|
||||
} while (false);
|
||||
TelEngine::destruct(route);
|
||||
unsigned int packed = pc.pack(type);
|
||||
|
@ -220,10 +237,12 @@ bool SS7Layer3::buildRoutes(const NamedList& params)
|
|||
m_local[type - 1] = packed;
|
||||
continue;
|
||||
}
|
||||
if (findRoute(type,packed))
|
||||
if (findRoute(type,packed)) {
|
||||
Debug(this,DebugWarn,"Duplicate route found %s!!",ns->c_str());
|
||||
continue;
|
||||
}
|
||||
added = true;
|
||||
m_route[(unsigned int)type - 1].append(new SS7Route(packed,prio,shift));
|
||||
m_route[(unsigned int)type - 1].append(new SS7Route(packed,type,prio,shift,maxLength));
|
||||
DDebug(this,DebugAll,"Added route '%s'",ns->c_str());
|
||||
}
|
||||
if (!added)
|
||||
|
@ -233,6 +252,19 @@ bool SS7Layer3::buildRoutes(const NamedList& params)
|
|||
return added;
|
||||
}
|
||||
|
||||
// Get the maximum data length that this route can transport
|
||||
unsigned int SS7Layer3::getRouteMaxLength(SS7PointCode::Type type, unsigned int packedPC)
|
||||
{
|
||||
if (type == SS7PointCode::Other || (unsigned int)type > YSS7_PCTYPE_COUNT || !packedPC)
|
||||
return MAX_TDM_DATA_SIZE;
|
||||
Lock lock(m_routeMutex);
|
||||
SS7Route* route = findRoute(type,packedPC);
|
||||
if (route)
|
||||
return route->m_maxDataLength;
|
||||
return MAX_TDM_DATA_SIZE;
|
||||
}
|
||||
|
||||
|
||||
// Get the priority of a route.
|
||||
unsigned int SS7Layer3::getRoutePriority(SS7PointCode::Type type, unsigned int packedPC)
|
||||
{
|
||||
|
|
|
@ -130,6 +130,11 @@ void SS7Route::attach(SS7Layer3* network, SS7PointCode::Type type)
|
|||
Lock lock(this);
|
||||
// Remove from list if already there
|
||||
detach(network);
|
||||
SS7Route* route = network->findRoute(m_type,m_packed);
|
||||
if (route) {
|
||||
if (m_maxDataLength > route->getMaxDataLength() || m_maxDataLength == 0)
|
||||
m_maxDataLength = route->getMaxDataLength();
|
||||
}
|
||||
// Insert
|
||||
if (priority == 0) {
|
||||
m_networks.insert(new L3Pointer(network));
|
||||
|
@ -161,6 +166,21 @@ bool SS7Route::detach(SS7Layer3* network)
|
|||
break;
|
||||
}
|
||||
}
|
||||
m_maxDataLength = 0;
|
||||
for (o = m_networks.skipNull(); o; o = o->skipNext()) {
|
||||
L3Pointer* p = static_cast<L3Pointer*>(o->get());
|
||||
if (!p)
|
||||
continue;
|
||||
RefPointer<SS7Layer3> l3 = static_cast<SS7Layer3*>(*p);
|
||||
if (!l3)
|
||||
continue;
|
||||
SS7Route* route = l3->findRoute(m_type,m_packed);
|
||||
if (route) {
|
||||
if (m_maxDataLength > route->getMaxDataLength() ||
|
||||
m_maxDataLength == 0)
|
||||
m_maxDataLength = route->getMaxDataLength();
|
||||
}
|
||||
}
|
||||
return 0 != m_networks.skipNull();
|
||||
}
|
||||
|
||||
|
@ -665,7 +685,7 @@ void SS7Router::buildView(SS7PointCode::Type type, ObjList& view, SS7Layer3* net
|
|||
if (!v) {
|
||||
DDebug(this,DebugAll,"Creating route to %u from %s in view of %s",
|
||||
route->packed(),(*p)->toString().c_str(),network->toString().c_str());
|
||||
view.append(new SS7Route(route->packed()));
|
||||
view.append(new SS7Route(route->packed(),type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,11 +32,16 @@
|
|||
using namespace TelEngine;
|
||||
|
||||
#define MAX_MANDATORY_PARAMS 16
|
||||
// NOTE Keep MAX_DATA_LEN smaller than the value defined by protocol.
|
||||
// In case that we have to encode optional parameters the pointer to optionalParameters will be wrapped around 255
|
||||
#define MAX_DATA_LEN 220 // ITU defines 255 if the calling party address does not include GT, ANSI 252
|
||||
#define SGM_PADDING 10 // Segmentation padding
|
||||
|
||||
// 227 is maximum data length that can be transported by a UDT message
|
||||
// with 2 full gt present both numbers with 16 digits (bcd encoded)
|
||||
#define MAX_UDT_LEN 227
|
||||
|
||||
#define MAX_INFO_TIMER 1200000 // Maximum interval for sending SST 20 min
|
||||
// Maximum length of optional parameters: 6 Segmentation, 3 Importance, 1 EOP
|
||||
#define MAX_OPT_LEN 10
|
||||
// Minimum data size in a SCCP message
|
||||
#define MIN_DATA_SIZE 2
|
||||
|
||||
static const char* s_userMutexName = "SCCPUserTransport";
|
||||
static const char* s_sccpMutexName = "SCCPUserList";
|
||||
|
@ -946,9 +951,8 @@ static unsigned int encodeData(const SS7SCCP* sccp, SS7MSU& msu, SS7MsgSCCP* msg
|
|||
}
|
||||
unsigned int length = data->length();
|
||||
unsigned char header[2];
|
||||
bool longData = msg->type() == SS7MsgSCCP::LUDT;
|
||||
DataBlock tmp;
|
||||
if (longData) {
|
||||
if (msg->isLongDataMessage()) {
|
||||
header[0] = length & 0xff;
|
||||
header[1] = length >> 8 & 0xff;
|
||||
tmp.assign(header,2,false);
|
||||
|
@ -1954,8 +1958,6 @@ bool SCCPManagement::handleMessage(int msgType, unsigned char ssn, unsigned char
|
|||
break;
|
||||
}
|
||||
lock.drop();
|
||||
NamedList notif("");
|
||||
notif.setParam("ssn",String("ssn"));
|
||||
if (!managementMessage(SCCP::SubsystemStatus,params))
|
||||
return true;
|
||||
String* status = params.getParam(YSTRING("subsystem-status"));
|
||||
|
@ -2648,7 +2650,7 @@ bool SccpRemote::initialize(const String& params)
|
|||
String* subsystem = static_cast<String*>(ob->get());
|
||||
unsigned int ssn = subsystem->toInteger(256);
|
||||
if (ssn > 255) {
|
||||
DDebug(DebugConf,"Skipping ssn %d for pointcode %d Value to big!",
|
||||
DDebug(DebugConf,"Skipping ssn %d for pointcode %d Value too big!",
|
||||
ssn,m_pointcode.pack(m_pointcodeType));
|
||||
continue;
|
||||
}
|
||||
|
@ -2766,7 +2768,7 @@ SS7SCCP::SS7SCCP(const NamedList& params)
|
|||
: SignallingComponent(params,¶ms), SS7Layer4(SS7MSU::SCCP|SS7MSU::National,¶ms), Mutex(true,params),
|
||||
m_type(SS7PointCode::Other), m_localPointCode(0), m_management(0), m_hopCounter(15),
|
||||
m_msgReturnStatus(""), m_segTimeout(0), m_ignoreUnkDigits(false), m_layer3Up(false),
|
||||
m_supportLongData(false), m_totalSent(0), m_totalReceived(0), m_errors(0),
|
||||
m_maxUdtLength(220), m_totalSent(0), m_totalReceived(0), m_errors(0),
|
||||
m_totalGTTranslations(0), m_gttFailed(0), m_extendedMonitoring(false), m_mgmName("sccp-mgm"),
|
||||
m_printMsg(false), m_extendedDebug(false), m_endpoint(true)
|
||||
{
|
||||
|
@ -2806,7 +2808,7 @@ SS7SCCP::SS7SCCP(const NamedList& params)
|
|||
m_printMsg = params.getBoolValue(YSTRING("print-messages"),false);
|
||||
m_extendedDebug = params.getBoolValue(YSTRING("extended-debug"),false);
|
||||
m_extendedMonitoring = params.getBoolValue(YSTRING("extended-monitoring"),false);
|
||||
m_supportLongData = params.getBoolValue(YSTRING("ludt-support"),false);
|
||||
m_maxUdtLength = params.getIntValue(YSTRING("max-udt-length"),MAX_UDT_LEN);
|
||||
m_segTimeout = params.getIntValue(YSTRING("segmentation-timeout"),10000);
|
||||
m_mgmName = params.getValue(YSTRING("management"));
|
||||
m_endpoint = params.getBoolValue(YSTRING("endpoint"),true);
|
||||
|
@ -2854,6 +2856,7 @@ bool SS7SCCP::initialize(const NamedList* config)
|
|||
m_printMsg = config->getBoolValue(YSTRING("print-messages"),m_printMsg);
|
||||
m_extendedDebug = config->getBoolValue(YSTRING("extended-debug"),m_extendedDebug);
|
||||
m_ignoreUnkDigits = config->getBoolValue(YSTRING("ignore-unknown-digits"),m_ignoreUnkDigits);
|
||||
m_maxUdtLength = config->getIntValue(YSTRING("max-udt-length"),m_maxUdtLength);
|
||||
m_endpoint = config->getBoolValue(YSTRING("endpoint"),m_endpoint);
|
||||
int hc = config->getIntValue("hopcounter",m_hopCounter);
|
||||
if (hc < 1 || hc > 15)
|
||||
|
@ -2879,14 +2882,6 @@ void SS7SCCP::attach(SS7Layer3* network)
|
|||
setNetworkUp(network && network->operational());
|
||||
}
|
||||
|
||||
bool SS7SCCP::canSendLUDT(const SS7Label& label)
|
||||
{
|
||||
// TODO Check the maxumum MSU size that can be transmited
|
||||
// and determine if we can send LUDT messages
|
||||
// SEE if we should update the MAX_DATA_SIZE!!
|
||||
return m_supportLongData;
|
||||
}
|
||||
|
||||
bool SS7SCCP::managementStatus(Type type, NamedList& params)
|
||||
{
|
||||
if (m_management)
|
||||
|
@ -2908,6 +2903,21 @@ void SS7SCCP::timerTick(const Time& when)
|
|||
}
|
||||
}
|
||||
|
||||
void SS7SCCP::ajustMessageParams(NamedList& params, SS7MsgSCCP::Type type)
|
||||
{
|
||||
if (type == SS7MsgSCCP::UDT || type == SS7MsgSCCP::UDTS)
|
||||
return;
|
||||
int hopCounter = params.getIntValue(YSTRING("HopCounter"),0);
|
||||
if (hopCounter < 1 || hopCounter > 15)
|
||||
params.setParam("HopCounter",String(m_hopCounter));
|
||||
if (ITU() && params.getParam(YSTRING("Importance"))) {
|
||||
int importance = params.getIntValue(YSTRING("Importance"));
|
||||
int temp = checkImportanceLevel(type, importance);
|
||||
if (importance != temp)
|
||||
params.setParam(YSTRING("Importance"),String(temp));
|
||||
}
|
||||
}
|
||||
|
||||
// Called by routing method to send a msu
|
||||
int SS7SCCP::transmitMessage(SS7MsgSCCP* sccpMsg, bool local)
|
||||
{
|
||||
|
@ -2935,23 +2945,10 @@ int SS7SCCP::transmitMessage(SS7MsgSCCP* sccpMsg, bool local)
|
|||
}
|
||||
// Build the routing label
|
||||
SS7Label outLabel(m_type,dest,orig,sls);
|
||||
while (!canSendLUDT(outLabel)) {
|
||||
if (sccpMsg->getData()->length() <= MAX_DATA_LEN)
|
||||
break;
|
||||
if (sccpMsg->getData()->length() > m_maxUdtLength) {
|
||||
lock.drop();
|
||||
if (sccpMsg->type() == SS7MsgSCCP::UDT || sccpMsg->type() == SS7MsgSCCP::UDTS) {
|
||||
Debug(this,DebugStub,"Request to segment message %s! Implement message change!",
|
||||
SS7MsgSCCP::lookup(sccpMsg->type()));
|
||||
return -1;
|
||||
return segmentMessage(sccpMsg,outLabel,local);
|
||||
}
|
||||
int sls = segmentMessage(*sccpMsg->getData(),sccpMsg,sccpMsg->type(),local);
|
||||
if (sls < 0) {
|
||||
Lock lock(this);
|
||||
m_errors++;
|
||||
}
|
||||
return sls;
|
||||
}
|
||||
|
||||
// Check route indicator
|
||||
if (!sccpMsg->params().getParam("CalledPartyAddress.route")) {
|
||||
// Set route indicator. If have pointcode and ssn, route on ssn
|
||||
|
@ -2963,32 +2960,9 @@ int SS7SCCP::transmitMessage(SS7MsgSCCP* sccpMsg, bool local)
|
|||
}
|
||||
// Build the msu
|
||||
SS7MSU* msu = buildMSU(sccpMsg,outLabel);
|
||||
|
||||
if (!msu) {
|
||||
Debug(this,DebugWarn,"Failed to build msu from sccpMessage %s",
|
||||
SS7MsgSCCP::lookup(sccpMsg->type()));
|
||||
return -1;
|
||||
}
|
||||
if (m_printMsg && debugAt(DebugInfo)) {
|
||||
String tmp;
|
||||
void* data = 0;
|
||||
unsigned int len = 0;
|
||||
if (m_extendedDebug && msu) {
|
||||
unsigned int offs = outLabel.length() + 4;
|
||||
data = msu->getData(offs);
|
||||
len = data ? msu->length() - offs : 0;
|
||||
}
|
||||
String tmp1;
|
||||
fillLabelAndReason(tmp1,outLabel,sccpMsg);
|
||||
sccpMsg->toString(tmp,outLabel,debugAt(DebugAll),data,len);
|
||||
Debug(this,DebugInfo,"Sending message (%p) '%s' %s %s",sccpMsg,
|
||||
SS7MsgSCCP::lookup(sccpMsg->type()),tmp1.c_str(),tmp.c_str());
|
||||
} else if (debugAt(DebugAll)) {
|
||||
String tmp;
|
||||
bool debug = fillLabelAndReason(tmp,outLabel,sccpMsg);
|
||||
Debug(this,debug ? DebugInfo : DebugAll,"Sending message '%s' %s",
|
||||
sccpMsg->name(),tmp.c_str());
|
||||
}
|
||||
if (!msu)
|
||||
return segmentMessage(sccpMsg,outLabel,local);
|
||||
printMessage(msu,sccpMsg,outLabel);
|
||||
lock.drop();
|
||||
sls = transmitMSU(*msu,outLabel,sls);
|
||||
#ifdef DEBUG
|
||||
|
@ -3100,31 +3074,18 @@ int SS7SCCP::sendMessage(DataBlock& data, const NamedList& params)
|
|||
Debug(this,DebugAll,"SS7SCCP::sendMessage() [%p]%s",this,tmp.c_str());
|
||||
#endif
|
||||
Lock lock1(this);
|
||||
// Verify the presence of optional parameters to detect the message
|
||||
// type used to send SCLC data
|
||||
bool checkImportance = false;
|
||||
bool checkHopCounter = false;
|
||||
SS7MsgSCCP* sccpMsg = 0;
|
||||
if (data.length() > MAX_DATA_LEN) {
|
||||
// TODO verify if we can send LUDT Have a sigtran under?
|
||||
// If not segment the message. send multiple XUDT messages
|
||||
sccpMsg = new SS7MsgSCCP(m_supportLongData ? SS7MsgSCCP::LUDT : SS7MsgSCCP::XUDT);
|
||||
checkHopCounter = true;
|
||||
if(params.getParam(YSTRING("Importance")) && m_type == SS7PointCode::ITU)
|
||||
checkImportance = true;
|
||||
} else if (params.getParam(YSTRING("Importance")) && m_type == SS7PointCode::ITU) {
|
||||
// Do not check for data length here! If message data is too long the message
|
||||
// change procedure will be initiated in segmentMessage method
|
||||
if (params.getParam(YSTRING("Importance")) && m_type == SS7PointCode::ITU) {
|
||||
// We have Importance optional parameter. Send XUDT. ITU only
|
||||
sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::XUDT);
|
||||
checkHopCounter = true;
|
||||
checkImportance = true;
|
||||
} else if ((params.getParam(YSTRING("ISNI")) || params.getParam(YSTRING("INS"))) &&
|
||||
m_type == SS7PointCode::ANSI) {
|
||||
// XUDT message ANSI only
|
||||
sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::XUDT);
|
||||
checkHopCounter = true;
|
||||
} else if (params.getParam(YSTRING("HopCounter"))) {
|
||||
sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::XUDT);
|
||||
checkHopCounter = true;
|
||||
} else // In rest send Unit Data Messages
|
||||
sccpMsg = new SS7MsgSCCP(SS7MsgSCCP::UDT);
|
||||
|
||||
|
@ -3134,17 +3095,7 @@ int SS7SCCP::sendMessage(DataBlock& data, const NamedList& params)
|
|||
return -1;
|
||||
}
|
||||
sccpMsg->params().copyParams(params); // Copy the parameters to message
|
||||
if (checkImportance) {
|
||||
int importance = sccpMsg->params().getIntValue(YSTRING("Importance"));
|
||||
int temp = checkImportanceLevel(sccpMsg->type(), importance);
|
||||
if (importance != temp)
|
||||
sccpMsg->params().setParam(YSTRING("Importance"),String(temp));
|
||||
}
|
||||
if (checkHopCounter) {
|
||||
int hopCounter = params.getIntValue(YSTRING("HopCounter"),0);
|
||||
if (hopCounter < 1 || hopCounter > 15) // HopCounter is an mandatory fixed length parameter in XUDT
|
||||
sccpMsg->params().setParam(YSTRING("HopCounter"),String(m_hopCounter));
|
||||
}
|
||||
ajustMessageParams(sccpMsg->params(),sccpMsg->type());
|
||||
if (params.getBoolValue(YSTRING("CallingPartyAddress.pointcode"),false) && m_localPointCode)
|
||||
sccpMsg->params().setParam("CallingPartyAddress.pointcode",String(getPackedPointCode()));
|
||||
// Avoid sending optional parameters that aren't specified by protocol
|
||||
|
@ -3165,109 +3116,344 @@ int SS7SCCP::sendMessage(DataBlock& data, const NamedList& params)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SS7SCCP::segmentMessage(DataBlock& data, SS7MsgSCCP* origMsg, SS7MsgSCCP::Type type, bool local)
|
||||
// This method approximates the length of sccp address
|
||||
unsigned int SS7SCCP::getAddressLength(const NamedList& params, const String& prefix)
|
||||
{
|
||||
unsigned int length = 2; // Parameter length + Address information octet
|
||||
if (params.getParam(prefix + ".ssn"))
|
||||
length++; // One octet for ssn
|
||||
if (params.getParam(prefix + ".pointcode"))
|
||||
length += ITU() ? 2 : 3; // Pointcode has 2 octets on ITU and 3 on ANSI
|
||||
const NamedString* gtNr = YOBJECT(NamedString,params.getParam(prefix + ".gt"));
|
||||
if (!gtNr)
|
||||
return length;
|
||||
DataBlock data;
|
||||
if (!data.unHexify(*gtNr,gtNr->length(),' ')) {
|
||||
length += gtNr->length() / 2 + gtNr->length() % 2;
|
||||
} else
|
||||
length += data.length();
|
||||
const NamedString* nature = YOBJECT(NamedString,params.getParam(prefix + ".gt.nature"));
|
||||
const NamedString* translation = YOBJECT(NamedString,params.getParam(prefix + ".gt.tt"));
|
||||
const NamedString* plan = YOBJECT(NamedString,params.getParam(prefix + ".gt.np"));
|
||||
const NamedString* encoding = YOBJECT(NamedString,params.getParam(prefix + ".gt.encoding"));
|
||||
if (nature)
|
||||
length++;
|
||||
if (translation)
|
||||
length++;
|
||||
if (plan && encoding)
|
||||
length++;
|
||||
return length;
|
||||
}
|
||||
|
||||
void SS7SCCP::getMaxDataLen(const SS7MsgSCCP* msg, const SS7Label& label,
|
||||
unsigned int& udt, unsigned int& xudt, unsigned int& ludt)
|
||||
{
|
||||
if (!network()) {
|
||||
Debug(this,DebugGoOn,"No Network Attached!!!");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int maxLen = network()->getRouteMaxLength(m_type,label.dpc().pack(m_type));
|
||||
if (maxLen < 272) {
|
||||
DDebug(this,DebugInfo,"Received MSU size (%d) lower than maximum TDM!",
|
||||
maxLen);
|
||||
maxLen = 272;
|
||||
}
|
||||
bool ludtSupport = maxLen > 272; // 272 maximum msu size
|
||||
maxLen -= (label.length() + 1); // subtract label length and SIO octet
|
||||
// Now max length represents the maximum length of SCCP message
|
||||
// Adjust maxLen to represent maximum data in the message.
|
||||
unsigned int headerLength = 3; // MsgType + ProtocolClass
|
||||
// Memorize pointer start to adjust data size.
|
||||
unsigned int pointerLen = 1;
|
||||
if (msg->type() == msg->isLongDataMessage())
|
||||
pointerLen++;
|
||||
unsigned int pointersStart = headerLength;
|
||||
maxLen -= headerLength;
|
||||
// We have 3 mandatory variable parameters CallingAddress, CalledAddress,
|
||||
// and Data and the pointer to optional parameters
|
||||
headerLength += 4 * pointerLen;
|
||||
headerLength += getAddressLength(msg->params(), "CalledPartyAddress");
|
||||
headerLength += getAddressLength(msg->params(), "CallingPartyAddress");
|
||||
ludt = 0;
|
||||
unsigned int sccpParamsSize = headerLength - pointersStart;
|
||||
// 254 = 255 max data length - 1 hopcounter - 1 optional parameters pointer +
|
||||
// 1 data length indicator
|
||||
if (maxLen > 254 + sccpParamsSize)
|
||||
udt = 255;
|
||||
else
|
||||
udt = maxLen - sccpParamsSize;
|
||||
// Append optional parameters length
|
||||
headerLength += MAX_OPT_LEN;
|
||||
if (ludtSupport) {
|
||||
unsigned int maxSupported = ITU() ? 3952 : 3904;
|
||||
if (maxLen > maxSupported)
|
||||
ludt = maxSupported - sccpParamsSize;
|
||||
else
|
||||
ludt = maxLen - sccpParamsSize;
|
||||
}
|
||||
// 254 represents the maximum value that can be stored
|
||||
if (maxLen < 254)
|
||||
xudt = maxLen - sccpParamsSize;
|
||||
// Adjust data length to make sure that the pointer to optional parameters
|
||||
// is not bigger than max unsigned char value
|
||||
xudt = 254 - sccpParamsSize;
|
||||
}
|
||||
|
||||
void SS7SCCP::printMessage(const SS7MSU* msu, const SS7MsgSCCP* sccpMsg, const
|
||||
SS7Label& label) {
|
||||
|
||||
if (m_printMsg && debugAt(DebugInfo)) {
|
||||
String tmp;
|
||||
const void* data = 0;
|
||||
unsigned int len = 0;
|
||||
if (m_extendedDebug && msu) {
|
||||
unsigned int offs = label.length() + 4;
|
||||
data = msu->getData(offs);
|
||||
len = data ? msu->length() - offs : 0;
|
||||
}
|
||||
String tmp1;
|
||||
fillLabelAndReason(tmp1,label,sccpMsg);
|
||||
sccpMsg->toString(tmp,label,debugAt(DebugAll),data,len);
|
||||
Debug(this,DebugInfo,"Sending message (%p) '%s' %s %s",sccpMsg,
|
||||
SS7MsgSCCP::lookup(sccpMsg->type()),tmp1.c_str(),tmp.c_str());
|
||||
} else if (debugAt(DebugAll)) {
|
||||
String tmp;
|
||||
bool debug = fillLabelAndReason(tmp,label,sccpMsg);
|
||||
Debug(this,debug ? DebugInfo : DebugAll,"Sending message '%s' %s",
|
||||
sccpMsg->name(),tmp.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ObjList* SS7SCCP::getDataSegments(unsigned int dataLength,
|
||||
unsigned int maxSegmentSize)
|
||||
{
|
||||
DDebug(DebugAll,"getDataSegments(%u,%u)",dataLength,maxSegmentSize);
|
||||
ObjList* segments = new ObjList();
|
||||
// The first sccp segment must be the largest
|
||||
int segmentSize = maxSegmentSize - 1;
|
||||
int dataLeft = dataLength;
|
||||
unsigned int totalSent = 0;
|
||||
int sgSize = maxSegmentSize;
|
||||
if (dataLength - maxSegmentSize <= MIN_DATA_SIZE)
|
||||
sgSize = maxSegmentSize - MIN_DATA_SIZE;
|
||||
segments->append(new SS7SCCPDataSegment(0,sgSize));
|
||||
dataLeft -= sgSize;
|
||||
totalSent += sgSize;
|
||||
while (dataLeft > 0) {
|
||||
sgSize = 0;
|
||||
if ((dataLeft - segmentSize) > MIN_DATA_SIZE) { // Make sure that the left segment is longer than 2
|
||||
sgSize = segmentSize;
|
||||
} else if (dataLeft > segmentSize) {
|
||||
sgSize = segmentSize - MIN_DATA_SIZE;
|
||||
} else {
|
||||
sgSize = dataLeft;
|
||||
}
|
||||
XDebug(this,DebugAll,"Creating new data segment total send %d, segment size %d",
|
||||
totalSent,sgSize);
|
||||
segments->append(new SS7SCCPDataSegment(totalSent,sgSize));
|
||||
dataLeft -= sgSize;
|
||||
totalSent += sgSize;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
SS7SCCPDataSegment* getAndRemoveDataSegment(ObjList* obj)
|
||||
{
|
||||
if (!obj)
|
||||
return 0;
|
||||
ObjList* o = obj->skipNull();
|
||||
if (!o)
|
||||
return 0;
|
||||
SS7SCCPDataSegment* sgm = static_cast<SS7SCCPDataSegment*>(o->get());
|
||||
obj->remove(sgm,false);
|
||||
return sgm;
|
||||
}
|
||||
|
||||
int SS7SCCP::segmentMessage(SS7MsgSCCP* origMsg, const SS7Label& label, bool local)
|
||||
{
|
||||
// TODO for the moment we have set the max data length at 220
|
||||
// Verify if data lenght is between 220 and 252 | 255 and the message does not heva optional parameters
|
||||
// send a single messages
|
||||
// TODO calculate dinamically the max data length by pre-encoding the message and determine
|
||||
// the length of the addresses
|
||||
// TODO implement a better way to split the data in smaller segments
|
||||
if (!origMsg)
|
||||
return -1;
|
||||
if (data.length() > 16 * (MAX_DATA_LEN - SGM_PADDING)) {
|
||||
Debug(this,DebugMild,"Can not segment message, data to long! dataLength = %d, max data length = %d",
|
||||
data.length(),16 * MAX_DATA_LEN);
|
||||
unsigned int udtLength = 0;
|
||||
unsigned int xudtLength = 0;
|
||||
unsigned int ludtLength = 0;
|
||||
getMaxDataLen(origMsg,label,udtLength,xudtLength,ludtLength);
|
||||
unsigned int dataLen = 0;
|
||||
|
||||
DDebug(this,DebugInfo, "Got max data len : udt (%d) : xudt (%d) ludt (%d)",
|
||||
udtLength,xudtLength,ludtLength);
|
||||
if (udtLength < 2 && xudtLength < 2 && ludtLength < 2)
|
||||
return -1;
|
||||
int sls = origMsg->params().getIntValue(YSTRING("sls"),-1);
|
||||
DataBlock* data = origMsg->getData();
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
SS7MsgSCCP::Type msgType = origMsg->type();
|
||||
if (data->length() < udtLength && origMsg->canBeUDT()) {
|
||||
msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::UDT : SS7MsgSCCP::UDTS;
|
||||
dataLen = udtLength;
|
||||
} else if (data->length() < xudtLength) {
|
||||
msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::XUDT : SS7MsgSCCP::XUDTS;
|
||||
dataLen = xudtLength;
|
||||
} else if (data->length() < ludtLength) {
|
||||
msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::LUDT : SS7MsgSCCP::LUDTS;
|
||||
dataLen = ludtLength;
|
||||
} else { // Segmentation is needed!!!
|
||||
if (ludtLength > 2) { // send ludt
|
||||
msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::LUDT : SS7MsgSCCP::LUDTS;
|
||||
dataLen = ludtLength;
|
||||
} else if (xudtLength > 2) { // Send Ludt
|
||||
msgType = isSCLCMessage(msgType) ? SS7MsgSCCP::XUDT : SS7MsgSCCP::XUDTS;
|
||||
dataLen = xudtLength;
|
||||
} else {
|
||||
Debug(this,DebugWarn,
|
||||
"Unable to segment message!! Invalid data len params! XUDT data len = %d, LUDT data len = %d",
|
||||
xudtLength,ludtLength);
|
||||
}
|
||||
}
|
||||
origMsg->updateType(msgType);
|
||||
origMsg->params().clearParam(YSTRING("Segmentation"),'.');
|
||||
// Send the message if it fits in a single message
|
||||
if (data->length() < dataLen) {
|
||||
Lock lock(this);
|
||||
ajustMessageParams(origMsg->params(),origMsg->type());
|
||||
SS7MSU* msu = buildMSU(origMsg,label,false);
|
||||
if (!msu) {
|
||||
Debug(this,DebugGoOn,"Failed to build msu from sccpMessage %s",
|
||||
SS7MsgSCCP::lookup(origMsg->type()));
|
||||
return -1;
|
||||
}
|
||||
printMessage(msu,origMsg,label);
|
||||
lock.drop();
|
||||
sls = transmitMSU(*msu,label,sls);
|
||||
#ifdef DEBUG
|
||||
if (sls < 0)
|
||||
Debug(this,DebugNote,"Failed to transmit message %s. %d",
|
||||
SS7MsgSCCP::lookup(origMsg->type()),sls);
|
||||
#endif
|
||||
// CleanUp memory
|
||||
TelEngine::destruct(msu);
|
||||
return sls;
|
||||
}
|
||||
// Verify if we should bother to segment the message
|
||||
if (data->length() > 16 * (dataLen - 1)) {
|
||||
Debug(DebugNote,
|
||||
"Unable to segment SCCP message! Data length (%d) excedes max data allowed (%d)",
|
||||
data->length(),(16 * (dataLen - 1)));
|
||||
return -1;
|
||||
}
|
||||
// Start segmentation process
|
||||
lock();
|
||||
ObjList* listSegments = getDataSegments(data->length(),dataLen);
|
||||
|
||||
// Build message params
|
||||
NamedList msgData("");
|
||||
msgData.copyParams(origMsg->params());
|
||||
int hopCounter = msgData.getIntValue(YSTRING("HopCounter"),0);
|
||||
if (hopCounter < 1 || hopCounter > 15) // HopCounter is an mandatory fixed length parameter in XUDT
|
||||
msgData.setParam("HopCounter",String(m_hopCounter));
|
||||
if (ITU() && msgData.getParam(YSTRING("Importance"))) {
|
||||
int importance = msgData.getIntValue(YSTRING("Importance"));
|
||||
int temp = checkImportanceLevel(type, importance);
|
||||
if (importance != temp)
|
||||
msgData.setParam(YSTRING("Importance"),String(temp));
|
||||
}
|
||||
ajustMessageParams(msgData,msgType);
|
||||
|
||||
// Set segmentation local reference for this message
|
||||
msgData.setParam("Segmentation","");
|
||||
if (!msgData.getParam(YSTRING("Segmentation.SegmentationLocalReference")))
|
||||
msgData.setParam("Segmentation.SegmentationLocalReference",String((u_int32_t)Random::random()));
|
||||
int segments = data.length() / (MAX_DATA_LEN - SGM_PADDING);
|
||||
if (data.length() / (MAX_DATA_LEN - SGM_PADDING) != 0)
|
||||
segments++;
|
||||
int segments = listSegments->count();
|
||||
msgData.setParam("Segmentation.ProtocolClass",msgData.getValue(YSTRING("ProtocolClass")));
|
||||
if (isSCLCMessage(type))
|
||||
msgData.setParam("ProtocolClass","1"); // Segmentation is useing in sequence delivery option
|
||||
if (isSCLCMessage(msgType))
|
||||
msgData.setParam("ProtocolClass","1"); // Segmentation is using in sequence delivery option
|
||||
bool msgReturn = msgData.getBoolValue(YSTRING("MessageReturn"),false);
|
||||
int dataLength = data.length();
|
||||
int totalSent = 0;
|
||||
int sls = msgData.getIntValue(YSTRING("sls"),-1);
|
||||
sls = msgData.getIntValue(YSTRING("sls"),-1);
|
||||
|
||||
// Transmit first segment
|
||||
SS7MsgSCCP* msg = new SS7MsgSCCP(type);
|
||||
SS7MsgSCCP* msg = new SS7MsgSCCP(msgType);
|
||||
msg->params().copyParams(msgData);
|
||||
DataBlock temp;
|
||||
if (dataLength - MAX_DATA_LEN > 2)
|
||||
temp.assign(data.data(0,MAX_DATA_LEN),MAX_DATA_LEN,false);
|
||||
else
|
||||
temp.assign(data.data(0,MAX_DATA_LEN - SGM_PADDING),MAX_DATA_LEN - SGM_PADDING,false);
|
||||
SS7SCCPDataSegment* sg = getAndRemoveDataSegment(listSegments);
|
||||
if (!sg) {
|
||||
Debug(DebugStub,"Unable to extract first data segment!!!");
|
||||
TelEngine::destruct(msg);
|
||||
TelEngine::destruct(listSegments);
|
||||
return -1;
|
||||
}
|
||||
sg->fillSegment(temp,*data);
|
||||
msg->params().setParam("Segmentation.RemainingSegments",
|
||||
String(isSCLCMessage(type) ? --segments : 0));
|
||||
String(isSCLCMessage(msgType) ? --segments : 0));
|
||||
msg->params().setParam("Segmentation.FirstSegment","true");
|
||||
msg->setData(&temp);
|
||||
dataLength -= temp.length();
|
||||
totalSent += temp.length();
|
||||
DDebug(this,DebugNote,"Sending first segment sl = %d, dl = %d, ts = %d",temp.length(),dataLength,totalSent);
|
||||
unlock();
|
||||
sls = transmitMessage(msg);
|
||||
SS7MSU* msu = buildMSU(msg,label,false);
|
||||
msg->removeData();
|
||||
temp.clear(false);
|
||||
if (!msu) {
|
||||
Debug(this,DebugGoOn,"Failed to build msu from sccpMessage %s",
|
||||
SS7MsgSCCP::lookup(msgType));
|
||||
TelEngine::destruct(msg);
|
||||
TelEngine::destruct(listSegments);
|
||||
return -1;
|
||||
}
|
||||
printMessage(msu,msg,label);
|
||||
unlock();
|
||||
sls = transmitMSU(*msu,label,sls);
|
||||
#ifdef DEBUG
|
||||
if (sls < 0)
|
||||
Debug(this,DebugNote,"Failed to transmit message %s. %d",
|
||||
SS7MsgSCCP::lookup(msgType),sls);
|
||||
#endif
|
||||
TelEngine::destruct(msu);
|
||||
TelEngine::destruct(msg);
|
||||
TelEngine::destruct(sg);
|
||||
if (sls < 0) {
|
||||
if (msgReturn && !local)
|
||||
returnMessage(origMsg,MtpFailure);
|
||||
Debug(this,DebugNote,"Failed to transmit first segment of message");
|
||||
TelEngine::destruct(listSegments);
|
||||
return sls;
|
||||
}
|
||||
if (isSCLCSMessage(type))
|
||||
if (isSCLCSMessage(msgType)) {
|
||||
TelEngine::destruct(listSegments);
|
||||
return sls;
|
||||
}
|
||||
lock();
|
||||
msgData.setParam("Segmentation.FirstSegment","false");
|
||||
// Set message return option only for the first segment
|
||||
msgData.setParam("MessageReturn","false");
|
||||
while (dataLength > 0) {
|
||||
msg = new SS7MsgSCCP(type);
|
||||
while ((sg = getAndRemoveDataSegment(listSegments))) {
|
||||
msg = new SS7MsgSCCP(msgType);
|
||||
msg->params().copyParams(msgData);
|
||||
if (dataLength - MAX_DATA_LEN - SGM_PADDING > 2) // Make shure that the left segment is longer than 2
|
||||
temp.assign(data.data(totalSent,MAX_DATA_LEN - SGM_PADDING),MAX_DATA_LEN - SGM_PADDING,false);
|
||||
else if (dataLength - MAX_DATA_LEN - 2 * SGM_PADDING > 2)
|
||||
temp.assign(data.data(totalSent,MAX_DATA_LEN - 2* SGM_PADDING),MAX_DATA_LEN - 2* SGM_PADDING,false);
|
||||
else
|
||||
temp.assign(data.data(totalSent,dataLength),dataLength,false); // Should be last segment
|
||||
sg->fillSegment(temp,*data);
|
||||
TelEngine::destruct(sg);
|
||||
msg->params().setParam("Segmentation.RemainingSegments",String(--segments));
|
||||
msg->setData(&temp);
|
||||
dataLength -= temp.length();
|
||||
totalSent += temp.length();
|
||||
DDebug(this,DebugNote,"Sending segment: %d sl = %d, dl = %d, ts = %d",segments,temp.length(),dataLength,totalSent);
|
||||
unlock();
|
||||
sls = transmitMessage(msg);
|
||||
SS7MSU* msu = buildMSU(msg,label,false);
|
||||
msg->removeData();
|
||||
temp.clear(false);
|
||||
if (!msu) {
|
||||
Debug(this,DebugGoOn,"Failed to build msu from sccpMessage %s",
|
||||
SS7MsgSCCP::lookup(msgType));
|
||||
TelEngine::destruct(msg);
|
||||
TelEngine::destruct(listSegments);
|
||||
return -1;
|
||||
}
|
||||
printMessage(msu,msg,label);
|
||||
unlock();
|
||||
sls = transmitMSU(*msu,label,sls);
|
||||
#ifdef DEBUG
|
||||
if (sls < 0)
|
||||
Debug(this,DebugNote,"Failed to transmit message %s. %d",
|
||||
SS7MsgSCCP::lookup(msgType),sls);
|
||||
#endif
|
||||
TelEngine::destruct(msg);
|
||||
TelEngine::destruct(msu);
|
||||
if (sls < 0) {
|
||||
if (msgReturn && !local)
|
||||
returnMessage(origMsg,MtpFailure);
|
||||
Debug(this,DebugNote,"Failed to transmit segment of %s message remaining segments %d",
|
||||
SS7MsgSCCP::lookup(origMsg->type()),segments);
|
||||
SS7MsgSCCP::lookup(msgType),segments);
|
||||
return sls;
|
||||
}
|
||||
lock();
|
||||
}
|
||||
if (segments != 0)
|
||||
Debug(this,DebugStub,"Bug in segment messsage!! RemainingSegments %d",segments);
|
||||
Debug(this,DebugStub,"Bug in segment message!! RemainingSegments %d",segments);
|
||||
TelEngine::destruct(listSegments);
|
||||
unlock();
|
||||
return sls;
|
||||
}
|
||||
|
@ -3311,7 +3497,7 @@ SS7MsgSccpReassemble::Return SS7SCCP::reassembleSegment(SS7MsgSCCP* segment,
|
|||
return ret;
|
||||
}
|
||||
|
||||
SS7MSU* SS7SCCP::buildMSU(SS7MsgSCCP* msg, const SS7Label& label) const
|
||||
SS7MSU* SS7SCCP::buildMSU(SS7MsgSCCP* msg, const SS7Label& label, bool checkLength) const
|
||||
{
|
||||
// see what mandatory parameters we should put in this message
|
||||
const MsgParams* msgParams = getSccpParams(msg->type());
|
||||
|
@ -3341,7 +3527,7 @@ SS7MSU* SS7SCCP::buildMSU(SS7MsgSCCP* msg, const SS7Label& label) const
|
|||
}
|
||||
len += param->size;
|
||||
}
|
||||
bool ludt = msg->type() == SS7MsgSCCP::LUDT;
|
||||
bool ludt = msg->isLongDataMessage();
|
||||
int pointerLen = ludt ? 2 : 1;
|
||||
// initialize the pointer array offset just past the mandatory fixed part
|
||||
unsigned int ptr = label.length() + 1 + len;
|
||||
|
@ -3395,9 +3581,18 @@ SS7MSU* SS7SCCP::buildMSU(SS7MsgSCCP* msg, const SS7Label& label) const
|
|||
// remember the offset this parameter will actually get stored
|
||||
len = msu->length();
|
||||
unsigned int size = 0;
|
||||
if (ptype == SS7MsgSCCP::Data || ptype == SS7MsgSCCP::LongData)
|
||||
if (ptype == SS7MsgSCCP::Data || ptype == SS7MsgSCCP::LongData) {
|
||||
size = encodeData(this,*msu,msg);
|
||||
else
|
||||
if (ptype == SS7MsgSCCP::Data) {
|
||||
// Data parameter is the last of variable mandatory parameters
|
||||
// Check if the pointer to variable part may be bigger than 255
|
||||
// (max unsigned char value)
|
||||
if (checkLength && ((len + size + MAX_OPT_LEN) > 254)) {
|
||||
TelEngine::destruct(msu);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
size = encodeParam(this,*msu,param,&msg->params(),exclude,prefix);
|
||||
d = msu->getData(0,len+1);
|
||||
if (!(size && d)) {
|
||||
|
@ -3456,8 +3651,19 @@ SS7MSU* SS7SCCP::buildMSU(SS7MsgSCCP* msg, const SS7Label& label) const
|
|||
storedLength --;
|
||||
d[ptr] = storedLength & 0xff;
|
||||
d[ptr+1] = storedLength >> 8;
|
||||
} else
|
||||
} else {
|
||||
// Do not try to set the pointer to optional parameters
|
||||
// if is bigger than max unsigned char value because will
|
||||
// result in a malformed packet!
|
||||
if (storedLength > 255) {
|
||||
Debug(this,checkLength ? DebugAll : DebugStub,
|
||||
"Build MSU the pointer to optional parameters is bigger than 255!!!! %d",
|
||||
storedLength);
|
||||
TelEngine::destruct(msu);
|
||||
return 0;
|
||||
}
|
||||
d[ptr] = storedLength;
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
@ -3547,6 +3753,7 @@ bool SS7SCCP::processMSU(SS7MsgSCCP::Type type, const unsigned char* paramPtr,
|
|||
m_totalReceived++;
|
||||
int protocolClass = msg->params().getIntValue(YSTRING("ProtocolClass"), -1);
|
||||
if (isSCOCMsg(msg->type())) {
|
||||
Debug(DebugWarn,"Received Connection oriented message!!");
|
||||
if (msg->type() != SS7MsgSCCP::CR) { // Received Connection Oriented message other than Connect Request
|
||||
// Drop the message
|
||||
DDebug(this,DebugNote,"Received message %s without a connection!",SS7MsgSCCP::lookup(msg->type()));
|
||||
|
@ -3930,7 +4137,7 @@ bool SS7SCCP::decodeMessage(SS7MsgSCCP* msg, SS7PointCode::Type pcType,
|
|||
paramLen -= param->size;
|
||||
} // while ((ptype = *plist++)...
|
||||
bool mustWarn = true;
|
||||
bool ludt = msg->type() == SS7MsgSCCP::LUDT;
|
||||
bool ludt = msg->isLongDataMessage();
|
||||
// next decode any mandatory variable parameters the message should have
|
||||
while ((ptype = *plist++) != SS7MsgSCCP::EndOfParameters) {
|
||||
mustWarn = false;
|
||||
|
|
|
@ -5756,12 +5756,17 @@ public:
|
|||
/**
|
||||
* Constructor
|
||||
* @param packed The packed value of the destination point code
|
||||
* @param type The destination point code type
|
||||
* @param priority Optional value of the network priority
|
||||
* @param shift SLS right shift to apply for balancing between linksets
|
||||
* @param maxDataLength The maximum data that can be transported on this
|
||||
* route
|
||||
*/
|
||||
inline SS7Route(unsigned int packed, unsigned int priority = 0, unsigned int shift = 0)
|
||||
: Mutex(true,"SS7Route"),
|
||||
m_packed(packed), m_priority(priority), m_shift(shift),
|
||||
inline SS7Route(unsigned int packed, SS7PointCode::Type type,
|
||||
unsigned int priority = 0, unsigned int shift = 0,
|
||||
unsigned int maxDataLength = 272)
|
||||
: Mutex(true,"SS7Route"), m_packed(packed), m_type(type),
|
||||
m_priority(priority), m_shift(shift),m_maxDataLength(maxDataLength),
|
||||
m_state(Unknown),m_buffering(0), m_congCount(0),m_congBytes(0)
|
||||
{ m_networks.setDelete(false); }
|
||||
|
||||
|
@ -5770,10 +5775,10 @@ public:
|
|||
* @param original The original route
|
||||
*/
|
||||
inline SS7Route(const SS7Route& original)
|
||||
: Mutex(true,"SS7Route"),
|
||||
m_packed(original.packed()), m_priority(original.priority()),
|
||||
m_shift(original.shift()), m_state(original.state()),
|
||||
m_buffering(0), m_congCount(0), m_congBytes(0)
|
||||
: Mutex(true,"SS7Route"), m_packed(original.packed()),
|
||||
m_type(original.m_type), m_priority(original.priority()),
|
||||
m_shift(original.shift()), m_maxDataLength(original.getMaxDataLength()),
|
||||
m_state(original.state()), m_buffering(0), m_congCount(0), m_congBytes(0)
|
||||
{ m_networks.setDelete(false); }
|
||||
|
||||
/**
|
||||
|
@ -5817,6 +5822,13 @@ public:
|
|||
unsigned int priority() const
|
||||
{ return m_priority; }
|
||||
|
||||
/**
|
||||
* Get the maximum data length that can be transported on this route
|
||||
* @return The maximum data length
|
||||
*/
|
||||
unsigned int getMaxDataLength() const
|
||||
{ return m_maxDataLength; }
|
||||
|
||||
/**
|
||||
* Get the packed Point Code of this route
|
||||
* @return Packed Point Code of the route's destination
|
||||
|
@ -5899,8 +5911,10 @@ private:
|
|||
void rerouteCheck(u_int64_t when);
|
||||
void rerouteFlush();
|
||||
unsigned int m_packed; // Packed destination point code
|
||||
SS7PointCode::Type m_type; // The point code type
|
||||
unsigned int m_priority; // Network priority for the given destination (used by SS7Layer3)
|
||||
unsigned int m_shift; // SLS right shift when selecting linkset
|
||||
unsigned int m_maxDataLength; // The maximum data length that can be transported on this route
|
||||
ObjList m_networks; // List of networks used to route to the given destination (used by SS7Router)
|
||||
State m_state; // State of the route
|
||||
u_int64_t m_buffering; // Time when controlled rerouting ends
|
||||
|
@ -6001,6 +6015,7 @@ class YSIG_API SS7Layer3 : virtual public SignallingComponent
|
|||
YCLASS(SS7Layer3,SignallingComponent)
|
||||
friend class SS7L3User;
|
||||
friend class SS7Router; // Access the data members to build the routing table
|
||||
friend class SS7Route;
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
|
@ -6176,6 +6191,15 @@ public:
|
|||
*/
|
||||
bool buildRoutes(const NamedList& params);
|
||||
|
||||
/**
|
||||
* Get the maximum data length of a route by packed Point Code.
|
||||
* This method is thread safe
|
||||
* @param type Destination point code type
|
||||
* @param packedPC The packed point code
|
||||
* @return The maximum data length that can be transported on the route. Maximum msu size (272) if no route to the given point code
|
||||
*/
|
||||
unsigned int getRouteMaxLength(SS7PointCode::Type type, unsigned int packedPC);
|
||||
|
||||
/**
|
||||
* Get the priority of a route by packed Point Code.
|
||||
* This method is thread safe
|
||||
|
@ -9435,6 +9459,30 @@ public:
|
|||
inline Type type() const
|
||||
{ return m_type; }
|
||||
|
||||
/**
|
||||
* Helper method to change the message type
|
||||
* @param type The new message type
|
||||
*/
|
||||
inline void updateType(Type type)
|
||||
{ m_type = type; params().assign(lookup(type,"Unknown")); }
|
||||
|
||||
/**
|
||||
* Utility method to verify if this message is a long unit data
|
||||
* @return True if this message is a long unit data
|
||||
*/
|
||||
inline bool isLongDataMessage() const
|
||||
{ return m_type == LUDT || m_type == LUDTS; }
|
||||
|
||||
/**
|
||||
* Utility method to verify if this message can be a UDT message
|
||||
* A SCCP message can be an UDT message if it not contains HopCounter parameter
|
||||
* or other optional parameters
|
||||
* @return True if this message can be a UDT message
|
||||
*/
|
||||
inline bool canBeUDT() const
|
||||
{ return !(params().getParam(YSTRING("Importance")) ||
|
||||
params().getParam(YSTRING("HopCounter"))); }
|
||||
|
||||
/**
|
||||
* Fill a string with this message's parameters for debug purposes
|
||||
* @param dest The destination string
|
||||
|
@ -10030,6 +10078,41 @@ public:
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class to memorize SCCP data segments
|
||||
*/
|
||||
class SS7SCCPDataSegment : public GenObject
|
||||
{
|
||||
YCLASS(SS7SCCPDataSegment,GenObject)
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param index The index in the original DataBlock where this segment starts
|
||||
* @param length The length of this segment
|
||||
*/
|
||||
inline SS7SCCPDataSegment(unsigned int index, unsigned int length)
|
||||
: m_length(length), m_index(index)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~SS7SCCPDataSegment()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Assignees to a DataBlock this segment's data
|
||||
* @param temp The destination DataBlock segment
|
||||
* @param orig The original DataBlock where this segment is located
|
||||
*/
|
||||
inline void fillSegment(DataBlock& temp, const DataBlock& orig)
|
||||
{ temp.assign(orig.data(m_index,m_length),m_length,false); }
|
||||
|
||||
private:
|
||||
unsigned int m_length;
|
||||
unsigned int m_index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of SS7 Signalling Connection Control Part
|
||||
* @short SS7 SCCP implementation
|
||||
|
@ -10148,20 +10231,12 @@ public:
|
|||
|
||||
/**
|
||||
* Message changeover procedure for segmentation purpose
|
||||
* @param data The message data
|
||||
* @param origMsg The original message
|
||||
* @param type The destination message type
|
||||
* @param label MTP3 routing label
|
||||
* @param local True if the origMsg is local initiated
|
||||
* @return Negative value if the message failed to be sent
|
||||
*/
|
||||
int segmentMessage(DataBlock& data, SS7MsgSCCP* origMsg, SS7MsgSCCP::Type type, bool local = false);
|
||||
|
||||
/**
|
||||
* Check if we can send LUDT messages
|
||||
* @param label The SS7 routing label
|
||||
* @return True if we can send LUDT messages
|
||||
*/
|
||||
bool canSendLUDT(const SS7Label& label);
|
||||
int segmentMessage(SS7MsgSCCP* origMsg, const SS7Label& label, bool local);
|
||||
|
||||
/**
|
||||
* Helper method to know if we use ITU or ANSI
|
||||
|
@ -10282,6 +10357,18 @@ protected:
|
|||
virtual bool isEndpoint()
|
||||
{ return m_endpoint; }
|
||||
private:
|
||||
// Helper method to calculate sccp address length
|
||||
unsigned int getAddressLength(const NamedList& params, const String& prefix);
|
||||
// Helper method used to ajust HopCounter and Importance parameters
|
||||
void ajustMessageParams(NamedList& params, SS7MsgSCCP::Type type);
|
||||
// Obtain maximum data length for a UDT, XUDT and LUDT message
|
||||
void getMaxDataLen(const SS7MsgSCCP* msg, const SS7Label& label,
|
||||
unsigned int& udtLength, unsigned int& xudtLength, unsigned int& ludtLength);
|
||||
// Helper method to obtain data segments
|
||||
// NOTE The list must be destroyed
|
||||
ObjList* getDataSegments(unsigned int dataLength, unsigned int maxSegmentSize);
|
||||
// Helper method to print a SCCP message
|
||||
void printMessage(const SS7MSU* msu, const SS7MsgSCCP* msg, const SS7Label& label);
|
||||
// Helper method used to extract the pointcode from Calling/Called party address.
|
||||
// Also will call GT translate if there is no pointcode in called party address
|
||||
bool fillPointCode(SS7PointCode& pointcode, SS7MsgSCCP* msg, const String& prefix, const char* pCode, bool translate);
|
||||
|
@ -10318,7 +10405,7 @@ private:
|
|||
void printStatus(bool extended);
|
||||
void setNetworkUp(bool operational);
|
||||
|
||||
SS7MSU* buildMSU(SS7MsgSCCP* msg, const SS7Label& label) const;
|
||||
SS7MSU* buildMSU(SS7MsgSCCP* msg, const SS7Label& label, bool checkLength = true) const;
|
||||
bool routeSCLCMessage(SS7MsgSCCP*& msg, const SS7Label& label);
|
||||
// Member data
|
||||
SS7PointCode::Type m_type; // Point code type of this SCCP
|
||||
|
@ -10330,7 +10417,7 @@ private:
|
|||
u_int32_t m_segTimeout; // Time in milliseconds for segmentation timeout
|
||||
bool m_ignoreUnkDigits; // Check if GT digit parser of should ignore unknown digits encoding
|
||||
bool m_layer3Up; // Flag used to verify if the network is operational
|
||||
bool m_supportLongData; // Flag used to check if this sccp can send LUDT messages
|
||||
unsigned int m_maxUdtLength; // The maximum length of data packet transported in a UDT message
|
||||
u_int32_t m_totalSent; // Counter of the total number of SCCP messages sent
|
||||
u_int32_t m_totalReceived; // The number of incoming sccp messages
|
||||
u_int32_t m_errors; // Counter of the number of messages that failed to be delivered
|
||||
|
|
Loading…
Reference in New Issue