gateway module for sems (Isdn and someday hopefully h323 also)

initial version.



git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@1137 8eb893ce-cfd4-0310-b710-fb5ebe64c474
sayer/1.4-spce2.6
Grzegorz Stanislawski 17 years ago
parent 841b2f663f
commit c97003fc76

@ -0,0 +1,147 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "globals.h"
#include "GWSession.h"
#include "AmMediaProcessor.h"
#include "AmApi.h"
#include "AmUAC.h"
#include "AmSession.h"
#include "AmSessionContainer.h"
#include "ampi/UACAuthAPI.h"
#include "GatewayFactory.h"
#include "log.h"
#include"mISDNChannel.h"
GWSession::GWSession(const string& auth_realm, const string& auth_user, const string& auth_pwd) :
credentials(auth_realm, auth_user, auth_pwd) {
DBG("new GWSession@%p\n", this);
}
UACAuthCred* GWSession::getCredentials() {
return &credentials;
}
void GWSession::setOtherLeg(AmAudio *otherleg) {
m_OtherLeg=otherleg;
}
void GWSession::onInvite(const AmSipRequest& req) {
DBG("GWSession::onInvite\n");
// rtp_str.setMonitorRTPTimeout(false);
invite_req=req;
return;
}
void GWSession::onSessionStart(const AmSipRequest& req) {
DBG("GWSession::onSessionStart\n");
try {
string sdp_reply;
acceptAudio(req.body,req.hdrs,&sdp_reply);
if(dlg.reply(req,200,"OK Isdn side state is: CONNECTED", "application/sdp",sdp_reply) != 0)
throw AmSession::Exception(500,"could not send response");
}catch(const AmSession::Exception& e){
ERROR("%i %s\n",e.code,e.reason.c_str());
setStopped();
AmSipDialog::reply_error(req,e.code,e.reason);
return;
}
DBG("GWSession::onSessionStart Setting Audio\n");
setInOut((AmAudio *)(m_OtherLeg),(AmAudio *)(m_OtherLeg));
AmSession::onSessionStart(req);
AmMediaProcessor::instance()->addSession(this, callgroup);
}
void GWSession::onSessionStart(const AmSipReply& reply) {
DBG("GWSession::onSessionStart(reply)\n");
DBG("calling ((mISDNChannel*)m_otherleg)->accept();\n");
int ret=((mISDNChannel*)m_OtherLeg)->accept();
DBG("GWSession::onSessionStart Setting Audio\n");
setInOut((AmAudio *)(m_OtherLeg),(AmAudio *)(m_OtherLeg));
AmSession::onSessionStart(reply);
}
void GWSession::onBye(const AmSipRequest& req) {
DBG("GWSession::onBye\n");
int ret=((mISDNChannel*)m_OtherLeg)->hangup();
AmSession::onBye(req);
}
void GWSession::onCancel() {
DBG("GWSession::onCancel\n");
int ret=((mISDNChannel*)m_OtherLeg)->hangup();
AmSession::onCancel();
}
GWSession::~GWSession()
{
INFO("destroying GWSession!\n");
}
// we just need a hack this function for INVITE as orginal executes onSessionStart imediately after OnInvite
void GWSession::onSipRequest(const AmSipRequest& req)
{
DBG("GWSession::onSipRequest check 1\n");
if(req.method == "INVITE"){
dlg.updateStatus(req);
onInvite(req);
} else {
DBG("GWSession::onSipRequest calling parent\n");
AmSession::onSipRequest(req);
}
}
void GWSession::onSipReply(const AmSipReply& reply) {
int status = dlg.getStatus();
DBG("GWSession::onSipReply: code = %i, reason = %s\n, status = %i\n", reply.code,reply.reason.c_str(),dlg.getStatus());
if((dlg.getStatus()==AmSipDialog::Pending)&&(reply.code==183)) { onProgress(reply); }
if((dlg.getStatus()==AmSipDialog::Pending)&&(reply.code>=300)) {
int ret=((mISDNChannel*)m_OtherLeg)->hangup();
}
DBG("GWSession::onSipReply calling parent\n");
AmSession::onSipReply(reply);
}
void GWSession::on_stop() {
DBG("GWSession::on_stop\n");
if (!getDetached())
AmMediaProcessor::instance()->clearSession(this);
else
clearAudio();
}
void GWSession::onRinging(const AmSipReply& reply) {
DBG("GWSession::onRinging\n");
//TODO
}
void GWSession::onProgress(const AmSipReply& reply){
DBG("GWSession::onProgress\n");
//TODO
}
GWSession* GWSession::CallFromOutside(std::string &fromnumber, std::string &tonumber, int backend, AmAudio* chan) {
AmArg* c_args = new AmArg();
std::string user=gwconf.getParameter("auth_user","");
std::string r_uri="sip:@";
r_uri.insert(4,tonumber);r_uri.append(gwconf.getParameter("calleddomain",""));
std::string from="sip:@";
from.insert(4,fromnumber);from.append(gwconf.getParameter("callerdomain",""));
std::string from_uri="sip:@";
from_uri.insert(4,fromnumber);from_uri.append(gwconf.getParameter("callerdomain",""));
std::string to="sip:@";
to.insert(4,tonumber);to.append(gwconf.getParameter("calleddomain",""));
DBG ("GWSession::CallFromOutside user=%s r_uri=%s from=%s to=%s\n",user.c_str(),r_uri.c_str(),from.c_str(),to.c_str());
AmSession* s = AmUAC::dialout(user, //user
"gateway", //app_name
r_uri, //r_uri
from, //from
from_uri , //from_uri
to, //to
string(""), // local_tag (callid)
string(""), // headers
c_args);
DBG("GWCall::CallFromOutside session=%p\n",s);
//this is static function so we dont that 'this' pointer yet as GWcall object is created in factory::onInvite. so we use pointer returned by dialout
((GWSession*)s)->setOtherLeg(chan);
//for early media?
// ((GWSession*)s)->setInOut(chan,chan);
return (GWSession *)s;
}

@ -0,0 +1,47 @@
#ifndef _ISDNGATEWAYDIALOG_H_
#define _ISDNGATEWAYDIALOG_H_
#include "AmApi.h"
#include "AmSession.h"
#include "ampi/UACAuthAPI.h"
class GWSession : public AmSession, public CredentialHolder
{
public:
GWSession(const string& auth_realm, const string& auth_user, const string& auth_pwd);
~GWSession();
inline UACAuthCred* getCredentials(); //auth interface
AmSipRequest invite_req;
static GWSession* CallFromOutside(std::string &fromnumber, std::string &tonumber, int backend, AmAudio* device);
void setOtherLeg(AmAudio *otherleg);
void onProgress(const AmSipReply& reply);
//Parent methods
//virtual void process(AmEvent* ev);
//virtual AmPayloadProviderInterface* getPayloadProvider();
//virtual void negotiate(const string& sdp_body,
//virtual void onDtmf(int event, int duration);
//virtual void onStart(){}
void onInvite(const AmSipRequest& req);
void onCancel();
void onSessionStart(const AmSipRequest& req);
void onSessionStart(const AmSipReply& reply);
//virtual void onEarlySessionStart(const AmSipReply& reply){}
void onRinging(const AmSipReply& reply);
void onBye(const AmSipRequest& req);
//virtual void onSipEvent(AmSipEvent* sip_ev);
void onSipRequest(const AmSipRequest& req);
void onSipReply(const AmSipReply& reply);
//virtual void onRtpTimeout();
//virtual void onSendRequest(const string& method, const string& content_type, const string& body, string& hdrs, int flags, unsigned int cseq);
//virtual void onSendReply(const AmSipRequest& req, unsigned int code,const string& reason,const string& content_type, const string& body,string& hdrs,int flags)
void on_stop();
private:
UACAuthCred credentials;
AmAudio *m_OtherLeg;
};
#endif

@ -0,0 +1,93 @@
#include "GatewayFactory.h"
#include "GWSession.h"
#include "mISDNStack.h"
#include "AmUtils.h"
#include "log.h"
EXPORT_SESSION_FACTORY(GatewayFactory,MODULE_NAME);
AmConfigReader gwconf;
GatewayFactory::GatewayFactory(const string& _app_name)
: AmSessionFactory(_app_name)
{
INFO("GatewayFactory constructor\n");
if(mISDNStack::GetPortInfo()!=OK) {
ERROR("mISDNStack::GetPortInfo failed");
return;
}
if(!mISDNStack::instance()){
ERROR("mISDN stack not initialized.\n");
return;
}
}
int GatewayFactory::onLoad()
{
INFO("gateway version %s loading (mISDN) ...\n", GW_VERSION);
if (gwconf.loadFile(AmConfig::ModConfigPath + string(MODULE_NAME)+ ".conf")) {
// if (gwconf.loadFile(AmConfig::ModConfigPath +"gateway.conf")) {
DBG("cant load conf file %s/%s.conf\n",AmConfig::ModConfigPath.c_str(),MODULE_NAME);
exit(-1);
}
configureModule(gwconf);
auth_enable = (gwconf.getParameter("auth_enable", "no")=="yes");
auth_realm = gwconf.getParameter("auth_realm", "");
auth_user = gwconf.getParameter("auth_user", "");
auth_pwd = gwconf.getParameter("auth_pwd", "");
if(auth_enable) {
uac_auth_f = AmPlugIn::instance()->getFactory4Seh("uac_auth");
DBG("uac_auth_f == 0x%.16lX\n",(unsigned long)uac_auth_f);
} else uac_auth_f=NULL;
return 0;
}
AmSession* GatewayFactory::onInvite(const AmSipRequest& req)
{
INFO("IsdnGatewayFactory::onInvite()\n");
if (req.user.empty())
throw AmSession::Exception(500,"gateway: internal error, user is empty\n");
DBG("received onInvite for outgoing call!\n");
GWSession* session=new GWSession(auth_realm,auth_user,auth_pwd);
// if (uac_auth_f != NULL) {
// DBG("UAC Auth enabled for session.\n");
// AmSessionEventHandler* h = uac_auth_f->getHandler(session);
// if (h != NULL ) session->addHandler(h);
// }
DBG("calling (mISDNStack::instance())->placeCall(req, session, tonumber, fromnumber);\n");
int ret=(mISDNStack::instance())->placeCall(req, session, req.user, req.from);
if(ret==FAIL) {
ERROR("mISDNStack::placeCall failed\n");
return NULL;
}
DBG("now returning GatewayDialog\n");
return session;
}
// this is session creator for incoming calls
//call actually starts in isdn module as CC_SETUP, and there GWSession::CallFromOutSide is executed
// which calls AmUac::dialout which in turn calls this function
//session pointer is returned back so we can finish filling object with data there
AmSession* GatewayFactory::onInvite(const AmSipRequest& req, AmArg& session_params)
{
INFO("GatewayFactory::onInvite(with args)\n");
// GWCall* call = new GWCall();
GWSession* session=new GWSession(auth_realm,auth_user,auth_pwd);
DBG("GatewayFactory::onInvite(with args) session=%p\n",session);
if (uac_auth_f != NULL) {
DBG("UAC Auth enabled for session.\n");
AmSessionEventHandler* h = uac_auth_f->getHandler(session);
if (h != NULL ) session->addHandler(h);
}
return session;
}
GatewayFactory::~GatewayFactory()
{
DBG("gateway: destructor of GatewayFactory: cleaning up.\n");
// mISDNStack::instance()->shutdown();
delete(mISDNStack::instance());
}

@ -0,0 +1,31 @@
#ifndef _ISDNGATEWAYFACTORY_H_
#define _ISDNGATEWAYFACTORY_H_
#include "GWSession.h"
#include "AmConfigReader.h"
#include <string>
using std::string;
class GatewayFactory: public AmSessionFactory
{
public:
GatewayFactory(const string& _app_name);
~GatewayFactory();
//Auth api
AmSessionEventHandlerFactory* uac_auth_f;
int onLoad();
AmSession* onInvite(const AmSipRequest& req);
AmSession* onInvite(const AmSipRequest& req, AmArg& session_params);
private:
static GatewayFactory* _instance;
bool auth_enable;
std::string auth_realm;
std::string auth_user;
std::string auth_pwd;
};
extern AmConfigReader gwconf;
#endif

@ -0,0 +1,9 @@
plug_in_name = gateway
module_ldflags =-lmISDN -lisdnnet
module_cflags =
COREPATH ?=../../core
module_cflags += -DGW_VERSION="\"0.1\""
# -I/usr/local/src/lcr/mISDN-2008_01_12/include -I/usr/local/src/lcr/mISDNuser-2008_01_12/include
include $(COREPATH)/plug-in/Makefile.app_module

@ -0,0 +1,9 @@
callerdomain=192.168.0.15
calleddomain=netitel.pl
msn=6240495,6240496,6240497,6233270
outprefixes=0*,1*,2*,3*,4*,5*,6*,7*,8*,9*,*
defaultmsn=6240495
auth_enable=yes
auth_realm=netitel.pl
auth_user=semsgw
auth_pwd=***

@ -0,0 +1,9 @@
#ifndef _GLOBALS_H_
#define _GLOBALS_H_
#define MODULE_NAME "gateway"
#define FAIL 0
#define OK 1
#define MAX_NUM_LEN 20
#endif

@ -0,0 +1,656 @@
#include "AmApi.h"
//#include "GWCall.h"
#include "globals.h"
#include "GatewayFactory.h"
#include "mISDNChannel.h"
#include "mISDNNames.h"
#include "amci/codecs.h"
#include <math.h>
using namespace mISDN;
//we need to swap bits in bytes for isdn audio. this 2 functions are borowed from asterisk
char flip_table[256];
void init_flip_bits(void) {
int i,k;
for (i = 0 ; i < 256 ; i++) {
unsigned char sample = 0 ;
for (k = 0; k<8; k++) {
if ( i & 1 << k ) sample |= 0x80 >> k;
}
flip_table[i] = sample;
}
}
static char * flip_buf_bits ( char * buf , int len) {
int i;
char * start = buf;
for (i = 0 ; i < len; i++) {
buf[i] = flip_table[(unsigned char)buf[i]];
}
return start;
}
/* First AmAudio interface This is short. */
int mISDNChannel::read(unsigned int user_ts, unsigned int size) {
// DBG("mISDNChannel::read user_ts=%d size=%d buffersize=%d\n",user_ts,size,fromISDN_buffer.size());
//i know this is not fastest implementation but its short and works
fromISDN_buffer.copy((char *)((unsigned char*)samples),size);
fromISDN_buffer.erase(0,size);
return size;
}
int mISDNChannel::write(unsigned int user_ts, unsigned int size) {
char buf[4096+mISDN_HEADER_LEN];
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
int ret;
// DBG("mISDNChannel::write user_ts=%d size=%d\n",user_ts,size);
if(m_BC==0) {
// DBG("bchannel is already detached or not yet initialised\n"); //we silently discard this to avoid log flooding
return 0;
}
if(size>=4096) {
DBG("truncating output audio (%d)\n",size);
size=4096;
}
memcpy(buf + (mISDN_HEADER_LEN), (unsigned char*)samples, size);
flip_buf_bits( buf + mISDN_HEADER_LEN, size);
frame->addr = m_BC | FLG_MSG_DOWN;
frame->prim = DL_DATA | REQUEST;
frame->dinfo = 0;
frame->len = size;
ret = mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, frame->len+mISDN_HEADER_LEN, 8000);
// DBG("mISDNChannel::write: sending packet directly to isdn 0x%x 0x%x %d ret=%d\n",frame->addr, frame->prim,frame->len,ret);
return ret;
}
void mISDNChannel::bchan_receive(char *msg_buf,int msg_buf_s) {
int len=msg_buf_s-mISDN_HEADER_LEN;
std::string tmp;
// DBG("mISDNChannel::bchannel_receive size=%d buffersize=%d\n",msg_buf_s - mISDN_HEADER_LEN,fromISDN_buffer.size());
flip_buf_bits( msg_buf + mISDN_HEADER_LEN, len);
tmp.assign(msg_buf + mISDN_HEADER_LEN,len);
fromISDN_buffer.append(tmp);
return;
}
//void mISDNChannel::bchannel_send() {
// char buf[PLAY_SIZE+mISDN_HEADER_LEN];
// mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
// int l,ret;
// int i,t;
// char *s;
//
// flip_buf_bits( buf + mISDN_HEADER_LEN, PLAY_SIZE);
// frame->addr = m_BC | FLG_MSG_DOWN;
// frame->prim = DL_DATA | REQUEST;
// frame->dinfo = 0;
// frame->len = PLAY_SIZE;
// ret = mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, PLAY_SIZE+mISDN_HEADER_LEN, 8000);
// DBG("mISDNChannel::bchannel_send write=%d\n",ret);
// return;
//}
//some code borrowed from Linux Call Router
static signed char _mISDN_l3_ie2pos[128] = {
-1,-1,-1,-1, 0,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,
2,-1,-1,-1, 3,-1,-1,-1, 4,-1,-1,-1, 5,-1, 6,-1,
7,-1,-1,-1,-1,-1,-1, 8, 9,10,-1,-1,11,-1,-1,-1,
-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
13,-1,14,15,16,17,18,19,-1,-1,-1,-1,20,21,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,23,-1,-1,
24,25,-1,-1,26,-1,-1,-1,27,28,-1,-1,29,30,31,-1
};
static unsigned char _mISDN_l3_pos2ie[32] = {
0x04, 0x08, 0x10, 0x14, 0x18, 0x1c, 0x1e, 0x20,
0x27, 0x28, 0x29, 0x2c, 0x34, 0x40, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47, 0x4c, 0x4d, 0x6c, 0x6d,
0x70, 0x71, 0x74, 0x78, 0x79, 0x7c, 0x7d, 0x7e
};
int mISDN_get_free_ext_ie(mISDN::Q931_info_t *qi) {
int i;
for (i = 0; i < 8; i++) {
if (qi->ext[i].ie.off == 0)
return(i);
}
return (-1);
}
int mISDN_AddIE(mISDN::Q931_info_t *qi, u_char *p, u_char ie, u_char *iep) {
u_char *ps;
mISDN::ie_info_t *ies;
int l;
if (ie & 0x80) { /* one octett IE */
if (ie == IE_MORE_DATA)
ies = &qi->more_data;
else if (ie == IE_COMPLETE)
ies = &qi->sending_complete;
else if ((ie & 0xf0) == IE_CONGESTION)
ies = &qi->congestion_level;
else {
return(-1);
}
l = 0;
} else {
if (!iep || !iep[0])
return(-3);
ies = &qi->bearer_capability;
if (_mISDN_l3_ie2pos[ie]<0) {
return(-2);
}
ies += _mISDN_l3_ie2pos[ie];
if (ies->off) {
while (ies->repeated)
ies = &qi->ext[ies->ridx].ie;;
l = mISDN_get_free_ext_ie(qi);
if (l < 0) { // overflow
return(-3);
}
ies->ridx = l;
ies->repeated = 1;
ies = &qi->ext[l].ie;
ies->cs_flg = 0;
qi->ext[l].v.codeset = 0;
qi->ext[l].v.val = ie;
}
l = iep[0] + 1;
}
ps = (u_char *) qi;
ps += L3_EXTRA_SIZE;
ies->off = (u16)(p - ps);
*p++ = ie;
if (l)
memcpy(p, iep, l);
return(l+1);
}
mISDNChannel::mISDNChannel() : AmAudio(new AmAudioSimpleFormat(CODEC_ALAW)){
DBG("this is temporary constructor\n");
init();
m_port=mISDNStack::instance()->mISDNport_first;
}
mISDNChannel::mISDNChannel(mISDNport *port) : AmAudio(new AmAudioSimpleFormat(CODEC_ALAW)){
init();
m_port=port;
}
mISDNChannel::~mISDNChannel() {
unregister_CR();
unregister_BC();
DBG("mISDNChannel destructor ends\n");
}
void mISDNChannel::init() {
m_frame=(mISDN::iframe_t*)m_last_msg;
m_qi = (mISDN::Q931_info_t*)(m_last_msg + mISDN_HEADER_LEN);
m_ie_data =(char *)m_qi + L3_EXTRA_SIZE;
/* init the audio buffers for in&out */
// pthread_mutex_init(&fromISDN_lock, NULL);
// pthread_mutex_init(&toISDN_lock, NULL);
fromISDN_buffer.assign("");
}
void mISDNChannel::setSession(GWSession* session) {
m_session = session;
}
GWSession* mISDNChannel::getSession() {
return m_session;
}
void mISDNChannel::unregister_CR() {
mISDNStack* stack=mISDNStack::instance();
std::map<int,mISDNChannel*>::iterator CR_iter=stack->CR_map.find(m_CR);;
if(CR_iter==stack->CR_map.end()) {
DBG("mISDNChannel::unregister_CR Cant find myself in CR_map this=%p (0x%08x)\n",this,m_CR);
} else {
DBG("mISDNChannel::unregister_CR removing channel from CR_map this=%p (0x%08x)\n",this,m_CR);
stack->CR_map.erase(CR_iter);
}
m_CR=0;
}
void mISDNChannel::unregister_BC() {
mISDNStack* stack=mISDNStack::instance();
if(m_BC!=0) {
std::map<int,mISDNChannel*>::iterator BC_iter=stack->BC_map.find(m_BC&STACK_ID_MASK);;
if(BC_iter==stack->BC_map.end()) {
DBG("mISDNChannel::unregister_BC Cant find myself in BC_map %p (0x%08x)\n",this,m_BC);
} else {
DBG("mISDNChannel::unregister_BC is removing channel from BC_map this=%p (0x%08x)\n",this,m_BC);
stack->BC_map.erase(BC_iter);
}
m_BC=0;
} else DBG("mISDNChannel::unregister_BC BC already removed or not initialized, this=%p (0x%08x)\n",this,m_BC);
}
int mISDNChannel::placeCall(const AmSipRequest &req, std::string tonumber, std::string fromnumber) {
int ret;
m_called=tonumber;
m_TON_d=0; //Unknown
m_NPI_d=1; // ISDN E.164
if(fromnumber.empty()) {
m_caller=gwconf.getParameter("out_msn","");
} else
m_caller=fromnumber;
m_TON_r=0; //Unknown
m_NPI_r=1; // ISDN E.164
m_Screening_r=0; // user provided
m_Presentation_r=0; // allowed
return call();
}
int mISDNChannel::accept() {
mISDNStack* stack=mISDNStack::instance();
char buf[MAX_MSG_SIZE];
mISDN::Q931_info_t *qi;
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
DBG("mISDNChannel::accept\n");
frame->prim = CC_CONNECT | REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len= 0;
DBG("Sending CC_CONNECT | REQUEST for CR=0x%04x \n",m_CR);
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
return OK;
}
int mISDNChannel::hangup() {
mISDNStack* stack=mISDNStack::instance();
char buf[MAX_MSG_SIZE];
mISDN::Q931_info_t *qi;
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
DBG("mISDNChannel::hangup\n");
frame->prim = CC_DISCONNECT | REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len= 0;
DBG("Sending CC_DISCONNECT | REQUEST for CR=0x%04x \n",m_CR);
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
return OK;
}
int mISDNChannel::call() {
mISDNStack* stack=mISDNStack::instance();
unsigned char buf[MAX_MSG_SIZE], *np, *p, *msg, ie[64];
mISDN::Q931_info_t *qi;
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
int ret,len,i;
INFO("mISDN is making outbound call from %s to %s\n", m_caller.c_str(), m_called.c_str());
//making new isdn call ref
m_CR=stack->GenerateCR();
frame->prim = CC_NEW_CR | REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len=0;
DBG("sending CC_NEW_CR | REQUEST to device=%d addr=0x%08x dinfo=0x%08x\n",mISDNStack::instance()->m_mISDNdevice,frame->addr,frame->dinfo);
ret=mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
if ( ret<0) {
ERROR("mISDNChannel::call error on NEW_CR | REQUEST %d\n", ret);
return FAIL;
}
stack->CR_map[m_CR]=this;
DBG("Adding self (%p) to channel_map my CR=0x%08x \n",this,m_CR);
p = msg = buf + mISDN_HEADER_LEN;
qi = (mISDN::Q931_info_t *)p;
memset(qi, 0, sizeof(mISDN::Q931_info_t));
qi->type = MT_SETUP;
p += L3_EXTRA_SIZE;
p++; /* needed to avoid offset 0 in IE array */
ret = mISDN_AddIE(qi, p, IE_COMPLETE, NULL);
if ( ret<0) {
ERROR("mISDNChannel::call Add IE_COMPLETE error %d\n", ret);
return FAIL;
}
p += ret;
ret = mISDN_AddIE(qi, p, IE_BEARER, (unsigned char*)"\x3\x90\x90\xa3"); /* Audio */
// ret = mISDN_AddIE(qi, p, IE_BEARER, (unsigned char*)"\x2\x88\x90"); /* default Datatransmission 64k */
if (ret<0) { ERROR("mISDNChannel::call Add IE_BEARER error %d\n", ret); return FAIL;}
p += ret;
ie[0] = m_caller.size() + 1;
ie[1] = 0x00 + (m_TON_r << 4) + m_NPI_r; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
if (m_Presentation_r >= 0) {
ie[1] = 0x00 + (m_TON_r<<4) + m_NPI_r;
ie[2] = 0x80 + (m_Presentation_r<<5) + m_Screening_r;
for (i=0; i<=m_caller.size(); i++)
ie[3+i] = m_caller[i] & 0x7f;
} else {
ie[1] = 0x80 + (m_TON_r<<4) + m_NPI_r;
for (i=0; i<=m_caller.size(); i++)
ie[2+i] = m_caller[i] & 0x7f;
}
ret = mISDN_AddIE(qi, p, IE_CALLING_PN, ie);
if (ret<0) { ERROR("mISDNChannel::call Add IE_CALLING_PN error %d\n", ret);return FAIL; }
p += ret;
ie[0] =m_called.size() + 1;
ie[1] = 0x80 + (m_TON_d << 4) + m_NPI_d; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
for (i=0; i<=m_called.size(); i++)
ie[2+i] = m_called[i] & 0x7f;
ret = mISDN_AddIE(qi, p, IE_CALLED_PN, ie);
if (ret<0) { ERROR("mISDNChannel::call Add IE_CALLED_PN error %d\n", ret);return FAIL; }
p += ret;
frame->prim = CC_SETUP | REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len= p - msg;
ret=mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
if ( ret<0) {
ERROR("mISDNChannel::call error dending CC_SETUP | REQUEST %d\n", ret);
return FAIL;
}
return OK;
}
int mISDNChannel::processMsg(char *msg_buf,int msg_buf_s) {
mISDNStack* stack=mISDNStack::instance();
char buf[MAX_MSG_SIZE];
int buf_s;
mISDN::Q931_info_t *qi;
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
char *p;
p=(char *)&m_last_msg;
memcpy(p, msg_buf, msg_buf_s);
m_last_msg_s=msg_buf_s;
memset(p+msg_buf_s,0,MAX_MSG_SIZE-msg_buf_s);
switch(m_frame->prim) {
case CC_SETUP |INDICATION:
DBG("CC_SETUP | INDICATION for CR=0x%04x \n",m_CR);
GetIEchannel_id();
DBG("Creating Bchannel for CR=0x%04x \n",m_CR);
bchan_create();
GetCallerNum();
GetCalledNum();
m_session=GWSession::CallFromOutside(m_caller, m_called, 0, this);
if(m_session!=NULL) {
unsigned char buf[MAX_MSG_SIZE];
// mISDN::Q931_info_t *qi;
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
int ret,len;
frame->prim = CC_PROCEEDING | REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len= 0;
ret=mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
DBG("m_session=%p Not null sending CC_PROCEEDING |REQUEST\n",m_session);
}
break;
case CC_PROCEEDING |INDICATION:
DBG("CC_PROCEEDING | INDICATION for CR=0x%04x \n",m_CR);
// m_session->acceptAudio(m_session->invite_req.body,m_req.hdrs,&sdp_reply);
// m_session->dlg.reply(m_session->invite_req,180, "Isdn side state is: PROCEEDING", "application/sdp",sdp_reply);
m_session->dlg.reply(m_session->invite_req,180, "Isdn side state is: PROCEEDING");
DBG("check 2 CC_PROCEEDING | INDICATION for CR=0x%04x \n",m_CR);
GetIEchannel_id();
DBG("Creating Bchannel for CR=0x%04x \n",m_CR);
bchan_create();
break;
case CC_ALERTING | INDICATION:
DBG("CC_ALERTING | INDICATION for CR=0x%04x \n",m_CR);
// m_session->acceptAudio(m_session->invite_req.body,m_req.hdrs,&sdp_reply);
// m_session->dlg.reply(m_session->invite_req,183, "Isdn side state is: ALERTING", "application/sdp",sdp_reply);
m_session->dlg.reply(m_session->invite_req,183, "Isdn side state is: ALERTING");
break;
case CC_CONNECT | INDICATION:
case CC_CONNECT_ACKNOWLEDGE | INDICATION:
DBG("CC_CONNECT(_ACKNOWLEDGE) | INDICATION for CR=0x%04x \n",m_CR);
DBG("Activating Bchannel for CR=0x%04x \n",m_CR);
bchan_activate();
m_session->onSessionStart(m_session->invite_req);
break;
case CC_DISCONNECT | INDICATION:
case CC_DISCONNECT | CONFIRM:
DBG("CC_DISCONNECT | INDICATION or CONFIRMfor CR=0x%04x \n",m_CR);
m_session->setInOut(NULL,NULL);
m_session->setStopped();
if(m_session->dlg.getStatus()==AmSipDialog::Pending) {
DBG("Sip side not yet connected sending reply\n");
m_session->dlg.reply(m_session->invite_req,487, "Isdn side state is: DISCONNECTING");
//maybe this would be better
// throw AmSession::Exception(487, "call terminated");
} else {
DBG("Sip side already connected sending bye\n");
m_session->dlg.bye();
}
// mISDN::mISDN_write_frame(stack->m_mISDNdevice, buf, m_port->upper_id | FLG_MSG_DOWN, CC_RELEASE | REQUEST, m_CR, 0, NULL, TIMEOUT_1SEC);
frame->prim = CC_RELEASE | REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len= 0;
DBG("Sending CC_RELEASE | REQUEST for CR=0x%04x \n",m_CR);
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
bchan_deactivate();
break;
case CC_RELEASE | INDICATION:
case CC_RELEASE_COMPLETE | INDICATION:
DBG("CC_RELEASE(_COMPLETE) | INDICATION for CR=0x%04x \n",m_CR);
// mISDN::mISDN_write_frame(stack->m_mISDNdevice, buf, m_port->upper_id | FLG_MSG_DOWN, CC_RELEASE_COMPLETE | REQUEST, m_CR, 0, NULL, TIMEOUT_1SEC);
frame->prim = CC_RELEASE_COMPLETE| REQUEST;
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
frame->dinfo= m_CR;
frame->len= 0;
DBG("Sending CC_RELEASE_COMPLETE | REQUEST for CR=0x%04x \n",m_CR);
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
bchan_destroy();
break;
default:
ERROR("mISDNChannel::processMsg unhandled: prim(0x%x) addr(0x%x) msg->len(%d)\n", m_frame->prim, m_frame->addr, msg_buf_s);
return FAIL;
break;
}
return OK;
}
int mISDNChannel::GetIEchannel_id(){
char *p;
m_bchannel=-1; //no ie or error (for now)
if (m_qi->channel_id.off==0) { ERROR("No channel_id IE here\n"); return FAIL; }
p = m_ie_data + m_qi->channel_id.off;
//p[0] is 0x18 - code for this ie;
DBG("mISDNChannel::GetIEchannel_id p= 0x%02hhx 0x%02hhx 0x%02hhx\n",p[0],p[1],p[2]);
if(p[1]<1) { ERROR("IE Too short\n"); return FAIL; }
if(p[2] & 0x40) { ERROR("Channels on other interfaces not supported\n"); return FAIL; } // bit 7 - other interface
if(p[2] & 0x04) { ERROR("using d-channel not supported\n"); return FAIL; } // bit 3 - d channel;
if(m_port->pri) {
switch((p[2]&0x03)) {
case 0: m_bchannel=-2; return OK; break; //no Channel
case 1: break; //channel num in folowing bytes
case 2: ERROR("Reserved bit set\n"); return FAIL; break; // reserver bit;
case 3: m_bchannel=-3; return OK; break; //ANY channel
}
if(p[1] < 3) { ERROR("IE Too short for PRI\n"); return FAIL; } // we need extended info on channel num for pri
if(p[3] & 0x10) { ERROR("channel map not supported\n"); return FAIL; } // bit 3 - d channel;
m_bchannel=p[4]&0x7f;
if(m_bchannel<1 || m_bchannel==16) {
ERROR("PRI channel out of range (%d)\n",m_bchannel);
m_bchannel=-1;
return FAIL;
}
DBG("mISDNChannel::GetIEchannel_id will use PRI b_channel=%d\n",m_bchannel);
return OK;
} else { //BRI
if ((p[2] & 0x20)) { ERROR("req for bri channel on PRI interface\n"); return FAIL; } // bit 6 - 0=BRI, 1-other(PRI);
switch((p[2]&0x03)) {
case 0: m_bchannel=-2; break; //no Channel
case 1: m_bchannel=1; break; //channel 1
case 2: m_bchannel=2; break; //channel 2
case 3: m_bchannel=-3; break; //ANY channel
}
DBG("mISDNChannel::GetIEchannel_id will use BRI b_channel=%d\n",m_bchannel);
return OK;
}
}
int mISDNChannel::GetCallerNum(){
char *p;
int len;
if (m_qi->calling_nr.off==0) { ERROR("No calling_nr IE here\n"); return FAIL; }
p = m_ie_data + m_qi->calling_nr.off;
//p[0] is 0x6C - code for this ie;
DBG("mISDNChannel::GetCallerNum p= 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",p[0],p[1],p[2],p[3]);
p++;//now we scan each byte as some are optional
if(p[0]<1) { ERROR("IE Too short\n"); return FAIL; }
if(p[0]>=MAX_NUM_LEN-1) { ERROR("Number too long for MAX_NUM_LEN \n"); return FAIL; }
len=p[0];
p++;
m_TON_r=(p[0]&0x70)>>4;
m_NPI_r=p[0]&0x0F;
if(!(p[0]&80)) { //if this is not last byte
len--;p++; //warning p is shifted here to next byte (optional Presentation/Screening)
m_Presentation_r=(p[0]&0x60)>>5;
m_Screening_r=p[0]&0x03;
} else DBG("mISDNChannel::GetCallerNum no Presentation/Screening byte\n");
len--;p++;
DBG("mISDNChannel::GetCallerNum len=%d TON=%d NPI=%d Presentation=%d Screening=%d\n",len,m_TON_r,m_NPI_r,m_Presentation_r,m_Screening_r);
// memcpy(&m_caller, p, len);
// m_caller[len]='\0';
m_caller.assign(p,len);
DBG("mISDNChannel::GetCallerNum %s %s %s %s %s\n",m_caller.c_str(),mISDNNames::TON(m_TON_r),mISDNNames::NPI(m_NPI_r),mISDNNames::Presentation(m_Presentation_r),mISDNNames::Screening(m_Screening_r));
return OK;
}
int mISDNChannel::GetCalledNum(){
char *p;
int len;
if (m_qi->called_nr.off==0) { ERROR("No called_nr IE here\n"); return FAIL; }
p = m_ie_data + m_qi->called_nr.off;
//p[0] is 0x70 - code for this ie;
DBG("mISDNChannel::GetCalledNum p= 0x%02hhx 0x%02hhx 0x%02hhx\n",p[0],p[1],p[2]);
if(p[1]<1) { ERROR("IE Too short\n"); return FAIL; }
if(p[1]>=MAX_NUM_LEN-1) { ERROR("Number too long for MAX_NUM_LEN \n"); return FAIL; }
len=p[1];
m_TON_d=(p[2]&0x70)>>4;
m_NPI_d=p[2]&0x0F;
DBG("mISDNChannel::GetCalledNum len=%d TON=%d NPI=%d\n",len,m_TON_d,m_NPI_d);
// memcpy(&m_called, p+3, len-1);
// m_called[len-1]='\0';
m_called.assign(p+3,len-1);
DBG("mISDNChannel::GetCalledNum %s %s %s\n",m_called.c_str(),mISDNNames::TON(m_TON_d),mISDNNames::NPI(m_NPI_d));
return OK;
}
int mISDNChannel::bchan_event(char *msg_buf,int msg_buf_s) {
char *p;
p=(char *)&m_last_msg;
memcpy(p, msg_buf, msg_buf_s);
m_last_msg_s=msg_buf_s;
memset(p+msg_buf_s,0,MAX_MSG_SIZE-msg_buf_s);
switch(m_frame->prim) {
case PH_DATA | CONFIRM:
case DL_DATA | CONFIRM:
// DBG("PH_DATA or DL_DATA confirm prim(0x%x) addr(0x%x) msg->len(%d) \n", m_frame->prim, m_frame->addr, msg_buf_s);
// bchannel_send(); //we are now transmiting directly from Channel(AmAudio)::write
break;
case PH_DATA | INDICATION:
case DL_DATA | INDICATION:
// DBG("PH_DATA or DL_DATA IND prim(0x%x) addr(0x%x) msg->len(%d) \n", m_frame->prim, m_frame->addr, msg_buf_s);
bchan_receive(msg_buf,msg_buf_s);
break;
case PH_CONTROL | INDICATION:
case PH_SIGNAL | INDICATION:
DBG("PH_CONTROL or PH_SIGNAL IND prim(0x%x) addr(0x%x) msg->len(%d) \n", m_frame->prim, m_frame->addr, msg_buf_s);
break;
case PH_ACTIVATE | INDICATION:
case DL_ESTABLISH | INDICATION:
case PH_ACTIVATE | CONFIRM:
case DL_ESTABLISH | CONFIRM:
DBG("(PH|DL)_(ESTABLISH|ACTIVATE (IND|CONFIRM): bchannel is now activated (address 0x%x).\n", m_frame->addr);
break;
case PH_DEACTIVATE | INDICATION:
case DL_RELEASE | INDICATION:
case PH_DEACTIVATE | CONFIRM:
case DL_RELEASE | CONFIRM:
DBG("(PH|DL)_(RELEASE|DEACTIVATE (IND|CONFIRM): bchannel is now de-activated (address 0x%x).\n", m_frame->addr);
bchan_destroy();
unregister_BC();
break;
default:
ERROR("child message not handled: prim(0x%x) addr(0x%x) msg->len(%d)\n", m_frame->prim, m_frame->addr, msg_buf_s);
return FAIL;
break;
}
return OK;
}
int mISDNChannel::bchan_create() {
layer_info_t li;
mISDN_pid_t pid;
int ret;
mISDNStack* stack=mISDNStack::instance();
if(m_bchannel<=0) { ERROR("b-channel num not known or invalid (%d)\n",m_bchannel); return FAIL; }
if(m_port->b_stid[m_bchannel-1]==0) { ERROR("No stack for b-channel (%d)\n",m_bchannel); return FAIL; }
if(m_port->b_addr[m_bchannel-1]!=0) { ERROR("Stack already created for b-channel (%d)\n",m_bchannel); return FAIL; }
memset(&li, 0, sizeof(li));
memset(&pid, 0, sizeof(pid));
li.object_id = -1;
li.extentions = 0;
li.st = m_port->b_stid[m_bchannel-1];
strcpy(li.name, "B L4");
// li.pid.layermask = ISDN_LAYER((4));
li.pid.layermask = ISDN_LAYER((3));
// li.pid.protocol[4] = ISDN_PID_L4_B_USER;
li.pid.protocol[3] = ISDN_PID_L3_B_TRANS;
ret = mISDN_new_layer(mISDNStack::instance()->m_mISDNdevice, &li);
if(ret || !li.id) { ERROR("mISDN_new_layer() failed to add bchannel %d\n", m_bchannel); return FAIL; }
m_BC=m_port->b_addr[m_bchannel-1]=li.id;
pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
pid.protocol[2] = ISDN_PID_L2_B_TRANS;
pid.protocol[3] = ISDN_PID_L3_B_TRANS;
// pid.protocol[3] = ISDN_PID_L3_B_DSP;
// pid.protocol[4] = ISDN_PID_L4_B_USER;
pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) ;
// pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4));
ret = mISDN_set_stack(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1], &pid);
if(ret) { ERROR("mISDN_set_stack failed to add bchannel %d\n", m_bchannel); return FAIL; }
ret = mISDN_get_setstack_ind(stack->m_mISDNdevice, m_BC);
if(ret) { ERROR("mISDN_set_stack_ind failed to add bchannel %d\n", m_bchannel); return FAIL; }
m_BC=m_port->b_addr[m_bchannel-1]=mISDN_get_layerid(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1], 3);
// m_BC=m_port->b_addr[m_bchannel-1]=mISDN_get_layerid(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1], 4);
if(m_BC==0) { ERROR("mISDN_get_layerid failed to add bchannel %d\n", m_bchannel); return FAIL; }
stack->BC_map[m_BC&STACK_ID_MASK]=this;
m_port->b_port[m_bchannel-1]=this;
DBG("Successfully created stack for port %d. addr=0x%08x\n",m_bchannel,m_BC);
return OK;
}
int mISDNChannel::bchan_activate() {
mISDN::iframe_t frame;
mISDNStack* stack=mISDNStack::instance();
int ret;
if(m_BC==0) { ERROR("bchannel (%d) not created\n",m_bchannel); return FAIL; }
DBG("sending DL_ESTABLISH | REQUEST to device=%d for bchannel=%d addr=0x%08x dinfo=0x%08x\n",stack->m_mISDNdevice, m_bchannel,frame.addr, frame.dinfo);
ret = mISDN::mISDN_write_frame(stack->m_mISDNdevice, &frame, m_BC | FLG_MSG_DOWN, DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
return OK;
}
int mISDNChannel::bchan_deactivate() {
mISDN::iframe_t frame;
mISDNStack* stack=mISDNStack::instance();
int ret;
DBG("sending DL_RELEASE | REQUEST to device=%d for bchannel=%d addr=0x%08x dinfo=0x%08x\n",stack->m_mISDNdevice, m_bchannel,frame.addr, frame.dinfo);
ret = mISDN::mISDN_write_frame(stack->m_mISDNdevice, &frame, m_BC | FLG_MSG_DOWN, DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
return OK;
}
int mISDNChannel::bchan_destroy() {
mISDN::iframe_t frame;
mISDNStack* stack=mISDNStack::instance();
int ret;
ret = mISDN_clear_stack(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1]);
DBG("sending MGR_DELLAYER | REQUEST to device=%d for bchannel=%d addr=0x%08x dinfo=0x%08x\n",stack->m_mISDNdevice, m_bchannel,frame.addr, frame.dinfo);
ret = mISDN::mISDN_write_frame(stack->m_mISDNdevice, &frame, m_BC | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
unregister_BC();
m_port->b_port[m_bchannel-1]=NULL;
m_port->b_addr[m_bchannel-1]=0;
return OK;
}

@ -0,0 +1,75 @@
#ifndef _mISDNCHANNEL_H_
#define _mISDNCHANNEL_H_
#include "AmApi.h"
#include "GWSession.h"
//#include "GWCall.h"
#include "globals.h"
#include "mISDNStack.h"
extern char flip_table[256];
void init_flip_bits(void);
class mISDNChannel: public AmAudio {
public:
/* AmAudio interface */
int read(unsigned int user_ts, unsigned int size);
int write(unsigned int user_ts, unsigned int size);
/* buffers for audio data */
//this buffer is feeded by isdn in 128byte chunks, while media processor eats 160bytes each time.
std::string fromISDN_buffer;
// pthread_mutex_t fromISDN_lock;
// std::string toISDN_buffer;
// pthread_mutex_t toISDN_lock;
int m_CR; //call reference (dinfo)
int m_BC; //b-channel (addr)
mISDNport *m_port;
char m_bchannel;
char m_last_msg[MAX_MSG_SIZE]; //we copy here packet from kernel
int m_last_msg_s;
mISDN::iframe_t* m_frame; //there are pointers to places in m_last_msg buffer
mISDN::Q931_info_t* m_qi; //
char* m_ie_data; //
std::string m_caller; // caller number
int m_TON_r,m_NPI_r,m_Screening_r,m_Presentation_r; //caler number attributes
std::string m_called; //calee number
int m_TON_d,m_NPI_d; //calee number attributes
mISDNChannel(); /* constructor */
mISDNChannel(mISDNport *port);
~mISDNChannel();
void init();
void setSession(GWSession*);
GWSession* getSession();
void unregister_CR();
void unregister_BC();
int processMsg(char *msg_buf,int msg_buf_s);
int bchan_event(char *msg_buf,int msg_buf_s);
int placeCall(const AmSipRequest &req, std::string tonumber, std::string fromnumber); /* place a call */
int call();
int accept(); /* accept a call */
int hangup(); /* hangup a call */
//ie processing functions
int GetIEchannel_id();
int GetCallerNum();
int GetCalledNum();
private:
GWSession* m_session;
int bchan_create();
int bchan_activate();
int bchan_deactivate();
int bchan_destroy();
void bchan_receive(char *msg_buf,int msg_buf_s);
// void bchan_send();
// int id;
};
#endif /*header*/

@ -0,0 +1,99 @@
#include "mISDNNames.h"
//namespace mISDN { //this is hack to cover definition of dprint which is defined in mISDN and sems core
extern "C" {
#include <mISDNuser/mISDNlib.h>
#include <mISDNuser/net_l2.h>
#include <mISDNuser/l3dss1.h>
}
//}
const char* mISDNNames::isdn_prim[4] = {" REQUEST"," CONFIRM"," INDICATION"," RESPONSE" };
const char* mISDNNames::IE_Names[37] ={ "bearer_capability", "cause", "call_id", "call_state", "channel_id", "facility",
"progress", "net_fac", "notify", "display", "date", "keypad", "signal", "info_rate", "end2end_transit",
"transit_delay_sel", "pktl_bin_para","pktl_window", "pkt_size", "closed_userg", "connected_nr", "connected_sub",
"calling_nr", "calling_sub", "called_nr", "called_sub", "redirect_nr", "redirect_dn", "transit_net_sel",
"restart_ind", "llc", "hlc", "useruser", "more_data", "sending_complete", "congestion_level", "comprehension_required"};
const char* mISDNNames::Message(int i) {
switch(i) {
case CC_TIMEOUT: return "TIMEOUT";
case CC_SETUP: return "SETUP";
case CC_SETUP_ACKNOWLEDGE: return "SETUP_ACK";
case CC_PROCEEDING: return "PROCEEDING";
case CC_ALERTING: return "ALERTING";
case CC_CONNECT: return "CONNECT";
case CC_CONNECT_ACKNOWLEDGE: return "CONNECT_ACK";
case CC_DISCONNECT: return "DISCONNECT";
case CC_RELEASE: return "RELEASE";
case CC_RELEASE_COMPLETE: return "RELEASE_COMP";
case CC_INFORMATION: return "INFORMATION";
case CC_PROGRESS: return "PROGRESS";
case CC_NOTIFY: return "NOTIFY";
case CC_SUSPEND: return "SUSPEND";
case CC_SUSPEND_ACKNOWLEDGE: return "SUSPEND_ACK";
case CC_SUSPEND_REJECT: return "SUSPEND_REJ";
case CC_RESUME: return "RESUME";
case CC_RESUME_ACKNOWLEDGE: return "RESUME_ACK";
case CC_RESUME_REJECT: return "RESUME_REJ";
case CC_HOLD: return "HOLD";
case CC_HOLD_ACKNOWLEDGE: return "HOLD_ACK";
case CC_HOLD_REJECT: return "HOLD_REJ";
case CC_RETRIEVE: return "RETRIEVE";
case CC_RETRIEVE_ACKNOWLEDGE: return "RETRIEVE_ACK";
case CC_RETRIEVE_REJECT: return "RETRIEVE_REJ";
case CC_FACILITY: return "FACILITY";
case CC_STATUS: return "STATUS";
case CC_RESTART: return "RESTART";
case CC_RELEASE_CR: return "RELEASE_CR";
case CC_NEW_CR: return "NEW_CR";
case DL_ESTABLISH: return "DL_ESTABLISH";
case DL_RELEASE: return "DL_RELEASE";
case PH_ACTIVATE: return "PH_ACTIVATE";
case PH_DEACTIVATE: return "PH_DEACTIVATE";
case MGR_SHORTSTATUS: return "MGR_SHORTSTATUS";
}
return "ERROR";
}
const char* mISDNNames::NPI(int i) {
switch(i) {
case 0x00: return "Unknown";
case 0x01: return "ISDN/Tel E.164";
case 0x03: return "Data X.121 ";
case 0x04: return "Telex F.69";
case 0x08: return "National";
case 0x09: return "Private";
case 0x0F: return "Reserved";
}
return "ERROR";
}
const char* mISDNNames::TON(int i) {
switch(i) {
case 0x00: return "Unknown";
case 0x01: return "International";
case 0x02: return "National";
case 0x03: return "NetworkSpec";
case 0x04: return "Subscriber";
case 0x06: return "abbreviated";
case 0x07: return "Reserved";
}
return "ERROR";
}
const char* mISDNNames::Presentation(int i) {
switch(i) {
case 0x00: return "Presentation Allowed";
case 0x01: return "Presentation Restricted";
case 0x02: return "Number not available";
case 0x03: return "Reserved";
}
return "ERROR";
}
const char* mISDNNames::Screening(int i) {
switch(i) {
case 0x00: return "User-privided not screened";
case 0x01: return "User-privided verified and passed";
case 0x02: return "User-privided verified and failed";
case 0x03: return "Network provided";
}
return "ERROR";
}

@ -0,0 +1,15 @@
#ifndef _MISDNNAMES_H_
#define _MISDNNAMES_H_
class mISDNNames {
public:
static const char* Message(int i);
static const char* NPI(int i);
static const char* TON(int i);
static const char* Presentation(int i);
static const char* Screening(int i);
static const char* isdn_prim[4];
static const char* IE_Names[37];
};
#endif

@ -0,0 +1,548 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "log.h"
#include "AmSession.h"
#include "globals.h"
#include "mISDNStack.h"
#include "mISDNChannel.h"
#include "mISDNNames.h"
using namespace mISDN;
mISDNStack* mISDNStack::_instance=NULL;
mISDNStack* mISDNStack::instance()
{
if(!_instance) {
DBG("mISDNStack::instance spawning new\n");
_instance = new mISDNStack();
if(_instance->init() != OK){
delete _instance;
_instance = 0;
} else {
DBG("mISDNStack::instance start\n");
_instance->start();
init_flip_bits();
}
}
return _instance;
}
mISDNChannel* mISDNStack::NewCR(mISDNport *port,mISDN::iframe_t *frame) {
std::map<int,mISDNChannel*>::iterator iter=CR_map.find(frame->dinfo);;
if(iter==CR_map.end()) {
mISDNChannel* chan=NULL;
DBG("This is new CR, spawning new object\n");
chan = new mISDNChannel(port);
CR_map[frame->dinfo]=chan;
chan->m_CR=frame->dinfo;
DBG("pointer to chan is %p\n",chan);
return chan;
} else {
DBG("got previous CR porinter is %p\n",iter->second);
return iter->second;
}
}
mISDNChannel* mISDNStack::FindCR(mISDN::iframe_t *frame) {
std::map<int,mISDNChannel*>::iterator iter=CR_map.find(frame->dinfo);;
if(iter!=CR_map.end()) {
// DBG("got previous CR porinter is %p\n",iter->second);
return iter->second;
} else {
ERROR("CR 0x%08x not found in CR_map\n",frame->dinfo);
return NULL;
}
}
mISDNChannel* mISDNStack::FindBC(mISDN::iframe_t *frame) {
std::map<int,mISDNChannel*>::iterator iter=BC_map.find(frame->addr&STACK_ID_MASK);;
if(iter!=BC_map.end()) {
// DBG("got previous BC porinter is %p\n",iter->second);
return iter->second;
} else {
ERROR("BC address 0x%08x not found in BC_map\n",frame->addr);
return NULL;
}
}
int mISDNStack::placeCall(const AmSipRequest &req, GWSession *session, const std::string &tonumber, const std::string &fromnumber) {
//we will have code to choose right port here.
mISDNChannel *chan = new mISDNChannel(); //(device);
if(chan==NULL) {
ERROR("Cant allocate new mISDNChannel\n");
return FAIL;
}
session->setOtherLeg(chan);
chan->setSession(session);
DBG("calling ((mISDNChannel*)m_pstndevice)->placeCall(m_req, tonumber, fromnumber);\n");
return chan->placeCall(req, tonumber, fromnumber);
}
int mISDNStack::GetPortInfo() {
int err;
int i, num_cards, p;
int useable, nt, pri;
unsigned char buff[1025];
iframe_t *frm = (iframe_t *)buff;
stack_info_t *stinf;
int device;
if ((device = mISDN_open()) < 0) {
ERROR("mISDNStack::mISDNStack: mISDN_open() failed: ret=%d errno=%d (%s) Check for mISDN modules and device.\n", device, errno, strerror(errno));
return FAIL;
}
DBG("mISDNStack::mISDNStack: mISDN_open %d\n",device);
/* get number of stacks */
i = 1;
num_cards = mISDN_get_stack_count(device);
if (num_cards <= 0) {
ERROR("Found no card. Please be sure to load card drivers.\n");
return FAIL;
}
/* loop the number of cards and get their info */
while(i <= num_cards) {
err = mISDN_get_stack_info(device, i, buff, sizeof(buff));
if (err <= 0) { ERROR("mISDN_get_stack_info() failed: port=%d err=%d\n", i, err); break; }
stinf = (stack_info_t *)&frm->data.p;
nt = pri = 0;
useable = 1;
switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) {
case ISDN_PID_L0_TE_S0: INFO("Port %2d: TE-mode BRI S/T interface line (for phone lines)\n",i); break;
case ISDN_PID_L0_NT_S0: nt = 1; INFO("Port %2d: NT-mode BRI S/T interface port (for phones)\n",i); break;
case ISDN_PID_L0_TE_E1: pri = 1; INFO("Port %2d: TE-mode PRI E1 interface line (for phone lines)\n",i); break;
case ISDN_PID_L0_NT_E1: nt = 1;pri = 1; INFO("Port %2d: NT-mode PRI E1 interface port (for phones)\n",i); break;
default: useable = 0; ERROR("unknown type 0x%08x\n",stinf->pid.protocol[0]);
}
if (nt) {
if (stinf->pid.protocol[1] == 0) { useable = 0; INFO(" -> Missing layer 1 NT-mode protocol.\n"); }
p = 2; while(p <= MAX_LAYER_NR) { if (stinf->pid.protocol[p]) {useable = 0; INFO(" -> Layer %d protocol 0x%08x is detected, but not allowed for NT.\n", p, stinf->pid.protocol[p]); } p++; }
if (useable) {
if (pri) INFO(" -> Interface is Point-To-Point (PRI).\n");
else INFO(" -> Interface can be Poin-To-Point/Multipoint.\n");
}
} else {
if (stinf->pid.protocol[1] == 0) { useable = 0; INFO(" -> Missing layer 1 protocol.\n"); }
if (stinf->pid.protocol[2] == 0) { useable = 0; INFO(" -> Missing layer 2 protocol.\n"); }
if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP) { INFO(" -> Interface is Poin-To-Point.\n"); }
if (stinf->pid.protocol[3] == 0) { useable = 0; INFO(" -> Missing layer 3 protocol.\n"); }
else { switch(stinf->pid.protocol[3] & ~ISDN_PID_FEATURE_MASK) {
case ISDN_PID_L3_DSS1USER: INFO(" -> Protocol: DSS1 (Euro ISDN)\n"); break;
default: useable = 0; INFO(" -> Protocol: unknown protocol 0x%08x\n",stinf->pid.protocol[3]);
}
}
p = 4; while(p <= MAX_LAYER_NR) { if (stinf->pid.protocol[p]) { useable = 0; INFO(" -> Layer %d protocol 0x%08x is detected, but not allowed for TE.\n", p, stinf->pid.protocol[p]); } p++; }
INFO(" -> childcnt: %d\n",stinf->childcnt);
}
if (!useable) ERROR(" * Port %2d NOT useable. (maybe somethind is using it already?)\n",i);
i++;
}
/* close mISDN */
if ((err = mISDN_close(device))) {
ERROR("mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
return FAIL;
}
return OK;
}
mISDNStack::mISDNStack() : m_mISDNdevice(0),m_entity(0) {
mISDNport_first=NULL;
}
mISDNStack::~mISDNStack() {
}
int mISDNStack::init() {
unsigned char buff[1025];
iframe_t *frm = (iframe_t *)buff;
int ret;
struct mISDNport *mISDNport, **mISDNportp;
int i, cnt,port;
int pri, ports;
int nt, ptp, ptmp;
net_stack_t *nst;
manager_t *mgr;
layer_info_t li;
stack_info_t *stinf;
if ((m_mISDNdevice = mISDN_open()) < 0) { ERROR("mISDNStack::init: mISDN_open() failed: ret=%d errno=%d (%s) Check for mISDN modules and device.\n", m_mISDNdevice, errno, strerror(errno)); return FAIL; }
DBG("mISDNStack::init: mISDN_opened %d\n",m_mISDNdevice);
/* create entity for layer 3 TE-mode */
mISDN_write_frame(m_mISDNdevice, buff, 0, MGR_NEWENTITY | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
ret = mISDN_read_frame(m_mISDNdevice, frm, sizeof(iframe_t), 0, MGR_NEWENTITY | CONFIRM, TIMEOUT_1SEC);
if (ret < (int)mISDN_HEADER_LEN) { ERROR("Cannot request MGR_NEWENTITY from mISDN. header too small.\n");return FAIL; }
m_entity = frm->dinfo & 0xffff;
if (!m_entity) { ERROR("Cannot request MGR_NEWENTITY from mISDN. Exitting due to software bug.\n"); return FAIL; }
DBG("our entity for l3-processes is 0x%08x.\n", m_entity);
m_crcount=1; //entity and crcount is used to generate uniqe addr for outgoing calls
cnt = mISDN_get_stack_count(m_mISDNdevice);
if(cnt<=0) { ERROR("no devices\n"); return FAIL;}
for(port=1;port<=cnt;port++) {
pri = ports = nt = 0;
ret = mISDN_get_stack_info(m_mISDNdevice, port, buff, sizeof(buff));
if (ret < 0) { ERROR("Cannot get stack info for port %d (ret=%d)\n", port, ret); }
stinf = (stack_info_t *)&frm->data.p;
switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK) {
case ISDN_PID_L0_TE_S0: DBG("TE-mode BRI S/T interface line\n"); pri = 0; nt = 0; break;
case ISDN_PID_L0_NT_S0: DBG("NT-mode BRI S/T interface port\n"); pri = 0; nt = 1; break;
case ISDN_PID_L0_TE_E1: DBG("TE-mode PRI E1 interface line\n"); pri = 1; nt = 0; break;
case ISDN_PID_L0_NT_E1: DBG("LT-mode PRI E1 interface port\n"); pri = 1; nt = 1; break;
default:
ERROR("unknown port(%d) type 0x%08x\n", port, stinf->pid.protocol[0]);
}
if (nt) {
DBG("Port %d (nt) proto1=0x%08x proto2=0x%08x\n",port, stinf->pid.protocol[1],stinf->pid.protocol[2]);
if (stinf->pid.protocol[1] == 0) { ERROR("Given port %d: Missing layer 1 NT-mode protocol.\n", port); }
if (stinf->pid.protocol[2]) { ERROR("Given port %d: Layer 2 protocol 0x%08x is detected, but not allowed for NT.\n", port, stinf->pid.protocol[2]); }
ERROR("NT mode not supported yet\n");
return FAIL;
} else { //(te)
DBG("Port %d (te) proto1=0x%08x proto2=0x%08x proto3=0x%08x proto4=0x%08x (nul proto4 is good here)\n",port, stinf->pid.protocol[1],stinf->pid.protocol[2],stinf->pid.protocol[3],stinf->pid.protocol[4]);
if (stinf->pid.protocol[1] == 0) { ERROR("Given port %d: Missing layer 1 protocol.\n", port);}
if (stinf->pid.protocol[2] == 0) { ERROR("Given port %d: Missing layer 2 protocol.\n", port);}
if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP) { ptp=1;DBG("Port %d is point-to-point.\n",port); } else { ptp=0;}
if (stinf->pid.protocol[3] == 0) { ERROR("Given port %d: Missing layer 3 protocol.\n", port);}
else {
switch(stinf->pid.protocol[3] & ~ISDN_PID_FEATURE_MASK) {
case ISDN_PID_L3_DSS1USER: break;
default:
ERROR("Given port %d: own protocol 0x%08x", port,stinf->pid.protocol[3]);
}
}
if (stinf->pid.protocol[4]) { ERROR("Given port %d: Layer 4 protocol not allowed.\n", port); }
}
/* add mISDNport structure */
mISDNportp = &mISDNport_first;
while(*mISDNportp)
mISDNportp = &((*mISDNportp)->next);
mISDNport = (struct mISDNport *)malloc(sizeof(struct mISDNport));
*mISDNportp = mISDNport;
/* allocate ressources of port */
mISDNport->d_stid = stinf->id;
DBG("d_stid = 0x%x.\n", mISDNport->d_stid);
/* create layer intance */
memset(&li, 0, sizeof(li));
strcpy(&li.name[0], "te l4");
li.object_id = -1;
li.extentions = 0;
// li.pid.protocol[4] = ISDN_PID_L4_CAPI20;
li.pid.protocol[4] = ISDN_PID_L4_B_USER;
li.pid.layermask = ISDN_LAYER(4);
li.st = mISDNport->d_stid;
DBG("setting mISDN_new_layer on port %d, li.st=0x%08x \n",port,li.st);
ret = mISDN_new_layer(m_mISDNdevice, &li);
if (ret) { ERROR("Cannot add layer4 of port %d (ret %d)\n", port, ret);
// mISDNport_close(mISDNport);
return FAIL;
}
mISDNport->upper_id = li.id;
ret = mISDN_register_layer(m_mISDNdevice, mISDNport->d_stid, mISDNport->upper_id);
if (ret) { ERROR("Cannot register layer4 of port %d\n", port);
// mISDNport_close(mISDNport);
return FAIL;
}
mISDNport->lower_id = mISDN_get_layerid(m_mISDNdevice, mISDNport->d_stid, 3);
if (mISDNport->lower_id < 0) { ERROR("Cannot get layer(%d) id of port %d\n", nt?1:3, port);
// mISDNport_close(mISDNport);
return FAIL;
}
mISDNport->upper_id = mISDN_get_layerid(m_mISDNdevice, mISDNport->d_stid, 4);
if (mISDNport->upper_id < 0) { ERROR("Cannot get layer4 id of port %d\n", port);
// mISDNport_close(mISDNport);
return FAIL;
}
DBG("Layer 4 of port %d added (0x%08x) lower_id=0x%08x.\n", port,mISDNport->upper_id,mISDNport->lower_id);
mISDNport->b_num = stinf->childcnt;
mISDNport->portnum = port;
mISDNport->ntmode = nt;
mISDNport->pri = pri;
mISDNport->ptp = ptp;
DBG("Port has %d b-channels.\n", mISDNport->b_num);
i = 0;
while(i < mISDNport->b_num) {
mISDNport->b_stid[i] = stinf->child[i];
DBG("b_stid[%d] = 0x%x.\n", i, mISDNport->b_stid[i]);
i++;
}
/* if te-mode, query state link */
// if (!mISDNport->ntmode) {
iframe_t act;
/* L2 */
act.prim = MGR_SHORTSTATUS | REQUEST;
act.addr = mISDNport->upper_id | MSG_BROADCAST;
act.dinfo = SSTATUS_BROADCAST_BIT | SSTATUS_ALL;
act.len = 0;
DBG("sending MGR_SHORTSTATUS request for port %d addr=0x%08x.\n", port,act.addr);
mISDN_write(m_mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
// }
act.prim = PH_ACTIVATE| REQUEST;
act.addr = mISDNport->upper_id | FLG_MSG_DOWN;
act.dinfo = 0;
act.len = 0;
DBG("sending PH_ACTIVATE request (l1 up) for port %d addr=0x%08x.\n", port,act.addr);
mISDN_write(m_mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
/* if ptp AND te-mode, pull up the link */
// if (mISDNport->ptp && !mISDNport->ntmode) {
// iframe_t act;
/* L2 */
act.prim = DL_ESTABLISH | REQUEST;
// act.addr = (mISDNport->upper_id & ~LAYER_ID_MASK) | 4 | FLG_MSG_DOWN;
act.addr = mISDNport->upper_id | FLG_MSG_DOWN;
act.dinfo = 0;
act.len = 0;
DBG("sending DL_ESTABLISH request (l2 up) for port %d addr=0x%08x.\n", port,act.addr);
mISDN_write(m_mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
// }
/* initially, we assume that the link is down, exept for nt-ptmp */
mISDNport->l2link = (mISDNport->ntmode && !mISDNport->ptp)?1:0;
}
return OK;
}
void mISDNStack::on_stop(void) {
unsigned char buff[1025];
DBG("mISDNStack::on_stop\n");
if (m_mISDNdevice >= 0) {
mISDN_write_frame(m_mISDNdevice, buff, 0, MGR_DELENTITY | REQUEST, m_entity, 0, NULL, TIMEOUT_1SEC);
mISDN_close(m_mISDNdevice); m_mISDNdevice = -1;
DBG("mISDN device closed.\n");
}
}
int mISDNStack::GenerateCR() {
int cr;
//llock()
if (m_crcount++ > 0x7fff)
m_crcount = 0x0001;
cr=(m_entity<<16) | m_crcount;
//unlock();
return cr;
}
void mISDNStack::run()
{
DBG("running mISDNStack::run...\n");
char msg_buf[MAX_MSG_SIZE];
int msg_buf_s;
iframe_t* frame;
mISDNport *port;
mISDNChannel* channel;
while(true){
// DBG("tick\n");
msg_buf_s = mISDN_read(m_mISDNdevice,&msg_buf,MAX_MSG_SIZE, TIMEOUT_10SEC);;
if(msg_buf_s == -1){
switch(errno){
case EINTR:
case EAGAIN:
continue;
default: break;
};
ERROR("running mISDNStack::run Error in mISDN_read %s\n",strerror(errno));
break;
}
if(msg_buf_s == 0){/*DBG("got 0, cotinuing\n");*/ continue; }
frame=(iframe_t*)msg_buf;
if (frame->dinfo==(signed long)0xffffffff && frame->prim==(PH_DATA|CONFIRM)) {
ERROR("SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n");
}
// DBG("Got something msg_buf_s=%d prim=0x%08x addr=0x%08x dinfo=0x%08x\n",msg_buf_s,frame->prim,frame->addr,frame->dinfo);
port = mISDNport_first;
while(port) {
if ((frame->addr&MASTER_ID_MASK) == (unsigned int)(port->upper_id&MASTER_ID_MASK))
break;
port = port->next;
}
if (!port) {
ERROR("message belongs to no mISDNport: prim(0x%x) addr(0x%x) msg->len(%d)\n", frame->prim, frame->addr, msg_buf_s);
continue;
}
if (frame->addr&FLG_CHILD_STACK) { /* child stack */
/* b-channel data and messages */
// DBG("processing child stack for %s (%d) prim(0x%x) addr(0x%x) dinfo=0x%x msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr,frame->dinfo, msg_buf_s);
channel=FindBC(frame);
if(channel==NULL) {
DBG("b-channel is not associated to an ISDNPort (address 0x%x), ignoring.\n", frame->addr);
continue;
}
if(channel->bchan_event(msg_buf,msg_buf_s)!=OK)
ERROR("Error processing bchan_event in channel object\n");
continue;
} else { /* d-message */
//next two are debug packet dumps uncomment if needed
l1l2l3_trace_header(port, frame->addr, frame->prim, 1);
if(msg_buf_s>16) DBG("IE: %s",mISDNStack::dumpIE(msg_buf,msg_buf_s).c_str());
/* general messages not(yet) related to CR */
switch(frame->prim) {
case CC_NEW_CR | INDICATION:
DBG("CC_NEW_CR | INDICATION for %s (%d) \n",port->name, port->portnum);
channel=NewCR(port,frame);
continue; break;
case CC_NEW_CR | CONFIRM:
DBG("CC_NEW_CR | CONFIRM for %s (%d) Is this possible?\n",port->name, port->portnum);
continue; break;
case CC_RELEASE_CR | INDICATION:
DBG("CC_RELEASE_CR | INDICATION for %s (%d) \n",port->name, port->portnum);
channel=FindCR(frame);
if(channel!=NULL) {
DBG("should delete channel=%p but we will leave it to have media procesor happy just unregister CR from map\n",channel);
channel->unregister_CR();
// delete(channel);
} else ERROR("Channel not found for CC_RELEASE_CR | INDICATION %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);
continue; break;
case CC_RELEASE_CR | CONFIRM:
DBG("CC_RELEASE_CR | CONFIRM for %s (%d) Is this possible?\n",port->name, port->portnum);
continue; break;
case MGR_SHORTSTATUS | INDICATION:
case MGR_SHORTSTATUS | CONFIRM:
DBG("MGR_SHORTSTATUS ind or confirm for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);
switch(frame->dinfo) {
case SSTATUS_L1_ACTIVATED: port->l1link = 1;DBG("MGR_SHORTSTATUS->SSTATUS_L1_ACTIVATED for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);break;
case SSTATUS_L1_DEACTIVATED: port->l1link = 0;DBG("MGR_SHORTSTATUS->SSTATUS_L1_DEACTIVATED for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);break;
case SSTATUS_L2_ESTABLISHED: port->l2link = 1;DBG("MGR_SHORTSTATUS->SSTATUS_L2_ESTABLISHED for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);break;
case SSTATUS_L2_RELEASED: port->l2link = 0;DBG("MGR_SHORTSTATUS->SSTATUS_L2_RELEASED for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);break;
}
continue; break;
case PH_ACTIVATE | CONFIRM:
case PH_ACTIVATE | INDICATION:
DBG("PH_ACTIVATE ind or confirm for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);
port->l1link = 1;
continue; break;
case PH_DEACTIVATE | CONFIRM:
case PH_DEACTIVATE | INDICATION:
DBG("PH_DEACTIVATE ind or confirm for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);
port->l1link = 0;
continue; break;
case PH_CONTROL | CONFIRM:
case PH_CONTROL | INDICATION:
DBG("Received PH_CONTROL for port %d (%s).\n", port->portnum, port->name);
continue; break;
case DL_ESTABLISH | INDICATION:
case DL_ESTABLISH | CONFIRM:
DBG("DL_ESTABLISH ind or confirm for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);
port->l2link = 1;
continue; break;
case DL_RELEASE | INDICATION:
case DL_RELEASE | CONFIRM:
DBG("DL_RELEASE ind or confirm for %s (%d) prim(0x%x) addr(0x%x) msg->len(%d) \n",port->name, port->portnum, frame->prim, frame->addr, msg_buf_s);
port->l2link = 0;
continue; break;
default:
DBG("GOT d-msg from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (port->ntmode)?"NT":"TE", port->portnum, frame->prim, frame->dinfo, frame->addr);
}
/* d-message */
if (port->ntmode) {
ERROR("NT mode not supported yet\n");
continue;
} else {
/* l3-data is sent to channel object for processing */
channel=FindCR(frame);
if(channel==NULL) {
ERROR("Cant find channel for message\n");
continue;
}
if(channel->processMsg(msg_buf,msg_buf_s)!=OK)
ERROR("Error processing msg in channel object\n");
continue;
}
}
}
}
////////////////////////////////////////////////////////////////
void mISDNStack::l1l2l3_trace_header(struct mISDNport *mISDNport, int port, unsigned long prim, int direction)
{
string msgtext;
msgtext.assign(mISDNNames::Message(prim&0xffffff00));
msgtext.append(mISDNNames::isdn_prim[prim&0x00000003]);
/* add direction */
if (direction && (prim&0xffffff00)!=CC_NEW_CR && (prim&0xffffff00)!=CC_RELEASE_CR) {
if (mISDNport) {
if (mISDNport->ntmode) { if (direction == DIRECTION_OUT) msgtext.append(" N->U"); else msgtext.append(" N<-U"); }
else { if (direction == DIRECTION_OUT) msgtext.append(" U->N"); else msgtext.append(" U<-N"); }
}
}
DBG("prim=0x%08lx port=0x%08x %s\n",prim,port, msgtext.c_str());
}
#define QI_DUMP(_x_,_y_) sprintf(x," %25s off=0x%04x ridx=0x%04x res1=0x%04x cs_flg=0x%04x",_y_,qi->_x_.off,qi->_x_.ridx,qi->_x_.res1,qi->_x_.cs_flg);ret.append(x);\
if(qi->_x_.off>0) {sprintf(x," 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",\
y[qi->_x_.off],\
y[qi->_x_.off+1],\
y[qi->_x_.off+2],\
y[qi->_x_.off+3]\
);ret.append(x);} else ret.append(" \n");
std::string mISDNStack::dumpIE(char *buf,int len) {
Q931_info_t* qi;
ie_info_t *ie;
char buf2[MAX_MSG_SIZE];
u16 *arr;
char *p,*x,*y;
std::string ret,tmp_a,tmp_b;
int i,j;
qi = (Q931_info_t*)(buf + mISDN_HEADER_LEN);
x =(char*)&buf2;
arr=(u16 *)qi;
ie=&(qi->bearer_capability);
p=(char*)qi;
y=p;
y+=L3_EXTRA_SIZE;
sprintf(x,"type=0x%02hhx crlen=0x%02hhx cr=0x%04x\n",qi->type,qi->crlen,qi->cr);ret.append(x);
for(i=0;i<37;i++) {
if(ie[i].off>0) {
sprintf(x," %25s off=0x%04x ridx=0x%04x res1=0x%04x cs_flg=0x%04x",mISDNNames::IE_Names[i],ie[i].off,ie[i].ridx,ie[i].res1,ie[i].cs_flg);ret.append(x);
tmp_a.assign("");tmp_b.assign(" ");
for(j=0;j<y[ie[i].off+1];j++) {
sprintf(x," 0x%02hhx",y[ie[i].off+2+j]);tmp_a.append(x);
sprintf(x,"%c",(y[ie[i].off+2+j]>32)?y[ie[i].off+2+j]:'.');tmp_b.append(x);
}
ret.append(tmp_a);ret.append(tmp_b);ret.append("\n");
if((ie[i].repeated>0) || (ie[i].ridx>0)) {
QI_DUMP(ext[i].ie,"extinfo ")
sprintf(x," extinfo[%d]: cs.codeset=0x%04x cs.locked=0x%04x cs.res1=0x%04x cs.len=0x%04x | v.codeset=0x%04x v.res1=0x%04x v.val=0x%04x\n",
i,qi->ext[i].cs.codeset,qi->ext[i].cs.locked,qi->ext[i].cs.res1,qi->ext[i].cs.len,
qi->ext[i].v.codeset,qi->ext[i].v.res1,qi->ext[i].v.val);
ret.append(x);
}
}
}
ret.append("=========================\n");
for(i=0;i<=(len-mISDN_HEADER_LEN)/2;i++) {
sprintf(x," 0x%04x (%c %c),",arr[i],
(p[2*i]>=32)?p[2*i]:'.',
((p[2*i+1])>=32)?p[2*i+1]:'.');
ret.append(x);
}
ret.append("\n");
if(len>(mISDN_HEADER_LEN+L3_EXTRA_SIZE)) {
ret.append("tail:");
for(i=0;i<=(len-(mISDN_HEADER_LEN+L3_EXTRA_SIZE));i++) {
sprintf(x," 0x%02hhx (%c),",y[i],(y[i]>32)?y[i]:'.');ret.append(x);
}
ret.append("\n");
} else ret.append("no tail\n");
return ret;
}

@ -0,0 +1,89 @@
#ifndef _MISDNSTACK_H_
#define _MISDNSTACK_H_
#include <pthread.h>
#include "globals.h"
namespace mISDN { //this is hack to cover definition of dprint which is defined in mISDN and sems core
extern "C" {
#include <mISDNuser/mISDNlib.h>
#include <mISDNuser/net_l2.h>
#include <mISDNuser/l3dss1.h>
}
}
#include "GWSession.h"
class mISDNChannel; //forward
struct mISDNport {
mISDN::net_stack_t nst; /* MUST be the first entry, so &nst equals &mISDNlist */
mISDN::manager_t mgr;
int upper_id; /* id to transfer data down */
int lower_id; /* id to transfer data up */
int d_stid;
// mISDN::msg_queue_t downqueue; /* l4->l3 */
struct mISDNport *next;
char name[64]; /* name of port, if available */
int portnum; /* port number 1..n */
int ptp; /* if ptp is set, we keep track of l2link */
int l1link; /* if l1 is available */
int l2link; /* if l2 is available */
int use; /* counts the number of port that uses this port */
int ntmode; /* is TRUE if port is nt mode */
int pri; /* is TRUE if port is a primary rate interface */
int b_num; /* number of bchannels */
class mISDNChannel *b_port[128]; /* bchannel assigned to port object */
int b_stid[128]; /* stack ids */
unsigned long b_addr[128]; /* addresses on b-channels */
int b_state[128]; /* statemachine, 0 = IDLE */
};
//forward declaration;
class mISDNChannel;
class mISDNStack: public AmThread
{
static mISDNStack* _instance;
int init();
void run();
void on_stop();
public:
mISDNStack();
~mISDNStack();
int placeCall(const AmSipRequest &req, GWSession *session, const std::string &tonumber, const std::string &fromnumber);
int m_mISDNdevice;
int m_entity;
int m_crcount;
mISDNport *mISDNport_first;
/* here are some maps and functions to lookup CallReference and B-channel number and decide to which channel object pass message */
std::map<int,mISDNChannel*> CR_map;
std::map<int,mISDNChannel*> BC_map;
mISDNChannel* NewCR(mISDNport *port,mISDN::iframe_t *frame);
mISDNChannel* FindCR(mISDN::iframe_t *frame);
mISDNChannel* FindBC(mISDN::iframe_t *frame);
static mISDNStack* instance();
static int GetPortInfo();
int GenerateCR();
void l1l2l3_trace_header(struct mISDNport *mISDNport, int port, unsigned long prim, int direction);
std::string dumpIE(char *buf,int len);
};
#define DIRECTION_NONE 0
#define DIRECTION_OUT 1
#define DIRECTION_IN 2
enum {
B_STATE_IDLE, /* not open */
B_STATE_ACTIVATING, /* DL_ESTABLISH sent */
B_STATE_ACTIVE, /* channel active */
B_STATE_DEACTIVATING, /* DL_RELEASE sent */
B_STATE_EXPORTING, /* BCHANNEL_ASSIGN sent */
B_STATE_REMOTE, /* bchannel assigned to remote application */
B_STATE_IMPORTING, /* BCHANNEL_REMOVE sent */
};
#define ISDN_PID_L3_B_USER 0x430000ff
#define ISDN_PID_L4_B_USER 0x440000ff
#endif
Loading…
Cancel
Save