diff --git a/modules/libypri.cpp b/modules/libypri.cpp index 3819727b..2385c39d 100644 --- a/modules/libypri.cpp +++ b/modules/libypri.cpp @@ -1,8 +1,8 @@ /** - * wpchan.cpp + * libypri.cpp * This file is part of the YATE Project http://YATE.null.ro * - * Wanpipe PRI cards telephony driver + * Common C++ base classes for PRI cards telephony drivers * * Yet Another Telephony Engine - a fully featured software PBX and IVR * Copyright (C) 2004 Null Team @@ -26,7 +26,6 @@ extern "C" { -#include extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req); #ifndef _WINDOWS @@ -64,21 +63,6 @@ static void pri_msg_cb(char *s) Debug("PRI",DebugInfo,"%s",s); } -#define bitswap(v) bitswap_table[v] - -static unsigned char bitswap_table[256]; - -static void bitswap_init() -{ - for (unsigned int c = 0; c <= 255; c++) { - unsigned char v = 0; - for (int b = 0; b <= 7; b++) - if (c & (1 << b)) - v |= (0x80 >> b); - bitswap_table[c] = v; - } -} - /* Switch types */ static TokenDict dict_str2switch[] = { { "unknown", PRI_SWITCH_UNKNOWN }, @@ -183,6 +167,12 @@ static TokenDict dict_str2nsf[] = { { 0, -1 } }; +static TokenDict dict_str2cause[] = { + { "noroute", PRI_CAUSE_NO_ROUTE_DESTINATION }, + { "noconn", PRI_CAUSE_REQUESTED_CHAN_UNAVAIL }, + { 0, -1 } +}; + /* Layer 1 formats */ static TokenDict dict_str2law[] = { { "mulaw", PRI_LAYER_1_ULAW }, @@ -236,128 +226,62 @@ unsigned char Fifo::get() return tmp; } -WanpipePlugin wplugin; -u_int64_t PriSpan::restartPeriod = 0; -bool PriSpan::dumpEvents = false; - -#define WP_HEADER 16 - -static int wp_read(struct pri *pri, void *buf, int buflen) +PriSpan::PriSpan(struct pri *_pri, PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect) + : m_span(span), m_offs(first), m_nchans(chans), m_bchans(0), + m_pri(_pri), m_restart(0), m_chans(0), m_ok(false) { - buflen -= 2; - int sz = buflen+WP_HEADER; - char *tmp = (char*)::calloc(sz,1); - XDebug("wp_read",DebugAll,"pre buf=%p len=%d tmp=%p sz=%d",buf,buflen,tmp,sz); - int r = ::recv(::pri_fd(pri),tmp,sz,MSG_NOSIGNAL); - XDebug("wp_read",DebugAll,"post r=%d",r); - if (r > 0) { - r -= WP_HEADER; - if ((r > 0) && (r <= buflen)) { - ::memcpy(buf,tmp+WP_HEADER,r); - r += 2; - } + int dchan = -1; + // guess where we may have a D channel + switch (chans) { + case 3: // BRI ISDN + dchan = 3; + break; + case 24: // T1 with CCS + dchan = 24; + break; + case 31: // EuroISDN + dchan = 16; + break; } - ::free(tmp); - return r; -} + dchan = cfg->getIntValue(sect,"dchan", dchan), -static int wp_write(struct pri *pri, void *buf, int buflen) -{ - buflen -= 2; - int sz = buflen+WP_HEADER; - char *tmp = (char*)::calloc(sz,1); - ::memcpy(tmp+WP_HEADER,buf,buflen); - XDebug("wp_write",DebugAll,"pre buf=%p len=%d tmp=%p sz=%d",buf,buflen,tmp,sz); - int w = ::send(::pri_fd(pri),tmp,sz,0); - XDebug("wp_write",DebugAll,"post w=%d",w); - if (w > 0) { - w -= WP_HEADER; - w += 2; - } - ::free(tmp); - return w; -} - -PriSpan *PriSpan::create(int span, int chan1, int nChans, int dChan, int netType, - int switchType, int dialPlan, int presentation, - int overlapDial, int nsf) -{ - int fd = ::socket(AF_WANPIPE, SOCK_RAW, 0); - if (fd < 0) - return 0; - struct pri *p = makePri(fd, - (dChan >= 0) ? dChan+chan1-1 : -1, - netType, - switchType, overlapDial, nsf); - if (!p) { - ::close(fd); - return 0; - } - PriSpan *ps = new PriSpan(p,span,chan1,nChans,dChan,fd,dialPlan,presentation,overlapDial); - ps->startup(); - return ps; -} - -struct pri *PriSpan::makePri(int fd, int dchan, int nettype, int swtype, - int overlapDial, int nsf) -{ - if (dchan >= 0) { - // Set up the D channel if we have one - struct wan_sockaddr_ll sa; - memset(&sa,0,sizeof(struct wan_sockaddr_ll)); - ::strcpy( (char*)sa.sll_device, "w1g2"); - ::strcpy( (char*)sa.sll_card, "wanpipe1"); - sa.sll_protocol = htons(PVC_PROT); - sa.sll_family=AF_WANPIPE; - if (::bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - Debug("PriSpan",DebugGoOn,"Failed to bind %d: error %d: %s", - fd,errno,::strerror(errno)); - return 0; - } - } - struct pri *ret = ::pri_new_cb(fd, nettype, swtype, wp_read, wp_write, 0); -#ifdef PRI_NSF_NONE - if (ret) - ::pri_set_nsf(ret, nsf); -#endif + m_dplan = cfg->getIntValue(sect,"dialplan",dict_str2dplan,PRI_UNKNOWN); + m_pres = cfg->getIntValue(sect,"presentation",dict_str2pres,PRES_ALLOWED_USER_NUMBER_NOT_SCREENED); + m_restartPeriod = cfg->getIntValue(sect,"restart") * (u_int64_t)1000000; + m_dumpEvents = cfg->getBoolValue(sect,"dumpevents"); + m_overlapped = cfg->getIntValue(sect,"overlapdial"); + if (m_overlapped < 0) + m_overlapped = 0; #ifdef PRI_SET_OVERLAPDIAL - if (ret) - ::pri_set_overlapdial(ret, (overlapDial > 0)); + ::pri_set_overlapdial(m_pri, (m_overlapped > 0)); #endif - return ret; -} +#ifdef PRI_NSF_NONE + ::pri_set_nsf(m_pri,cfg->getIntValue(sect,"facilities",dict_str2nsf,YATE_NSF_DEFAULT)); +#endif + ::pri_set_userdata(m_pri, this); -PriSpan::PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres, int overlapDial) - : Thread("PriSpan"), m_span(span), m_offs(first), m_nchans(chans), m_bchans(0), - m_fd(fd), m_dplan(dplan), m_pres(pres), m_overlapped(0), m_pri(_pri), - m_restart(0), m_chans(0), m_data(0), m_ok(false) -{ - Debug(DebugAll,"PriSpan::PriSpan(%p,%d,%d,%d) [%p]",_pri,span,chans,fd,this); - if (overlapDial > 0) - m_overlapped = overlapDial; - WpChan **ch = new WpChan* [chans]; + PriChan **ch = new PriChan* [chans]; for (int i = 1; i <= chans; i++) { if (i != dchan) { - ch[i-1] = new WpChan(this,i,s_buflen); + ch[i-1] = create(i); m_bchans++; } else ch[i-1] = 0; } + m_chans = ch; - wplugin.m_spans.append(this); - WpData* dat = new WpData(this); - dat->startup(); + m_restart = Time::now() + m_restartPeriod; + m_driver->m_spans.append(this); } PriSpan::~PriSpan() { Debug(DebugAll,"PriSpan::~PriSpan() [%p]",this); - wplugin.m_spans.remove(this,false); + m_driver->m_spans.remove(this,false); m_ok = false; - delete m_data; for (int i = 0; i < m_nchans; i++) { - WpChan *c = m_chans[i]; + PriChan *c = m_chans[i]; m_chans[i] = 0; if (c) { c->hangup(PRI_CAUSE_NORMAL_UNSPECIFIED); @@ -365,41 +289,22 @@ PriSpan::~PriSpan() } } delete[] m_chans; - ::close(m_fd); } -void PriSpan::run() +void PriSpan::runEvent(bool idleRun) { - Debug(DebugAll,"PriSpan::run() [%p]",this); - m_restart = Time::now() + restartPeriod; - ::pri_set_userdata(m_pri, this); - fd_set rdfds; - fd_set errfds; - for (;;) { - FD_ZERO(&rdfds); - FD_SET(m_fd, &rdfds); - FD_ZERO(&errfds); - FD_SET(m_fd, &errfds); - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100; - int sel = ::select(m_fd+1, &rdfds, NULL, &errfds, &tv); - pri_event *ev = 0; - Lock lock(wplugin.mutex); - if (!sel) { - ev = ::pri_schedule_run(m_pri); - idle(); - } - else if (sel > 0) - ev = ::pri_check_event(m_pri); - else if (errno != EINTR) - Debug("PriSpan",DebugGoOn,"select() error %d: %s", - errno,::strerror(errno)); - if (ev) { - if (dumpEvents && debugAt(DebugAll)) - ::pri_dump_event(m_pri, ev); - handleEvent(*ev); - } + Lock lock(m_driver); + pri_event *ev = 0; + if (idleRun) { + ev = ::pri_schedule_run(m_pri); + idle(); + } + else + ev = ::pri_check_event(m_pri); + if (ev) { + if (m_dumpEvents && debugAt(DebugAll)) + ::pri_dump_event(m_pri, ev); + handleEvent(*ev); } } @@ -407,8 +312,8 @@ void PriSpan::idle() { if (!m_chans) return; - if (restartPeriod && (Time::now() > m_restart)) { - m_restart = Time::now() + restartPeriod; + if (m_restartPeriod && (Time::now() > m_restart)) { + m_restart = Time::now() + m_restartPeriod; Debug("PriSpan",DebugInfo,"Restarting idle channels on span %d",m_span); for (int i=0; iring(ev.call); - if (m_overlapped && !ev.complete) { - if (::strlen(ev.callednum) < m_overlapped) { - ::pri_need_more_info(pri(),ev.call,chan,!c->isISDN()); - return; - } - } - Message *m = new Message("call.route"); - m->addParam("driver","wp"); - m->addParam("id",c->id()); - m->addParam("span",String(m_span)); - m->addParam("channel",String(chan)); - if (ev.callingnum[0]) - m->addParam("caller",ev.callingnum); - if (ev.callednum[0]) - m->addParam("called",ev.callednum); - if (m_overlapped && !ev.complete) - m->addParam("overlapped","yes"); - const char* dataLaw = "slin"; - switch (ev.layer1) { - case PRI_LAYER_1_ALAW: - dataLaw = "alaw"; - break; - case PRI_LAYER_1_ULAW: - dataLaw = "mulaw"; - break; - } - m->addParam("format",dataLaw); - if (Engine::dispatch(m)) { - *m = "call.execute"; - m->addParam("callto",m->retValue()); - m->retValue().clear(); - c->open(dataLaw); - m->userData(getChan(chan)); - if (Engine::dispatch(m)) { - c->setTarget(m->getValue("targetid")); - if (c->getTarget().null()) { - Debug(DebugInfo,"Answering now chan %s [%p] because we have no targetid", - c->id().c_str(),c); - c->answer(); - } - else - getChan(chan)->setTimeout(60000000); - } - else - getChan(chan)->hangup(PRI_CAUSE_REQUESTED_CHAN_UNAVAIL); - } - else - getChan(chan)->hangup(PRI_CAUSE_NO_ROUTE_DESTINATION); - delete m; + PriChan* c = getChan(chan); + if (c) + c->ring(ev); } void PriSpan::infoChan(int chan, pri_event_ring &ev) @@ -654,177 +511,49 @@ void PriSpan::proceedingChan(int chan) getChan(chan)->setTimeout(60000000); } -WpSource::WpSource(WpChan *owner,unsigned int bufsize,const char* format) - : DataSource(format), - m_owner(owner), m_bufpos(0), m_buf(0,bufsize) +PriSource::PriSource(PriChan *owner, unsigned int bufsize) + : DataSource(0), + m_owner(owner), m_buffer(0,bufsize) { - Debug(DebugAll,"WpSource::WpSource(%p) [%p]",owner,this); - m_owner->m_wp_s = this; + Debug(DebugAll,"PriSource::PriSource(%p) [%p]",owner,this); } -WpSource::~WpSource() +PriSource::~PriSource() { - Debug(DebugAll,"WpSource::~WpSource() [%p]",this); - m_owner->m_wp_s = 0; + Debug(DebugAll,"PriSource::~PriSource() [%p]",this); } -void WpSource::put(unsigned char val) +PriConsumer::PriConsumer(PriChan *owner, unsigned int bufsize) + : DataConsumer(0), + m_owner(owner), m_buffer(0,bufsize) { - ((char*)m_buf.data())[m_bufpos] = val; - if (++m_bufpos >= m_buf.length()) { - m_bufpos = 0; - Forward(m_buf); - } + Debug(DebugAll,"PriConsumer::PriConsumer(%p) [%p]",owner,this); } -WpConsumer::WpConsumer(WpChan *owner,unsigned int bufsize,const char* format) - : DataConsumer(format), Fifo(2*bufsize), - m_owner(owner) +PriConsumer::~PriConsumer() { - Debug(DebugAll,"WpConsumer::WpConsumer(%p) [%p]",owner,this); - m_owner->m_wp_c = this; + Debug(DebugAll,"PriConsumer::~PriConsumer() [%p]",this); } -WpConsumer::~WpConsumer() +PriChan::PriChan(PriSpan *parent, int chan, unsigned int bufsize) + : Channel(parent->driver()), m_span(parent), m_chan(chan), m_ring(false), + m_timeout(0), m_call(0), m_bufsize(bufsize) { - Debug(DebugAll,"WpConsumer::~WpConsumer() [%p]",this); - m_owner->m_wp_c = 0; -} - -void WpConsumer::Consume(const DataBlock &data, unsigned long timeDelta) -{ - const unsigned char* buf = (const unsigned char*)data.data(); - for (unsigned int i = 0; i < data.length(); i++) - put(buf[i]); -} - -WpData::WpData(PriSpan* span) - : Thread("WpData"), m_span(span), m_fd(-1), m_buffer(0), m_chans(0) -{ - Debug(DebugAll,"WpData::WpData(%p) [%p]",span,this); - int fd = ::socket(AF_WANPIPE, SOCK_RAW, 0); - if (fd >= 0) { - // Set up the B channel group - struct wan_sockaddr_ll sa; - memset(&sa,0,sizeof(struct wan_sockaddr_ll)); - ::strcpy( (char*)sa.sll_device, "w1g1"); - ::strcpy( (char*)sa.sll_card, "wanpipe1"); - sa.sll_protocol = htons(PVC_PROT); - sa.sll_family=AF_WANPIPE; - if (::bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - Debug("PriSpan",DebugGoOn,"Failed to bind %d: error %d: %s", - fd,errno,::strerror(errno)); - ::close(fd); - } - else { - m_fd = fd; - m_span->m_data = this; - } - } -} - -WpData::~WpData() -{ - Debug(DebugAll,"WpData::~WpData() [%p]",this); - m_span->m_data = 0; - if (m_fd >= 0) - ::close(m_fd); - if (m_buffer) - ::free(m_buffer); - if (m_chans) - delete[] m_chans; -} - -void WpData::run() -{ - Debug(DebugAll,"WpData::run() [%p]",this); - int samp = 50; - int bchans = m_span->bchans(); - int buflen = samp*bchans; - int sz = buflen+WP_HEADER; - m_buffer = (unsigned char*)::malloc(sz); - // Build a compacted list of allocated B channels - m_chans = new WpChan* [bchans]; - int b = 0; - for (int n = 0; n < bchans; n++) { - while (!m_span->m_chans[b]) - b++; - m_chans[n] = m_span->m_chans[b++]; - DDebug("wpdata_chans",DebugInfo,"ch[%d]=%d (%p)",n,m_chans[n]->chan(),m_chans[n]); - } - fd_set rdfds,oobfds; - while (m_span && (m_fd >= 0)) { - FD_ZERO(&rdfds); - FD_ZERO(&oobfds); - FD_SET(m_fd, &rdfds); - FD_SET(m_fd, &oobfds); - if (::select(m_fd+1, &rdfds, NULL, &oobfds, NULL) <= 0) - continue; - - if (FD_ISSET(m_fd, &oobfds)) { - DDebug("wpdata_recv_oob",DebugAll,"pre buf=%p len=%d sz=%d",m_buffer,buflen,sz); - int r = ::recv(m_fd,m_buffer,sz,MSG_OOB); - DDebug("wpdata_recv_oob",DebugAll,"post r=%d",r); - } - - if (FD_ISSET(m_fd, &rdfds)) { - XDebug("wpdata_recv",DebugAll,"pre buf=%p len=%d sz=%d",m_buffer,buflen,sz); - int r = ::recv(m_fd,m_buffer,sz,0/*MSG_NOSIGNAL*/); - XDebug("wpdata_recv",DebugAll,"post r=%d",r); - r -= WP_HEADER; - // We should have read N bytes for each B channel - if ((r > 0) && ((r % bchans) == 0)) { - r /= bchans; - const unsigned char* dat = m_buffer + WP_HEADER; - wplugin.mutex.lock(); - for (int n = r; n > 0; n--) - for (b = 0; b < bchans; b++) { - WpSource *s = m_chans[b]->m_wp_s; - if (s) - s->put(bitswap(*dat)); - dat++; - } - wplugin.mutex.unlock(); - } - int w = samp; - ::memset(m_buffer,0,WP_HEADER); - unsigned char* dat = m_buffer + WP_HEADER; - wplugin.mutex.lock(); - for (int n = w; n > 0; n--) { - for (b = 0; b < bchans; b++) { - WpConsumer *c = m_chans[b]->m_wp_c; - *dat++ = bitswap(c ? c->get() : 0xff); - } - } - wplugin.mutex.unlock(); - w = (w * bchans) + WP_HEADER; - XDebug("wpdata_send",DebugAll,"pre buf=%p len=%d sz=%d",m_buffer,w,sz); - w = ::send(m_fd,m_buffer,w,MSG_DONTWAIT); - XDebug("wpdata_send",DebugAll,"post w=%d",w); - } - } -} - -WpChan::WpChan(PriSpan *parent, int chan, unsigned int bufsize) - : DataEndpoint("wanpipe"), m_span(parent), m_chan(chan), m_ring(false), - m_timeout(0), m_call(0), m_bufsize(bufsize), m_wp_s(0), m_wp_c(0) -{ - Debug(DebugAll,"WpChan::WpChan(%p,%d) [%p]",parent,chan,this); + Debug(DebugAll,"PriChan::PriChan(%p,%d) [%p]",parent,chan,this); // I hate counting from one... m_abschan = m_chan+m_span->chan1()-1; m_isdn = true; - m_id << "wp/" << m_abschan; } -WpChan::~WpChan() +PriChan::~PriChan() { - Debug(DebugAll,"WpChan::~WpChan() [%p] %d",this,m_chan); + Debug(DebugAll,"PriChan::~PriChan() [%p] %d",this,m_chan); hangup(PRI_CAUSE_NORMAL_UNSPECIFIED); } -void WpChan::disconnected(bool final, const char *reason) +void PriChan::disconnected(bool final, const char *reason) { - Debugger debug("WpChan::disconnected()", " '%s' [%p]",reason,this); + Debugger debug("PriChan::disconnected()", " '%s' [%p]",reason,this); if (!final) { Message m("chan.disconnected"); m.addParam("driver","wp"); @@ -833,35 +562,35 @@ void WpChan::disconnected(bool final, const char *reason) m.addParam("channel",String(m_chan)); if (m_targetid) { m.addParam("targetid",m_targetid); - setTarget(); + m_targetid.clear(); } m.addParam("reason",reason); Engine::enqueue(m); } - wplugin.mutex.lock(); + driver()->lock(); hangup(PRI_CAUSE_NORMAL_CLEARING); - wplugin.mutex.unlock(); + driver()->unlock(); } -bool WpChan::nativeConnect(DataEndpoint *peer) +bool PriChan::nativeConnect(DataEndpoint *peer) { return false; } -const char *PriChan::status() const +const char *PriChan::chanStatus() const { if (m_ring) return "ringing"; if (m_call) return m_timeout ? "calling" : "connected"; - return m_span->outOfOrder() ? "down" : "idle"; + return m_span->outOfOrder() ? "alarm" : "idle"; } -void WpChan::idle() +void PriChan::idle() { if (m_timeout && (Time::now() > m_timeout)) { - Debug("WpChan",DebugWarn,"Timeout %s channel %d on span %d", - status(),m_chan,m_span->span()); + Debug("PriChan",DebugWarn,"Timeout %s channel %s (%d/%d)", + chanStatus(),id().c_str(),m_chan,m_span->span()); m_timeout = 0; hangup(PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE); } @@ -877,49 +606,42 @@ void PriChan::restart(bool outgoing) void PriChan::closeData() { - wplugin.mutex.lock(); + driver()->lock(); setSource(); setConsumer(); - wplugin.mutex.unlock(); -} - -bool WpChan::openData(const char* format) -{ - setSource(new WpSource(this,m_bufsize,format)); - getSource()->deref(); - setConsumer(new WpConsumer(this,m_bufsize,format)); - getConsumer()->deref(); - return true; + driver()->unlock(); } bool PriChan::answer() { if (!m_ring) { Debug("PriChan",DebugWarn,"Answer request on %s channel %d on span %d", - status(),m_chan,m_span->span()); + chanStatus(),m_chan,m_span->span()); return false; } m_ring = false; m_timeout = 0; Output("Answering on %s (%d/%d)",id().c_str(),m_span->span(),m_chan); - ::pri_answer(m_span->pri(),m_call,m_chan,!m_isdn); + ::pri_answer(m_span->pri(),(q931_call*)m_call,m_chan,!m_isdn); return true; } void PriChan::hangup(int cause) { + if (!cause) + cause = PRI_CAUSE_INVALID_MSG_UNSPECIFIED; const char *reason = pri_cause2str(cause); if (inUse()) Debug(DebugInfo,"Hanging up %s in state %s: %s (%d)", - id().c_str(),status(),reason,cause); + id().c_str(),chanStatus(),reason,cause); m_timeout = 0; - setTarget(); + m_targetid.clear(); disconnect(reason); closeData(); m_ring = false; if (m_call) { - ::pri_hangup(m_span->pri(),m_call,cause); - ::pri_destroycall(m_span->pri(),m_call); + ::pri_hangup(m_span->pri(),(q931_call*)m_call,cause); + ::pri_destroycall(m_span->pri(),(q931_call*)m_call); m_call = 0; Message *m = new Message("chan.hangup"); m->addParam("driver","wp"); @@ -935,7 +657,7 @@ void PriChan::answered() { if (!m_call) { Debug("PriChan",DebugWarn,"Answer detected on %s %s channel %d on span %d", - status(),id().c_str(),m_chan,m_span->span()); + chanStatus(),id().c_str(),m_chan,m_span->span()); return; } m_timeout = 0; @@ -967,7 +689,7 @@ void PriChan::gotDigits(const char *digits) void PriChan::sendDigit(char digit) { if (m_call) - ::pri_information(m_span->pri(),m_call,digit); + ::pri_information(m_span->pri(),(q931_call*)m_call,digit); } bool PriChan::call(Message &msg, const char *called) @@ -982,11 +704,12 @@ bool PriChan::call(Message &msg, const char *called) called, m_chan,m_span->span()); int layer1 = lookup(msg.getValue("format"),dict_str2law,-1); hangup(PRI_CAUSE_PRE_EMPTED); - DataEndpoint *dd = static_cast(msg.userData()); - if (dd) { + setOutgoing(true); + Channel *ch = static_cast(msg.userData()); + if (ch) { openData(lookup(layer1,dict_str2law)); - connect(dd); - setTarget(msg.getValue("id")); + connect(ch); + m_targetid = msg.getValue("id"); msg.addParam("targetid",id()); } else @@ -1009,7 +732,7 @@ bool PriChan::call(Message &msg, const char *called) ::pri_sr_set_called(req,(char *)called,calledplan,1/*complete*/); ::q931_setup(span()->pri(),m_call,req); #else - ::pri_call(m_span->pri(),m_call,0/*transmode*/,m_chan,1/*exclusive*/,!m_isdn, + ::pri_call(m_span->pri(),(q931_call*)m_call,0/*transmode*/,m_chan,1/*exclusive*/,!m_isdn, caller,callerplan,callername,callerpres,(char *)called,calledplan,layer1 ); #endif @@ -1024,14 +747,16 @@ bool PriChan::call(Message &msg, const char *called) return true; } -void PriChan::ring(q931_call *call) +void PriChan::ring(pri_event_ring &ev) { + q931_call *call = ev.call; if (call) { setTimeout(10000000); + setOutgoing(false); m_call = call; m_ring = true; ::pri_acknowledge(m_span->pri(),m_call,m_chan,0); - Message *m = new Message("chan.startup"); + Message *m = message("chan.startup"); m->addParam("driver","wp"); m->addParam("id",id()); m->addParam("span",String(m_span->span())); @@ -1041,166 +766,131 @@ void PriChan::ring(q931_call *call) } else hangup(PRI_CAUSE_WRONG_CALL_STATE); + + Message *m = message("call.route"); + if (m_span->overlapped() && !ev.complete && (::strlen(ev.callednum) < m_span->overlapped())) { + ::pri_need_more_info(m_span->pri(),m_call,m_chan,!isISDN()); + m->addParam("overlapped","yes"); + } + if (ev.callingnum[0]) + m->addParam("caller",ev.callingnum); + if (ev.callednum[0]) + m->addParam("called",ev.callednum); + const char* dataLaw = "slin"; + switch (ev.layer1) { + case PRI_LAYER_1_ALAW: + dataLaw = "alaw"; + break; + case PRI_LAYER_1_ULAW: + dataLaw = "mulaw"; + break; + } + m->addParam("format",dataLaw); + if (!startRouter(m)) + hangup(PRI_CAUSE_SWITCH_CONGESTION); } -bool WpHandler::received(Message &msg) +void PriChan::callAccept(Message& msg) { - String dest(msg.getValue("callto")); - if (dest.null()) - return false; - Regexp r("^wp/\\([^/]*\\)/\\?\\(.*\\)$"); + Debug(DebugAll,"PriChan::callAccept() [%p]",this); + setTimeout(60000000); + Channel::callAccept(msg); +} + +void PriChan::callReject(const char* error, const char* reason) +{ + int cause = lookup(error,dict_str2cause,PRI_CAUSE_NETWORK_OUT_OF_ORDER); + hangup(cause); +} + +bool PriChan::msgDrop(Message& msg, const char* reason) +{ + if (inUse()) { + hangup(PRI_CAUSE_INTERWORKING); + return true; + } + return false; +} + + +bool PriDriver::msgExecute(Message& msg, String& dest) +{ + Regexp r("^\\([^/]*\\)/\\?\\(.*\\)$"); if (!dest.matches(r)) return false; if (!msg.userData()) { - Debug(DebugWarn,"Wanpipe call found but no data channel!"); + Debug(DebugWarn,"Pri call found but no data channel!"); return false; } String chan = dest.matchString(1); String num = dest.matchString(2); - DDebug(DebugInfo,"Found call to Wanpipe chan='%s' name='%s'", + DDebug(DebugInfo,"Found call to pri chan='%s' name='%s'", chan.c_str(),num.c_str()); - WpChan *c = 0; + PriChan *c = 0; r = "^\\([0-9]\\+\\)-\\([0-9]*\\)$"; - Lock lock(wplugin.mutex); + Lock lock(this); if (chan.matches(r)) - c = wplugin.findChan(chan.matchString(1).toInteger(), + c = find(chan.matchString(1).toInteger(), chan.matchString(2).toInteger(65535)); else - c = wplugin.findChan(chan.toInteger(-1)); + c = find(chan.toInteger(-1)); if (c) { - Debug(DebugInfo,"Will call '%s' on chan wp/%d (%d/%d)", - num.c_str(),c->absChan(),c->span()->span(),c->chan()); + Debug(DebugInfo,"Will call '%s' on chan %s (%d/%d)", + num.c_str(),c->id().c_str(),c->span()->span(),c->chan()); return c->call(msg,num); } else - Debug(DebugWarn,"No free Wanpipe channel '%s'",chan.c_str()); + Debug(DebugWarn,"No free Pri channel '%s'",chan.c_str()); return false; } -bool WpDropper::received(Message &msg) +void PriDriver::dropAll() { - String id(msg.getValue("id")); - if (id.null()) { - Debug("WpDropper",DebugInfo,"Dropping all calls"); - wplugin.mutex.lock(); - const ObjList *l = &wplugin.m_spans; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - for (int n=1; n<=s->chans(); n++) { - WpChan *c = s->getChan(n); - if (c) - c->hangup(PRI_CAUSE_INTERWORKING); - } - } - } - wplugin.mutex.unlock(); - return false; - } - if (!id.startsWith("wp/")) - return false; - WpChan *c = 0; - id >> "wp/"; - int n = id.toInteger(); - if ((n > 0) && (c = wplugin.findChan(n))) { - Debug("WpDropper",DebugInfo,"Dropping wp/%d (%d/%d)", - n,c->span()->span(),c->chan()); - wplugin.mutex.lock(); - c->hangup(PRI_CAUSE_INTERWORKING); - wplugin.mutex.unlock(); - return true; - } - Debug("WpDropper",DebugInfo,"Could not find wp/%s",id.c_str()); - return false; -} - -bool WpChanHandler::received(Message &msg, int id) -{ - String tid(msg.getValue("targetid")); - if (!tid.startSkip("wp/",false)) - return false; - int n = tid.toInteger(); - WpChan* c = 0; - if ((n > 0) && (c = wplugin.findChan(n))) { - Lock lock(wplugin.mutex); - switch (id) { - case Answered: - c->answer(); - break; - case Ringing: - Debug("Wp",DebugInfo,"Not implemented ringing!"); - break; - case DTMF: - for (const char* t = msg.getValue("text"); t && *t; ++t) - c->sendDigit(*t); - break; - } - } - Debug("WpChanHandler",DebugInfo,"Could not find wp/%s",tid.c_str()); - return false; -} - -bool StatusHandler::received(Message &msg) -{ - const char *sel = msg.getValue("module"); - if (sel && ::strcmp(sel,"wp") && ::strcmp(sel,"fixchans")) - return false; - String st("name=wp,type=fixchans,format=Status|Span/Chan"); - wplugin.mutex.lock(); - const ObjList *l = &wplugin.m_spans; - st << ",spans=" << l->count() << ",spanlen="; - bool first = true; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - if (first) - first = false; - else - st << "|"; - st << s->chans(); - } - } - st << ";buflen=" << s_buflen << ";"; - l = &wplugin.m_spans; - first = true; + Debug(DebugInfo,"Dropping all %s calls",name().c_str()); + lock(); + const ObjList *l = &m_spans; for (; l; l=l->next()) { PriSpan *s = static_cast(l->get()); if (s) { for (int n=1; n<=s->chans(); n++) { - WpChan *c = s->getChan(n); - if (c) { - if (first) - first = false; - else - st << ","; - st << c->id() << "="; - st << c->status() << "|" << s->span() << "/" << n; - } + PriChan *c = s->getChan(n); + if (c) + c->hangup(PRI_CAUSE_INTERWORKING); } } } - wplugin.mutex.unlock(); - msg.retValue() << st << "\n"; - return false; + unlock(); } -WanpipePlugin::WanpipePlugin() - : mutex(true) +u_int8_t PriDriver::s_bitswap[256]; + +bool PriDriver::s_init = true; + + +PriDriver::PriDriver(const char* name) + : Driver(name,"fixchans") { - Output("Loaded module Wanpipe"); - bitswap_init(); - ::pri_set_error(pri_err_cb); - ::pri_set_message(pri_msg_cb); + if (s_init) { + s_init = false; + for (unsigned int c = 0; c <= 255; c++) { + u_int8_t v = 0; + for (int b = 0; b <= 7; b++) + if (c & (1 << b)) + v |= (0x80 >> b); + s_bitswap[c] = v; + } + ::pri_set_error(pri_err_cb); + ::pri_set_message(pri_msg_cb); + } } -WanpipePlugin::~WanpipePlugin() +PriDriver::~PriDriver() { - Output("Unloading module Wanpipe"); } -PriSpan *WanpipePlugin::findSpan(int chan) +PriSpan *PriDriver::findSpan(int chan) { const ObjList *l = &m_spans; for (; l; l=l->next()) { @@ -1211,19 +901,9 @@ PriSpan *WanpipePlugin::findSpan(int chan) return 0; } -WpChan *WanpipePlugin::findChan(const char *id) +PriChan *PriDriver::find(int first, int last) { - String s(id); - if (!s.startsWith("wp/")) - return 0; - s >> "wp/"; - int n = s.toInteger(); - return (n > 0) ? findChan(n) : 0; -} - -WpChan *WanpipePlugin::findChan(int first, int last) -{ - DDebug(DebugAll,"WanpipePlugin::findChan(%d,%d)",first,last); + DDebug(DebugAll,"PriDriver::find(%d,%d)",first,last); // see first if we have an exact request if (first > 0 && last < 0) { PriSpan *s = findSpan(first); @@ -1247,14 +927,14 @@ WpChan *WanpipePlugin::findChan(int first, int last) return 0; } -bool WanpipePlugin::isBusy() const +bool PriDriver::isBusy() const { const ObjList *l = &m_spans; for (; l; l=l->next()) { PriSpan *s = static_cast(l->get()); if (s) { for (int n=1; n<=s->chans(); n++) { - WpChan *c = s->getChan(n); + PriChan *c = s->getChan(n); if (c && c->inUse()) return true; } @@ -1263,64 +943,28 @@ bool WanpipePlugin::isBusy() const return false; } -void WanpipePlugin::initialize() +void PriDriver::init(const char* configName) { Output("Initializing module Wanpipe"); - Configuration cfg(Engine::configFile("chan_wanpipe")); - PriSpan::restartPeriod = cfg.getIntValue("general","restart") * (u_int64_t)1000000; - PriSpan::dumpEvents = cfg.getBoolValue("general","dumpevents"); + Configuration cfg(Engine::configFile("configName")); + s_buflen = cfg.getIntValue("general","buflen",480); if (!m_spans.count()) { - s_buflen = cfg.getIntValue("general","buflen",480); int chan1 = 1; for (int span = 1;;span++) { String sect("span "); - sect += String(span); + sect << span; int num = cfg.getIntValue(sect,"chans",-1); if (num < 0) break; if (num) { - int dchan = -1; - // guess where we may have a D channel - switch (num) { - case 3: - // BRI ISDN - dchan = 3; - break; - case 24: - // T1 with CCS - dchan = 24; - break; - case 31: - // EuroISDN - dchan = 16; - break; - } chan1 = cfg.getIntValue(sect,"first",chan1); - PriSpan::create(span,chan1,num, - cfg.getIntValue(sect,"dchan", dchan), - cfg.getIntValue(sect,"type",dict_str2type,PRI_NETWORK), - cfg.getIntValue(sect,"swtype",dict_str2switch, - PRI_SWITCH_UNKNOWN), - cfg.getIntValue(sect,"dialplan",dict_str2dplan, - PRI_UNKNOWN), - cfg.getIntValue(sect,"presentation",dict_str2pres, - PRES_ALLOWED_USER_NUMBER_NOT_SCREENED), - cfg.getIntValue(sect,"overlapdial"), - cfg.getIntValue(sect,"facilities",dict_str2nsf, - YATE_NSF_DEFAULT) - ); + create(this,span,chan1,num,&cfg,sect); chan1 += num; } } if (m_spans.count()) { Output("Created %d spans",m_spans.count()); - Engine::install(new WpHandler); - Engine::install(new WpDropper); - Engine::install(new StatusHandler); - WpChanHandler* ch = new WpChanHandler; - Engine::install(new MessageRelay("call.ringing",ch,WpChanHandler::Ringing)); - Engine::install(new MessageRelay("call.answered",ch,WpChanHandler::Answered)); - Engine::install(new MessageRelay("chan.dtmf",ch,WpChanHandler::DTMF)); + setup(); } else Output("No spans created, module not activated"); diff --git a/modules/libypri.h b/modules/libypri.h index d2434d88..8cc6b7da 100644 --- a/modules/libypri.h +++ b/modules/libypri.h @@ -24,23 +24,11 @@ #include -namespace TelEngine { - -#define bitswap(v) bitswap_table[v] - -static unsigned char bitswap_table[256]; - -static void bitswap_init() -{ - for (unsigned int c = 0; c <= 255; c++) { - unsigned char v = 0; - for (int b = 0; b <= 7; b++) - if (c & (1 << b)) - v |= (0x80 >> b); - bitswap_table[c] = v; - } +extern "C" { +#include } +namespace TelEngine { class Fifo { @@ -58,18 +46,16 @@ private: }; class PriChan; +class PriDriver; -class PriSpan : public GenObject, public Thread +class PriSpan : public GenObject { - friend class WpData; public: - static PriSpan *create(int span, int chan1, int nChans, int dChan, int netType, - int switchType, int dialPlan, int presentation, - int overlapDial, int nsf = YATE_NSF_DEFAULT); virtual ~PriSpan(); - virtual void run(); inline struct pri *pri() { return m_pri; } + inline PriDriver* driver() const + { return m_driver; } inline int span() const { return m_span; } inline bool belongs(int chan) const @@ -88,15 +74,16 @@ public: { return m_overlapped; } inline bool outOfOrder() const { return !m_ok; } + inline int buflen() const + { return m_buflen; } int findEmptyChan(int first = 0, int last = 65535) const; - WpChan *getChan(int chan) const; + PriChan *getChan(int chan) const; void idle(); - static u_int64_t restartPeriod; - static bool dumpEvents; -private: - PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres, int overlapDial); - static struct pri *makePri(int fd, int dchan, int nettype, int swtype, int overlapDial, int nsf); +protected: + PriSpan(struct pri *_pri, PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect); + virtual PriChan* create(int chan) = 0; + void runEvent(bool idleRun); void handleEvent(pri_event &ev); bool validChan(int chan) const; void restartChan(int chan, bool outgoing, bool force = false); @@ -106,57 +93,57 @@ private: void ackChan(int chan); void answerChan(int chan); void proceedingChan(int chan); + PriDriver* m_driver; int m_span; int m_offs; int m_nchans; int m_bchans; - int m_fd; int m_dplan; int m_pres; + int m_buflen; unsigned int m_overlapped; + String m_callednumber; struct pri *m_pri; u_int64_t m_restart; - WpChan **m_chans; - WpData *m_data; + u_int64_t m_restartPeriod; + bool m_dumpEvents; + PriChan **m_chans; bool m_ok; }; -class WpSource : public DataSource +class PriSource : public DataSource { public: - WpSource(WpChan *owner,unsigned int bufsize,const char* format); - ~WpSource(); - void put(unsigned char val); + PriSource(PriChan *owner, unsigned int bufsize); + virtual ~PriSource(); -private: - WpChan *m_owner; - unsigned int m_bufpos; - DataBlock m_buf; -}; - -class WpConsumer : public DataConsumer, public Fifo -{ -public: - WpConsumer(WpChan *owner,unsigned int bufsize,const char* format); - ~WpConsumer(); - - virtual void Consume(const DataBlock &data, unsigned long timeDelta); - -private: - WpChan *m_owner; +protected: + PriChan *m_owner; DataBlock m_buffer; }; -class PriChan : public DataEndpoint +class PriConsumer : public DataConsumer { - friend class WpSource; - friend class WpConsumer; - friend class WpData; public: - WpChan(PriSpan *parent, int chan, unsigned int bufsize); - virtual ~WpChan(); + PriConsumer(PriChan *owner, unsigned int bufsize); + virtual ~PriConsumer(); + +protected: + PriChan *m_owner; + DataBlock m_buffer; +}; + +class PriChan : public Channel +{ + friend class PriSource; + friend class PriConsumer; +public: + virtual ~PriChan(); virtual void disconnected(bool final, const char *reason); virtual bool nativeConnect(DataEndpoint *peer); + virtual bool msgDrop(Message& msg, const char* reason); + virtual void callAccept(Message& msg); + virtual void callReject(const char* error, const char* reason = 0); inline PriSpan *span() const { return m_span; } inline int chan() const @@ -165,8 +152,8 @@ public: { return m_abschan; } inline bool inUse() const { return (m_ring || m_call); } - void ring(q931_call *call = 0); - void hangup(int cause = PRI_CAUSE_INVALID_MSG_UNSPECIFIED); + void ring(pri_event_ring &ev); + void hangup(int cause = 0); void sendDigit(char digit); void gotDigits(const char *digits); bool call(Message &msg, const char *called = 0); @@ -174,93 +161,45 @@ public: void answered(); void idle(); void restart(bool outgoing = false); - bool openData(const char* format); + virtual bool openData(const char* format) = 0; void closeData(); inline void setTimeout(u_int64_t tout) { m_timeout = tout ? Time::now()+tout : 0; } - const char *status() const; - const String& id() const - { return m_id; } + const char *chanStatus() const; bool isISDN() const { return m_isdn; } - inline void setTarget(const char *target = 0) - { m_targetid = target; } - inline const String& getTarget() const - { return m_targetid; } -private: +protected: + PriChan(PriSpan *parent, int chan, unsigned int bufsize); PriSpan *m_span; int m_chan; bool m_ring; u_int64_t m_timeout; - q931_call *m_call; + q931_call* m_call; unsigned int m_bufsize; int m_abschan; bool m_isdn; - String m_id; - String m_targetid; - WpSource* m_wp_s; - WpConsumer* m_wp_c; }; -class WpData : public Thread -{ -public: - WpData(PriSpan* span); - ~WpData(); - virtual void run(); -private: - PriSpan* m_span; - int m_fd; - unsigned char* m_buffer; - WpChan **m_chans; -}; - -class WpHandler : public MessageHandler -{ -public: - WpHandler() : MessageHandler("call.execute") { } - virtual bool received(Message &msg); -}; - -class WpDropper : public MessageHandler -{ -public: - WpDropper() : MessageHandler("call.drop") { } - virtual bool received(Message &msg); -}; - -class StatusHandler : public MessageHandler -{ -public: - StatusHandler() : MessageHandler("engine.status") { } - virtual bool received(Message &msg); -}; - -class WpChanHandler : public MessageReceiver -{ -public: - enum { - Ringing, - Answered, - DTMF, - }; - virtual bool received(Message &msg, int id); -}; - -class WanpipePlugin : public Plugin +class PriDriver : public Driver { friend class PriSpan; - friend class WpHandler; public: - WanpipePlugin(); - virtual ~WanpipePlugin(); - virtual void initialize(); + virtual ~PriDriver(); virtual bool isBusy() const; + virtual void dropAll(); + virtual bool msgExecute(Message& msg, String& dest); + virtual void init(const char* configName); + virtual bool create(PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect) = 0; PriSpan *findSpan(int chan); - WpChan *findChan(const char *id); - WpChan *findChan(int first = -1, int last = -1); + PriChan *find(int first = -1, int last = -1); + static inline u_int8_t bitswap(u_int8_t v) + { return s_bitswap[v]; } +protected: + PriDriver(const char* name); +private: ObjList m_spans; - Mutex mutex; + static u_int8_t s_bitswap[256]; + static bool s_init; }; } diff --git a/modules/wpchan.cpp b/modules/wpchan.cpp index 96e41483..7b83bb3c 100644 --- a/modules/wpchan.cpp +++ b/modules/wpchan.cpp @@ -51,24 +51,6 @@ extern "C" { using namespace TelEngine; -static int s_buflen = 480; - -#define bitswap(v) bitswap_table[v] - -static unsigned char bitswap_table[256]; - -static void bitswap_init() -{ - for (unsigned int c = 0; c <= 255; c++) { - unsigned char v = 0; - for (int b = 0; b <= 7; b++) - if (c & (1 << b)) - v |= (0x80 >> b); - bitswap_table[c] = v; - } -} - - /* Layer 1 formats */ static TokenDict dict_str2law[] = { { "mulaw", PRI_LAYER_1_ULAW }, @@ -79,69 +61,21 @@ static TokenDict dict_str2law[] = { class WpChan; -class PriSpan : public GenObject, public Thread +class WpSpan : public PriSpan, public Thread { friend class WpData; public: - static PriSpan *create(int span, int chan1, int nChans, int dChan, int netType, - int switchType, int dialPlan, int presentation, - int overlapDial, int nsf = YATE_NSF_DEFAULT); - virtual ~PriSpan(); + virtual ~WpSpan(); virtual void run(); - inline struct pri *pri() - { return m_pri; } - inline int span() const - { return m_span; } - inline bool belongs(int chan) const - { return (chan >= m_offs) && (chan < m_offs+m_nchans); } - inline int chan1() const - { return m_offs; } - inline int chans() const - { return m_nchans; } - inline int bchans() const - { return m_bchans; } - inline int dplan() const - { return m_dplan; } - inline int pres() const - { return m_pres; } - inline unsigned int overlapped() const - { return m_overlapped; } - inline bool outOfOrder() const - { return !m_ok; } - int findEmptyChan(int first = 0, int last = 65535) const; - WpChan *getChan(int chan) const; - void idle(); - static u_int64_t restartPeriod; - static bool dumpEvents; private: - PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres, int overlapDial); + WpSpan(struct pri *_pri, PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect, int fd); static struct pri *makePri(int fd, int dchan, int nettype, int swtype, int overlapDial, int nsf); - void handleEvent(pri_event &ev); - bool validChan(int chan) const; - void restartChan(int chan, bool outgoing, bool force = false); - void ringChan(int chan, pri_event_ring &ev); - void infoChan(int chan, pri_event_ring &ev); - void hangupChan(int chan,pri_event_hangup &ev); - void ackChan(int chan); - void answerChan(int chan); - void proceedingChan(int chan); - int m_span; - int m_offs; - int m_nchans; - int m_bchans; int m_fd; - int m_dplan; - int m_pres; - unsigned int m_overlapped; - struct pri *m_pri; - u_int64_t m_restart; - WpChan **m_chans; WpData *m_data; - bool m_ok; }; -class WpSource : public DataSource +class WpSource : public PriSource { public: WpSource(WpChan *owner,unsigned int bufsize,const char* format); @@ -149,25 +83,19 @@ public: void put(unsigned char val); private: - WpChan *m_owner; unsigned int m_bufpos; - DataBlock m_buf; }; -class WpConsumer : public DataConsumer, public Fifo +class WpConsumer : public PriConsumer, public Fifo { public: WpConsumer(WpChan *owner,unsigned int bufsize,const char* format); ~WpConsumer(); virtual void Consume(const DataBlock &data, unsigned long timeDelta); - -private: - WpChan *m_owner; - DataBlock m_buffer; }; -class WpChan : public DataEndpoint +class WpChan : public PriChan { friend class WpSource; friend class WpConsumer; @@ -177,47 +105,9 @@ public: virtual ~WpChan(); virtual void disconnected(bool final, const char *reason); virtual bool nativeConnect(DataEndpoint *peer); - inline PriSpan *span() const - { return m_span; } - inline int chan() const - { return m_chan; } - inline int absChan() const - { return m_abschan; } - inline bool inUse() const - { return (m_ring || m_call); } - void ring(q931_call *call = 0); - void hangup(int cause = PRI_CAUSE_INVALID_MSG_UNSPECIFIED); - void sendDigit(char digit); - void gotDigits(const char *digits); - bool call(Message &msg, const char *called = 0); - bool answer(); - void answered(); - void idle(); - void restart(bool outgoing = false); - bool open(const char* format); - void close(); - inline void setTimeout(u_int64_t tout) - { m_timeout = tout ? Time::now()+tout : 0; } - const char *status() const; - const String& id() const - { return m_id; } - bool isISDN() const - { return m_isdn; } - inline void setTarget(const char *target = 0) - { m_targetid = target; } - inline const String& getTarget() const - { return m_targetid; } + bool openData(const char* format); + private: - PriSpan *m_span; - int m_chan; - bool m_ring; - u_int64_t m_timeout; - q931_call *m_call; - unsigned int m_bufsize; - int m_abschan; - bool m_isdn; - String m_id; - String m_targetid; WpSource* m_wp_s; WpConsumer* m_wp_c; }; @@ -225,67 +115,28 @@ private: class WpData : public Thread { public: - WpData(PriSpan* span); + WpData(WpSpan* span); ~WpData(); virtual void run(); private: - PriSpan* m_span; + WpSpan* m_span; int m_fd; unsigned char* m_buffer; WpChan **m_chans; }; -class WpHandler : public MessageHandler -{ -public: - WpHandler() : MessageHandler("call.execute") { } - virtual bool received(Message &msg); -}; - -class WpDropper : public MessageHandler -{ -public: - WpDropper() : MessageHandler("call.drop") { } - virtual bool received(Message &msg); -}; - -class StatusHandler : public MessageHandler -{ -public: - StatusHandler() : MessageHandler("engine.status") { } - virtual bool received(Message &msg); -}; - -class WpChanHandler : public MessageReceiver -{ -public: - enum { - Ringing, - Answered, - DTMF, - }; - virtual bool received(Message &msg, int id); -}; - -class WanpipePlugin : public Plugin +class WpDriver : public PriDriver { friend class PriSpan; friend class WpHandler; public: - WanpipePlugin(); - virtual ~WanpipePlugin(); + WpDriver(); + virtual ~WpDriver(); virtual void initialize(); - virtual bool isBusy() const; - PriSpan *findSpan(int chan); - WpChan *findChan(const char *id); - WpChan *findChan(int first = -1, int last = -1); - ObjList m_spans; - Mutex mutex; + virtual bool create(PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect); }; -WanpipePlugin wplugin; -u_int64_t PriSpan::restartPeriod = 0; -bool PriSpan::dumpEvents = false; +WpDriver wdriver; #define WP_HEADER 16 @@ -325,6 +176,16 @@ static int wp_write(struct pri *pri, void *buf, int buflen) return w; } +bool WpDriver::create(PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect) +{ +} + + +virtual PriChan* WpSpan::create(int chan) +{ + return new WpChan(this,chan,m_bufsize) +} + PriSpan *PriSpan::create(int span, int chan1, int nChans, int dChan, int netType, int switchType, int dialPlan, int presentation, int overlapDial, int nsf) @@ -340,13 +201,12 @@ PriSpan *PriSpan::create(int span, int chan1, int nChans, int dChan, int netType ::close(fd); return 0; } - PriSpan *ps = new PriSpan(p,span,chan1,nChans,dChan,fd,dialPlan,presentation,overlapDial); + WpSpan *ps = new WpSpan(p,span,chan1,nChans,dChan,fd); ps->startup(); return ps; } -struct pri *PriSpan::makePri(int fd, int dchan, int nettype, int swtype, - int overlapDial, int nsf) +struct pri *PriSpan::makePri(int fd, int dchan, int nettype, int swtype) { if (dchan >= 0) { // Set up the D channel if we have one @@ -362,64 +222,30 @@ struct pri *PriSpan::makePri(int fd, int dchan, int nettype, int swtype, return 0; } } - struct pri *ret = ::pri_new_cb(fd, nettype, swtype, wp_read, wp_write, 0); -#ifdef PRI_NSF_NONE - if (ret) - ::pri_set_nsf(ret, nsf); -#endif -#ifdef PRI_SET_OVERLAPDIAL - if (ret) - ::pri_set_overlapdial(ret, (overlapDial > 0)); -#endif - return ret; + return ::pri_new_cb(fd, nettype, swtype, wp_read, wp_write, 0); } -PriSpan::PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres, int overlapDial) - : Thread("PriSpan"), m_span(span), m_offs(first), m_nchans(chans), m_bchans(0), - m_fd(fd), m_dplan(dplan), m_pres(pres), m_overlapped(0), m_pri(_pri), - m_restart(0), m_chans(0), m_data(0), m_ok(false) +WpSpan::WpSpan(struct pri *_pri, PriDriver* driver, int span, int first, int chans, Configuration* cfg, const String& sect, int fd) + : PriSpan(_pri,driver,span,first,chans,cfg,sect), Thread("WpSpan"), + m_fd(fd), m_data(0) { - Debug(DebugAll,"PriSpan::PriSpan(%p,%d,%d,%d) [%p]",_pri,span,chans,fd,this); - if (overlapDial > 0) - m_overlapped = overlapDial; - WpChan **ch = new WpChan* [chans]; - for (int i = 1; i <= chans; i++) { - if (i != dchan) { - ch[i-1] = new WpChan(this,i,s_buflen); - m_bchans++; - } - else - ch[i-1] = 0; - } - m_chans = ch; - wplugin.m_spans.append(this); + Debug(DebugAll,"PriSpan::PriSpan() [%p]",this); WpData* dat = new WpData(this); dat->startup(); } -PriSpan::~PriSpan() +WpSpan::~WpSpan() { - Debug(DebugAll,"PriSpan::~PriSpan() [%p]",this); - wplugin.m_spans.remove(this,false); + Debug(DebugAll,"WpSpan::~WpSpan() [%p]",this); m_ok = false; delete m_data; - for (int i = 0; i < m_nchans; i++) { - WpChan *c = m_chans[i]; - m_chans[i] = 0; - if (c) { - c->hangup(PRI_CAUSE_NORMAL_UNSPECIFIED); - c->destruct(); - } - } - delete[] m_chans; ::close(m_fd); + m_fd = -1; } -void PriSpan::run() +void WpSpan::run() { Debug(DebugAll,"PriSpan::run() [%p]",this); - m_restart = Time::now() + restartPeriod; - ::pri_set_userdata(m_pri, this); fd_set rdfds; fd_set errfds; for (;;) { @@ -432,310 +258,50 @@ void PriSpan::run() tv.tv_usec = 100; int sel = ::select(m_fd+1, &rdfds, NULL, &errfds, &tv); pri_event *ev = 0; - Lock lock(wplugin.mutex); - if (!sel) { - ev = ::pri_schedule_run(m_pri); - idle(); - } + if (!sel) + runEvent(true); else if (sel > 0) - ev = ::pri_check_event(m_pri); + runEvent(false); else if (errno != EINTR) - Debug("PriSpan",DebugGoOn,"select() error %d: %s", + Debug("WpSpan",DebugGoOn,"select() error %d: %s", errno,::strerror(errno)); - if (ev) { - if (dumpEvents && debugAt(DebugAll)) - ::pri_dump_event(m_pri, ev); - handleEvent(*ev); - } } } -void PriSpan::idle() -{ - if (!m_chans) - return; - if (restartPeriod && (Time::now() > m_restart)) { - m_restart = Time::now() + restartPeriod; - Debug("PriSpan",DebugInfo,"Restarting idle channels on span %d",m_span); - for (int i=0; iidle(); -} - -void PriSpan::handleEvent(pri_event &ev) -{ - switch (ev.e) { - case PRI_EVENT_DCHAN_UP: - Debug(DebugInfo,"D-channel up on span %d",m_span); - m_ok = true; - m_restart = Time::now() + 1000000; - break; - case PRI_EVENT_DCHAN_DOWN: - Debug(DebugWarn,"D-channel down on span %d",m_span); - m_ok = false; - { - for (int i=0; ihangup(PRI_CAUSE_NETWORK_OUT_OF_ORDER); - } - break; - case PRI_EVENT_RESTART: - restartChan(ev.restart.channel,false,true); - break; - case PRI_EVENT_CONFIG_ERR: - Debug(DebugWarn,"Error on span %d: %s",m_span,ev.err.err); - break; - case PRI_EVENT_RING: - ringChan(ev.ring.channel,ev.ring); - break; - case PRI_EVENT_INFO_RECEIVED: - infoChan(ev.ring.channel,ev.ring); - break; - case PRI_EVENT_RINGING: - Debug(DebugInfo,"Ringing our call on channel %d on span %d",ev.ringing.channel,m_span); - break; - case PRI_EVENT_HANGUP: - Debug(DebugInfo,"Hangup detected on channel %d on span %d",ev.hangup.channel,m_span); - hangupChan(ev.hangup.channel,ev.hangup); - break; - case PRI_EVENT_ANSWER: - Debug(DebugInfo,"Answered channel %d on span %d",ev.answer.channel,m_span); - answerChan(ev.setup_ack.channel); - break; - case PRI_EVENT_HANGUP_ACK: - Debug(DebugInfo,"Hangup ACK on channel %d on span %d",ev.hangup.channel,m_span); - break; - case PRI_EVENT_RESTART_ACK: - Debug(DebugInfo,"Restart ACK on channel %d on span %d",ev.restartack.channel,m_span); - break; - case PRI_EVENT_SETUP_ACK: - Debug(DebugInfo,"Setup ACK on channel %d on span %d",ev.setup_ack.channel,m_span); - ackChan(ev.setup_ack.channel); - break; - case PRI_EVENT_HANGUP_REQ: - Debug(DebugInfo,"Hangup REQ on channel %d on span %d",ev.hangup.channel,m_span); - hangupChan(ev.hangup.channel,ev.hangup); - break; - case PRI_EVENT_PROCEEDING: - Debug(DebugInfo,"Call proceeding on channel %d on span %d",ev.proceeding.channel,m_span); - proceedingChan(ev.proceeding.channel); - break; -#ifdef PRI_EVENT_PROGRESS - case PRI_EVENT_PROGRESS: - Debug(DebugInfo,"Call progressing on channel %d on span %d",ev.proceeding.channel,m_span); - proceedingChan(ev.proceeding.channel); - break; -#endif - default: - Debug(DebugInfo,"Received PRI event %d",ev.e); - } -} - -bool PriSpan::validChan(int chan) const -{ - return (chan > 0) && (chan <= m_nchans) && m_chans && m_chans[chan-1]; -} - -int PriSpan::findEmptyChan(int first, int last) const -{ - if (!m_ok) - return -1; - first -= m_offs; - last -= m_offs; - if (first < 0) - first = 0; - if (last > m_nchans-1) - last = m_nchans-1; - for (int i=first; i<=last; i++) - if (m_chans[i] && !m_chans[i]->inUse()) - return i+1; - return -1; -} - -WpChan *PriSpan::getChan(int chan) const -{ - return validChan(chan) ? m_chans[chan-1] : 0; -} - -void PriSpan::restartChan(int chan, bool outgoing, bool force) -{ - if (chan < 0) { - Debug(DebugInfo,"Restart request on entire span %d",m_span); - return; - } - if (!validChan(chan)) { - Debug(DebugInfo,"Restart request on invalid channel %d on span %d",chan,m_span); - return; - } - if (force || !getChan(chan)->inUse()) { - Debug(DebugAll,"Restarting B-channel %d on span %d",chan,m_span); - getChan(chan)->restart(outgoing); - } -} - -void PriSpan::ringChan(int chan, pri_event_ring &ev) -{ - if (chan == -1) - chan = findEmptyChan(); - if (!validChan(chan)) { - Debug(DebugInfo,"Ring on invalid channel %d on span %d",chan,m_span); - ::pri_hangup(pri(),ev.call,PRI_CAUSE_CHANNEL_UNACCEPTABLE); - ::pri_destroycall(pri(),ev.call); - return; - } - Debug(DebugInfo,"Ring on channel %d on span %d",chan,m_span); - Debug(DebugInfo,"caller='%s' callerno='%s' callingplan=%d", - ev.callingname,ev.callingnum,ev.callingplan); - Debug(DebugInfo,"callednum='%s' redirectnum='%s' calledplan=%d", - ev.callednum,ev.redirectingnum,ev.calledplan); - Debug(DebugInfo,"type=%d complete=%d format='%s'", - ev.ctype,ev.complete,lookup(ev.layer1,dict_str2law,"unknown")); - WpChan* c = getChan(chan); - c->ring(ev.call); - if (m_overlapped && !ev.complete) { - if (::strlen(ev.callednum) < m_overlapped) { - ::pri_need_more_info(pri(),ev.call,chan,!c->isISDN()); - return; - } - } - Message *m = new Message("call.route"); - m->addParam("driver","wp"); - m->addParam("id",c->id()); - m->addParam("span",String(m_span)); - m->addParam("channel",String(chan)); - if (ev.callingnum[0]) - m->addParam("caller",ev.callingnum); - if (ev.callednum[0]) - m->addParam("called",ev.callednum); - if (m_overlapped && !ev.complete) - m->addParam("overlapped","yes"); - const char* dataLaw = "slin"; - switch (ev.layer1) { - case PRI_LAYER_1_ALAW: - dataLaw = "alaw"; - break; - case PRI_LAYER_1_ULAW: - dataLaw = "mulaw"; - break; - } - m->addParam("format",dataLaw); - if (Engine::dispatch(m)) { - *m = "call.execute"; - m->addParam("callto",m->retValue()); - m->retValue().clear(); - c->open(dataLaw); - m->userData(getChan(chan)); - if (Engine::dispatch(m)) { - c->setTarget(m->getValue("targetid")); - if (c->getTarget().null()) { - Debug(DebugInfo,"Answering now chan %s [%p] because we have no targetid", - c->id().c_str(),c); - c->answer(); - } - else - getChan(chan)->setTimeout(60000000); - } - else - getChan(chan)->hangup(PRI_CAUSE_REQUESTED_CHAN_UNAVAIL); - } - else - getChan(chan)->hangup(PRI_CAUSE_NO_ROUTE_DESTINATION); - delete m; -} - -void PriSpan::infoChan(int chan, pri_event_ring &ev) -{ - if (!validChan(chan)) { - Debug(DebugInfo,"Info on invalid channel %d on span %d",chan,m_span); - return; - } - Debug(DebugInfo,"info on channel %d on span %d",chan,m_span); - Debug(DebugInfo,"caller='%s' callerno='%s' callingplan=%d", - ev.callingname,ev.callingnum,ev.callingplan); - Debug(DebugInfo,"callednum='%s' redirectnum='%s' calledplan=%d", - ev.callednum,ev.redirectingnum,ev.calledplan); - getChan(chan)->gotDigits(ev.callednum); -} - -void PriSpan::hangupChan(int chan,pri_event_hangup &ev) -{ - if (!validChan(chan)) { - Debug(DebugInfo,"Hangup on invalid channel %d on span %d",chan,m_span); - return; - } - Debug(DebugInfo,"Hanging up channel %d on span %d",chan,m_span); - getChan(chan)->hangup(ev.cause); -} - -void PriSpan::ackChan(int chan) -{ - if (!validChan(chan)) { - Debug(DebugInfo,"ACK on invalid channel %d on span %d",chan,m_span); - return; - } - Debug(DebugInfo,"ACKnowledging channel %d on span %d",chan,m_span); - getChan(chan)->setTimeout(0); -} - -void PriSpan::answerChan(int chan) -{ - if (!validChan(chan)) { - Debug(DebugInfo,"ANSWER on invalid channel %d on span %d",chan,m_span); - return; - } - Debug(DebugInfo,"ANSWERing channel %d on span %d",chan,m_span); - getChan(chan)->answered(); -} - -void PriSpan::proceedingChan(int chan) -{ - if (!validChan(chan)) { - Debug(DebugInfo,"Proceeding on invalid channel %d on span %d",chan,m_span); - return; - } - Debug(DebugInfo,"Extending timeout on channel %d on span %d",chan,m_span); - getChan(chan)->setTimeout(60000000); -} - WpSource::WpSource(WpChan *owner,unsigned int bufsize,const char* format) - : DataSource(format), - m_owner(owner), m_bufpos(0), m_buf(0,bufsize) + : PriSource(owner,bufsize), + m_bufpos(0) { Debug(DebugAll,"WpSource::WpSource(%p) [%p]",owner,this); - m_owner->m_wp_s = this; + static_cast(m_owner)->m_wp_s = this; } WpSource::~WpSource() { Debug(DebugAll,"WpSource::~WpSource() [%p]",this); - m_owner->m_wp_s = 0; + static_cast(m_owner)->m_wp_s = 0; } void WpSource::put(unsigned char val) { - ((char*)m_buf.data())[m_bufpos] = val; - if (++m_bufpos >= m_buf.length()) { + ((char*)m_buffer.data())[m_bufpos] = val; + if (++m_bufpos >= m_buffer.length()) { m_bufpos = 0; - Forward(m_buf); + Forward(m_buffer); } } WpConsumer::WpConsumer(WpChan *owner,unsigned int bufsize,const char* format) - : DataConsumer(format), Fifo(2*bufsize), - m_owner(owner) + : PriConsumer(owner,bufsize), Fifo(2*bufsize) { Debug(DebugAll,"WpConsumer::WpConsumer(%p) [%p]",owner,this); - m_owner->m_wp_c = this; + static_cast(m_owner)->m_wp_c = this; } WpConsumer::~WpConsumer() { Debug(DebugAll,"WpConsumer::~WpConsumer() [%p]",this); - m_owner->m_wp_c = 0; + static_cast(m_owner)->m_wp_c = 0; } void WpConsumer::Consume(const DataBlock &data, unsigned long timeDelta) @@ -745,7 +311,7 @@ void WpConsumer::Consume(const DataBlock &data, unsigned long timeDelta) put(buf[i]); } -WpData::WpData(PriSpan* span) +WpData::WpData(WpSpan* span) : Thread("WpData"), m_span(span), m_fd(-1), m_buffer(0), m_chans(0) { Debug(DebugAll,"WpData::WpData(%p) [%p]",span,this); @@ -828,7 +394,7 @@ void WpData::run() for (b = 0; b < bchans; b++) { WpSource *s = m_chans[b]->m_wp_s; if (s) - s->put(bitswap(*dat)); + s->put(PriDriver::bitswap(*dat)); dat++; } wplugin.mutex.unlock(); @@ -840,7 +406,7 @@ void WpData::run() for (int n = w; n > 0; n--) { for (b = 0; b < bchans; b++) { WpConsumer *c = m_chans[b]->m_wp_c; - *dat++ = bitswap(c ? c->get() : 0xff); + *dat++ = PriDriver::bitswap(c ? c->get() : 0xff); } } wplugin.mutex.unlock(); @@ -852,85 +418,7 @@ void WpData::run() } } -WpChan::WpChan(PriSpan *parent, int chan, unsigned int bufsize) - : DataEndpoint("wanpipe"), m_span(parent), m_chan(chan), m_ring(false), - m_timeout(0), m_call(0), m_bufsize(bufsize), m_wp_s(0), m_wp_c(0) -{ - Debug(DebugAll,"WpChan::WpChan(%p,%d) [%p]",parent,chan,this); - // I hate counting from one... - m_abschan = m_chan+m_span->chan1()-1; - m_isdn = true; - m_id << "wp/" << m_abschan; -} - -WpChan::~WpChan() -{ - Debug(DebugAll,"WpChan::~WpChan() [%p] %d",this,m_chan); - hangup(PRI_CAUSE_NORMAL_UNSPECIFIED); -} - -void WpChan::disconnected(bool final, const char *reason) -{ - Debugger debug("WpChan::disconnected()", " '%s' [%p]",reason,this); - if (!final) { - Message m("chan.disconnected"); - m.addParam("driver","wp"); - m.addParam("id",id()); - m.addParam("span",String(m_span->span())); - m.addParam("channel",String(m_chan)); - if (m_targetid) { - m.addParam("targetid",m_targetid); - setTarget(); - } - m.addParam("reason",reason); - Engine::enqueue(m); - } - wplugin.mutex.lock(); - hangup(PRI_CAUSE_NORMAL_CLEARING); - wplugin.mutex.unlock(); -} - -bool WpChan::nativeConnect(DataEndpoint *peer) -{ - return false; -} - -const char *WpChan::status() const -{ - if (m_ring) - return "ringing"; - if (m_call) - return m_timeout ? "calling" : "connected"; - return "idle"; -} - -void WpChan::idle() -{ - if (m_timeout && (Time::now() > m_timeout)) { - Debug("WpChan",DebugWarn,"Timeout %s channel %d on span %d", - status(),m_chan,m_span->span()); - m_timeout = 0; - hangup(PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE); - } -} - -void WpChan::restart(bool outgoing) -{ - disconnect("restart"); - close(); - if (outgoing) - ::pri_reset(m_span->pri(),m_chan); -} - -void WpChan::close() -{ - wplugin.mutex.lock(); - setSource(); - setConsumer(); - wplugin.mutex.unlock(); -} - -bool WpChan::open(const char* format) +bool WpChan::openData(const char* format) { setSource(new WpSource(this,m_bufsize,format)); getSource()->deref(); @@ -939,439 +427,21 @@ bool WpChan::open(const char* format) return true; } -bool WpChan::answer() -{ - if (!m_ring) { - Debug("WpChan",DebugWarn,"Answer request on %s channel %d on span %d", - status(),m_chan,m_span->span()); - return false; - } - m_ring = false; - m_timeout = 0; - Output("Answering on wp/%d (%d/%d)",m_abschan,m_span->span(),m_chan); - ::pri_answer(m_span->pri(),m_call,m_chan,!m_isdn); - return true; -} - -void WpChan::hangup(int cause) -{ - const char *reason = pri_cause2str(cause); - if (inUse()) - Debug(DebugInfo,"Hanging up wp/%d in state %s: %s (%d)", - m_abschan,status(),reason,cause); - m_timeout = 0; - setTarget(); - disconnect(reason); - close(); - m_ring = false; - if (m_call) { - ::pri_hangup(m_span->pri(),m_call,cause); - ::pri_destroycall(m_span->pri(),m_call); - m_call = 0; - Message *m = new Message("chan.hangup"); - m->addParam("driver","wp"); - m->addParam("id",id()); - m->addParam("span",String(m_span->span())); - m->addParam("channel",String(m_chan)); - m->addParam("reason",pri_cause2str(cause)); - Engine::enqueue(m); - } -} - -void WpChan::answered() -{ - if (!m_call) { - Debug("WpChan",DebugWarn,"Answer detected on %s channel %d on span %d", - status(),m_chan,m_span->span()); - return; - } - m_timeout = 0; - Output("Remote answered on wp/%d (%d/%d)",m_abschan,m_span->span(),m_chan); - Message *m = new Message("call.answered"); - m->addParam("driver","wp"); - m->addParam("id",id()); - m->addParam("span",String(m_span->span())); - m->addParam("channel",String(m_chan)); - if (m_targetid) - m->addParam("targetid",m_targetid); - m->addParam("status","answered"); - Engine::enqueue(m); -} - -void WpChan::gotDigits(const char *digits) -{ - Message *m = new Message("chan.dtmf"); - m->addParam("driver","wp"); - m->addParam("id",id()); - m->addParam("span",String(m_span->span())); - m->addParam("channel",String(m_chan)); - if (m_targetid) - m->addParam("targetid",m_targetid); - m->addParam("text",digits); - Engine::enqueue(m); -} - -void WpChan::sendDigit(char digit) -{ - if (m_call) - ::pri_information(m_span->pri(),m_call,digit); -} - -bool WpChan::call(Message &msg, const char *called) -{ - if (m_span->outOfOrder()) { - Debug("WpChan",DebugInfo,"Span %d is out of order, failing call",m_span->span()); - return false; - } - if (!called) - called = msg.getValue("called"); - Debug("WpChan",DebugInfo,"Calling '%s' on channel %d span %d", - called, m_chan,m_span->span()); - int layer1 = lookup(msg.getValue("format"),dict_str2law,-1); - hangup(PRI_CAUSE_PRE_EMPTED); - DataEndpoint *dd = static_cast(msg.userData()); - if (dd) { - open(lookup(layer1,dict_str2law)); - connect(dd); - setTarget(msg.getValue("id")); - msg.addParam("targetid",id()); - } - else - msg.userData(this); - Output("Calling '%s' on wp/%d (%d/%d)",called,m_abschan,m_span->span(),m_chan); - char *caller = (char *)msg.getValue("caller"); - int callerplan = lookup(msg.getValue("callerplan"),dict_str2dplan,m_span->dplan()); - char *callername = (char *)msg.getValue("callername"); - int callerpres = lookup(msg.getValue("callerpres"),dict_str2pres,m_span->pres()); - int calledplan = lookup(msg.getValue("calledplan"),dict_str2dplan,m_span->dplan()); - Debug(DebugAll,"Caller='%s' name='%s' plan=%s pres=%s, Called plan=%s", - caller,callername,lookup(callerplan,dict_str2dplan), - lookup(callerpres,dict_str2pres),lookup(calledplan,dict_str2dplan)); - m_call =::pri_new_call(span()->pri()); -#ifdef PRI_DUMP_INFO - struct pri_sr *req = ::pri_sr_new(); - ::pri_sr_set_bearer(req,0/*transmode*/,layer1); - ::pri_sr_set_channel(req,m_chan,1/*exclusive*/,!m_isdn); - ::pri_sr_set_caller(req,caller,callername,callerplan,callerpres); - ::pri_sr_set_called(req,(char *)called,calledplan,1/*complete*/); - ::q931_setup(span()->pri(),m_call,req); -#else - ::pri_call(m_span->pri(),m_call,0/*transmode*/,m_chan,1/*exclusive*/,!m_isdn, - caller,callerplan,callername,callerpres,(char *)called,calledplan,layer1 - ); -#endif - setTimeout(10000000); - Message *m = new Message("chan.startup"); - m->addParam("driver","wp"); - m->addParam("id",id()); - m->addParam("span",String(m_span->span())); - m->addParam("channel",String(m_chan)); - m->addParam("direction","outgoing"); - Engine::enqueue(m); - return true; -} - -void WpChan::ring(q931_call *call) -{ - if (call) { - setTimeout(10000000); - m_call = call; - m_ring = true; - ::pri_acknowledge(m_span->pri(),m_call,m_chan,0); - Message *m = new Message("chan.startup"); - m->addParam("driver","wp"); - m->addParam("id",id()); - m->addParam("span",String(m_span->span())); - m->addParam("channel",String(m_chan)); - m->addParam("direction","incoming"); - Engine::enqueue(m); - } - else - hangup(PRI_CAUSE_WRONG_CALL_STATE); -} - -bool WpHandler::received(Message &msg) -{ - String dest(msg.getValue("callto")); - if (dest.null()) - return false; - Regexp r("^wp/\\([^/]*\\)/\\?\\(.*\\)$"); - if (!dest.matches(r)) - return false; - if (!msg.userData()) { - Debug(DebugWarn,"Wanpipe call found but no data channel!"); - return false; - } - String chan = dest.matchString(1); - String num = dest.matchString(2); - DDebug(DebugInfo,"Found call to Wanpipe chan='%s' name='%s'", - chan.c_str(),num.c_str()); - WpChan *c = 0; - - r = "^\\([0-9]\\+\\)-\\([0-9]*\\)$"; - Lock lock(wplugin.mutex); - if (chan.matches(r)) - c = wplugin.findChan(chan.matchString(1).toInteger(), - chan.matchString(2).toInteger(65535)); - else - c = wplugin.findChan(chan.toInteger(-1)); - - if (c) { - Debug(DebugInfo,"Will call '%s' on chan wp/%d (%d/%d)", - num.c_str(),c->absChan(),c->span()->span(),c->chan()); - return c->call(msg,num); - } - else - Debug(DebugWarn,"No free Wanpipe channel '%s'",chan.c_str()); - return false; -} - -bool WpDropper::received(Message &msg) -{ - String id(msg.getValue("id")); - if (id.null()) { - Debug("WpDropper",DebugInfo,"Dropping all calls"); - wplugin.mutex.lock(); - const ObjList *l = &wplugin.m_spans; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - for (int n=1; n<=s->chans(); n++) { - WpChan *c = s->getChan(n); - if (c) - c->hangup(PRI_CAUSE_INTERWORKING); - } - } - } - wplugin.mutex.unlock(); - return false; - } - if (!id.startsWith("wp/")) - return false; - WpChan *c = 0; - id >> "wp/"; - int n = id.toInteger(); - if ((n > 0) && (c = wplugin.findChan(n))) { - Debug("WpDropper",DebugInfo,"Dropping wp/%d (%d/%d)", - n,c->span()->span(),c->chan()); - wplugin.mutex.lock(); - c->hangup(PRI_CAUSE_INTERWORKING); - wplugin.mutex.unlock(); - return true; - } - Debug("WpDropper",DebugInfo,"Could not find wp/%s",id.c_str()); - return false; -} - -bool WpChanHandler::received(Message &msg, int id) -{ - String tid(msg.getValue("targetid")); - if (!tid.startSkip("wp/",false)) - return false; - int n = tid.toInteger(); - WpChan* c = 0; - if ((n > 0) && (c = wplugin.findChan(n))) { - Lock lock(wplugin.mutex); - switch (id) { - case Answered: - c->answer(); - break; - case Ringing: - Debug("Wp",DebugInfo,"Not implemented ringing!"); - break; - case DTMF: - for (const char* t = msg.getValue("text"); t && *t; ++t) - c->sendDigit(*t); - break; - } - } - Debug("WpChanHandler",DebugInfo,"Could not find wp/%s",tid.c_str()); - return false; -} - -bool StatusHandler::received(Message &msg) -{ - const char *sel = msg.getValue("module"); - if (sel && ::strcmp(sel,"wp") && ::strcmp(sel,"fixchans")) - return false; - String st("name=wp,type=fixchans,format=Status|Span/Chan"); - wplugin.mutex.lock(); - const ObjList *l = &wplugin.m_spans; - st << ",spans=" << l->count() << ",spanlen="; - bool first = true; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - if (first) - first = false; - else - st << "|"; - st << s->chans(); - } - } - st << ";buflen=" << s_buflen << ";"; - l = &wplugin.m_spans; - first = true; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - for (int n=1; n<=s->chans(); n++) { - WpChan *c = s->getChan(n); - if (c) { - if (first) - first = false; - else - st << ","; - st << c->id() << "="; - st << c->status() << "|" << s->span() << "/" << n; - } - } - } - } - wplugin.mutex.unlock(); - msg.retValue() << st << "\n"; - return false; -} - -WanpipePlugin::WanpipePlugin() - : mutex(true) +WpDriver::WpDriver() + : PriDriver("wp") { Output("Loaded module Wanpipe"); - bitswap_init(); - ::pri_set_error(pri_err_cb); - ::pri_set_message(pri_msg_cb); } -WanpipePlugin::~WanpipePlugin() +WpDriver::~WpDriver() { Output("Unloading module Wanpipe"); } -PriSpan *WanpipePlugin::findSpan(int chan) -{ - const ObjList *l = &m_spans; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s && s->belongs(chan)) - return s; - } - return 0; -} - -WpChan *WanpipePlugin::findChan(const char *id) -{ - String s(id); - if (!s.startsWith("wp/")) - return 0; - s >> "wp/"; - int n = s.toInteger(); - return (n > 0) ? findChan(n) : 0; -} - -WpChan *WanpipePlugin::findChan(int first, int last) -{ - DDebug(DebugAll,"WanpipePlugin::findChan(%d,%d)",first,last); - // see first if we have an exact request - if (first > 0 && last < 0) { - PriSpan *s = findSpan(first); - return s ? s->getChan(first - s->chan1() + 1) : 0; - } - if (last < 0) - last = 65535; - const ObjList *l = &m_spans; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - Debug(DebugAll,"Searching for free chan in span %d [%p]", - s->span(),s); - int c = s->findEmptyChan(first,last); - if (c > 0) - return s->getChan(c); - if (s->belongs(last)) - break; - } - } - return 0; -} - -bool WanpipePlugin::isBusy() const -{ - const ObjList *l = &m_spans; - for (; l; l=l->next()) { - PriSpan *s = static_cast(l->get()); - if (s) { - for (int n=1; n<=s->chans(); n++) { - WpChan *c = s->getChan(n); - if (c && c->inUse()) - return true; - } - } - } - return false; -} - -void WanpipePlugin::initialize() +void WpDriver::initialize() { Output("Initializing module Wanpipe"); - Configuration cfg(Engine::configFile("chan_wanpipe")); - PriSpan::restartPeriod = cfg.getIntValue("general","restart") * (u_int64_t)1000000; - PriSpan::dumpEvents = cfg.getBoolValue("general","dumpevents"); - if (!m_spans.count()) { - s_buflen = cfg.getIntValue("general","buflen",480); - int chan1 = 1; - for (int span = 1;;span++) { - String sect("span "); - sect += String(span); - int num = cfg.getIntValue(sect,"chans",-1); - if (num < 0) - break; - if (num) { - int dchan = -1; - // guess where we may have a D channel - switch (num) { - case 3: - // BRI ISDN - dchan = 3; - break; - case 24: - // T1 with CCS - dchan = 24; - break; - case 31: - // EuroISDN - dchan = 16; - break; - } - chan1 = cfg.getIntValue(sect,"first",chan1); - PriSpan::create(span,chan1,num, - cfg.getIntValue(sect,"dchan", dchan), - cfg.getIntValue(sect,"type",dict_str2type,PRI_NETWORK), - cfg.getIntValue(sect,"swtype",dict_str2switch, - PRI_SWITCH_UNKNOWN), - cfg.getIntValue(sect,"dialplan",dict_str2dplan, - PRI_UNKNOWN), - cfg.getIntValue(sect,"presentation",dict_str2pres, - PRES_ALLOWED_USER_NUMBER_NOT_SCREENED), - cfg.getIntValue(sect,"overlapdial"), - cfg.getIntValue(sect,"facilities",dict_str2nsf, - YATE_NSF_DEFAULT) - ); - chan1 += num; - } - } - if (m_spans.count()) { - Output("Created %d spans",m_spans.count()); - Engine::install(new WpHandler); - Engine::install(new WpDropper); - Engine::install(new StatusHandler); - WpChanHandler* ch = new WpChanHandler; - Engine::install(new MessageRelay("call.ringing",ch,WpChanHandler::Ringing)); - Engine::install(new MessageRelay("call.answered",ch,WpChanHandler::Answered)); - Engine::install(new MessageRelay("chan.dtmf",ch,WpChanHandler::DTMF)); - } - else - Output("No spans created, module not activated"); - } + init("wpchan"); } /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/yateclass.h b/yateclass.h index ff8da018..8681e8ed 100644 --- a/yateclass.h +++ b/yateclass.h @@ -45,6 +45,9 @@ #include #include +typedef signed __int8 int8_t; +typedef unsigned __int8 u_int8_t; +typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 u_int16_t; typedef unsigned __int16 uint16_t; diff --git a/yatephone.h b/yatephone.h index b2a393d1..c0b134aa 100644 --- a/yatephone.h +++ b/yatephone.h @@ -1148,6 +1148,13 @@ protected: inline void status(const char* newstat) { m_status = newstat; } + /** + * Set the current direction of the channel + * @param outgoing True if this is an outgoing call channel + */ + inline void setOutgoing(bool outgoing = true) + { m_outgoing = outgoing; } + /** * Connect notification method. */ @@ -1246,7 +1253,7 @@ protected: /** * Constructor * @param name Plugin name of this driver - * @param type Type of the driver: "fixchan", "varchan", etc. + * @param type Type of the driver: "fixchans", "varchans", etc. */ Driver(const char* name, const char* type = 0);