yate/libs/ysig/testpart.cpp

236 lines
6.4 KiB
C++
Raw Normal View History

/**
* testpart.cpp
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2010 Null Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "yatesig.h"
#include <yatephone.h>
using namespace TelEngine;
#define CMD_STOP 0
#define CMD_SINGLE 1
#define CMD_START 2
#define CMD_RESET 3
// Control operations
static const TokenDict s_dict_control[] = {
{ "stop", CMD_STOP, },
{ "single", CMD_SINGLE, },
{ "start", CMD_START, },
{ "reset", CMD_RESET, },
{ 0, 0 }
};
HandledMSU SS7Testing::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
{
if (msu.getSIF() != sif())
return HandledMSU::Rejected;
String src;
int lvl = DebugNote;
if (m_lbl.type() != SS7PointCode::Other) {
if (label.type() != m_lbl.type())
return HandledMSU::Unequipped;
if (label.opc() == m_lbl.opc() && label.dpc() == m_lbl.dpc()) {
src = "MYSELF!";
lvl = DebugWarn;
}
else if (label.dpc() != m_lbl.opc())
return HandledMSU::Unequipped;
}
if (src.null())
src << SS7PointCode::lookup(label.type()) << ":" << label.opc();
XDebug(this,DebugStub,"Possibly incomplete SS7Testing::receivedMSU(%p,%p,%p,%d) [%p]",
&msu,&label,network,sls,this);
// Q.782 2.3: 4 bytes message number, 2 bytes length (9 bits used), N bytes zeros
const unsigned char* s = msu.getData(label,6);
if (!s)
return false;
u_int32_t seq = s[0] + ((u_int32_t)s[1] << 8) +
((u_int32_t)s[2] << 16) + ((u_int32_t)s[3] << 24);
u_int16_t len = s[4] + ((u_int16_t)s[5] << 8);
const unsigned char* t = msu.getData(label.length()+6,len);
if (!t) {
if (lvl > DebugMild)
lvl = DebugMild;
Debug(this,lvl,"Received MTP_T from %s, seq %u, length %u with invalid test length %u [%p]",
src.c_str(),seq,msu.length(),len,this);
return false;
}
Debug(this,lvl,"Received MTP_T from %s, seq %u, test length %u",
src.c_str(),seq,len);
return true;
}
bool SS7Testing::sendTraffic()
{
if (!m_lbl.length())
return false;
u_int32_t seq = m_seq++;
u_int16_t len = m_len + 6;
SS7MSU msu(sio(),m_lbl,0,len);
unsigned char* d = msu.getData(m_lbl,len);
if (!d)
return false;
for (unsigned int i = 0; i < 4; i++)
*d++ = 0xff & (seq >> (8 * i));
*d++ = m_len & 0xff;
*d++ = (m_len >> 8) & 0xff;
Debug(this,DebugInfo,"Sending MTP_T seq %u, test length %u",seq,m_len);
return transmitMSU(msu,m_lbl,m_lbl.sls()) >= 0;
}
void SS7Testing::notify(SS7Layer3* network, int sls)
{
Debug(this,DebugStub,"Please implement SS7Testing::notify(%p,%d) [%p]",
network,sls,this);
}
void SS7Testing::timerTick(const Time& when)
{
Lock mylock(this);
if (!m_timer.timeout(when.msec()))
return;
m_timer.start(when.msec());
sendTraffic();
}
bool SS7Testing::initialize(const NamedList* config)
{
if (!config)
return true;
Lock engLock(engine());
Lock mylock(this);
setParams(*config);
bool ok = SS7Layer4::initialize(config);
if (ok && config->getBoolValue("autostart",false)) {
if (m_timer.interval() && m_lbl.length())
m_timer.start();
sendTraffic();
}
return ok;
}
bool SS7Testing::control(NamedList& params)
{
String* ret = params.getParam("completion");
const String* oper = params.getParam("operation");
const char* cmp = params.getValue("component");
int cmd = oper ? oper->toInteger(s_dict_control,-1) : -1;
if (ret) {
if (oper && (cmd < 0))
return false;
String part = params.getValue("partword");
if (cmp) {
if (toString() != cmp)
return false;
for (const TokenDict* d = s_dict_control; d->token; d++)
Module::itemComplete(*ret,d->token,part);
return true;
}
return Module::itemComplete(*ret,toString(),part);
}
if (!(cmp && toString() == cmp))
return false;
if (cmd >= 0) {
Lock mylock(this);
setParams(params,true);
switch (cmd) {
case CMD_STOP:
m_timer.stop();
return true;
case CMD_START:
if (!(m_timer.interval() && m_lbl.length()))
return false;
m_timer.start();
return sendTraffic();
case CMD_SINGLE:
if (!m_lbl.length())
return false;
m_timer.stop();
return sendTraffic();
case CMD_RESET:
m_timer.stop();
m_lbl.assign(SS7PointCode::Other,m_lbl.opc(),m_lbl.dpc(),m_lbl.sls());
return true;
}
}
return SignallingComponent::control(params);
}
void SS7Testing::setParams(const NamedList& params, bool setSeq)
{
m_timer.interval(params,"interval",20,500,true);
m_len = params.getIntValue("length",m_len);
if (m_len > 1024)
m_len = 1024;
if (setSeq || !m_seq)
m_seq = params.getIntValue("sequence",m_seq);
const String* lbl = params.getParam("address");
if (!TelEngine::null(lbl)) {
// TYPE,opc,dpc,sls,spare
SS7PointCode::Type t = SS7PointCode::Other;
ObjList* l = lbl->split(',');
const GenObject* o = l->at(0);
if (o) {
t = SS7PointCode::lookup(o->toString());
if (t == SS7PointCode::Other)
t = m_lbl.type();
}
if (t != SS7PointCode::Other) {
o = l->at(1);
if (o) {
SS7PointCode c(m_lbl.opc());
if (c.assign(o->toString(),t))
m_lbl.assign(t,m_lbl.dpc(),c,m_lbl.sls(),m_lbl.spare());
}
o = l->at(2);
if (o) {
SS7PointCode c(m_lbl.dpc());
if (c.assign(o->toString(),t))
m_lbl.assign(t,c,m_lbl.opc(),m_lbl.sls(),m_lbl.spare());
}
o = l->at(3);
if (o) {
int sls = o->toString().toInteger(-1);
if (sls >= 0)
m_lbl.setSls(sls);
}
o = l->at(4);
if (o) {
int spare = o->toString().toInteger(-1);
if (spare >= 0)
m_lbl.setSpare(spare);
}
}
delete l;
}
}
/* vi: set ts=8 sw=4 sts=4 noet: */