aboutsummaryrefslogtreecommitdiffstats
path: root/apps/app_rpt.c
diff options
context:
space:
mode:
authorjim <jim@f38db490-d61c-443f-a65b-d21fe96a405b>2005-01-14 21:57:31 +0000
committerjim <jim@f38db490-d61c-443f-a65b-d21fe96a405b>2005-01-14 21:57:31 +0000
commite31daabcef274762ce3e04902b88a8c1c33f77d4 (patch)
tree8047e67113d39be26e0027ed8b07f51087f33407 /apps/app_rpt.c
parentc2e9244d869fb678322e55ed25e7e89be074b03a (diff)
Fixed some bugs; added re-connect mode
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@4794 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps/app_rpt.c')
-rwxr-xr-xapps/app_rpt.c301
1 files changed, 255 insertions, 46 deletions
diff --git a/apps/app_rpt.c b/apps/app_rpt.c
index 702f465e2..faafc2048 100755
--- a/apps/app_rpt.c
+++ b/apps/app_rpt.c
@@ -3,7 +3,7 @@
* Asterisk -- A telephony toolkit for Linux.
*
* Radio Repeater / Remote Base program
- * version 0.18 11/16/04
+ * version 0.19 01/14/05
*
* See http://www.zapatatelephony.org/app_rpt.html
*
@@ -63,11 +63,24 @@
*
*/
+/* The following is JUST GROSS!! There is some soft of underlying problem,
+ probably in channel_iax2.c, that causes an IAX2 connection to sometimes
+ stop transmitting randomly. We have been working for weeks to try to
+ locate it and fix it, but to no avail We finally decided to put our
+ tail between our legs, and just make the radio system re-connect upon
+ network failure. This just shouldnt have to be done. For normal operation,
+ comment-out the following line */
+#define RECONNECT_KLUDGE
+
/* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
#define MAXDTMF 32
#define DTMF_TIMEOUT 3
+#define DISC_TIME 10000 /* report disc after 10 seconds of no connect */
+#define MAX_RETRIES 5
+
+#define RETRY_TIMER_MS 5000
#define MAXREMSTR 15
@@ -137,7 +150,7 @@ enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
#include <tonezone.h>
#include <linux/zaptel.h>
-static char *tdesc = "Radio Repeater / Remote Base version 0.18 11/16/2004";
+static char *tdesc = "Radio Repeater / Remote Base version 0.19 01/14/2005";
static char *app = "Rpt";
static char *synopsis = "Radio Repeater/Remote Base Control System";
@@ -148,7 +161,7 @@ static char *descrip =
static int debug = 0; /* Set this >0 for extra debug output */
static int nrpts = 0;
-
+char *discstr = "!!DISCONNECT!!";
struct ast_config *cfg;
@@ -178,7 +191,11 @@ struct rpt_link
char lastrx;
char connected;
char outbound;
- long elaptime;
+ char disced;
+ long elaptime;
+ long disctime;
+ long retrytimer;
+ int retries;
struct ast_channel *chan;
struct ast_channel *pchan;
} ;
@@ -689,7 +706,7 @@ static int telem_lookup(struct ast_channel *chan, char *node, char *name)
*/
-static void wait_interval(struct rpt *myrpt, int type)
+static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
{
int interval;
char *wait_times;
@@ -739,7 +756,7 @@ static void wait_interval(struct rpt *myrpt, int type)
return;
}
- usleep(1000 * interval);
+ ast_safe_sleep(chan,interval);
return;
}
@@ -808,7 +825,7 @@ struct tm localtm;
case ID:
case ID1:
/* wait a bit */
- wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM);
+ wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
res = telem_any(mychannel, ident);
imdone=1;
@@ -824,17 +841,17 @@ struct tm localtm;
case PROC:
/* wait a little bit longer */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
break;
case TERM:
/* wait a little bit longer */
- wait_interval(myrpt, DLY_CALLTERM);
+ wait_interval(myrpt, DLY_CALLTERM, mychannel);
res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
break;
case COMPLETE:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = telem_lookup(mychannel, myrpt->name, "functcomplete");
break;
case UNKEY:
@@ -860,7 +877,7 @@ struct tm localtm;
}
/* wait a little bit */
- wait_interval(myrpt, DLY_UNKEY);
+ wait_interval(myrpt, DLY_UNKEY, mychannel);
hastx = 0;
@@ -901,7 +918,7 @@ struct tm localtm;
break;
case REMDISC:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
if (!res)
res = ast_waitstream(mychannel, "");
@@ -914,22 +931,22 @@ struct tm localtm;
break;
case REMALREADY:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
break;
case REMNOTFOUND:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
break;
case REMGO:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
break;
case CONNECTED:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
if (!res)
res = ast_waitstream(mychannel, "");
@@ -951,7 +968,7 @@ struct tm localtm;
break;
case STATUS:
/* wait a little bit */
- wait_interval(myrpt, DLY_TELEM);
+ wait_interval(myrpt, DLY_TELEM, mychannel);
hastx = 0;
linkbase.next = &linkbase;
linkbase.prev = &linkbase;
@@ -1051,7 +1068,7 @@ struct tm localtm;
break;
case STATS_TIME:
- wait_interval(myrpt, DLY_TELEM); /* Wait a little bit */
+ wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
t = time(NULL);
localtime_r(&t, &localtm);
/* Say the phase of the day is before the time */
@@ -1085,7 +1102,7 @@ struct tm localtm;
break;
if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
break;
- wait_interval(myrpt, DLY_TELEM); /* Wait a little bit */
+ wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
/* Say "version" */
if (sayfile(mychannel,"rpt/version") == -1)
{
@@ -1113,7 +1130,7 @@ struct tm localtm;
imdone = 1;
break;
case ARB_ALPHA:
- wait_interval(myrpt, DLY_TELEM); /* Wait a little bit */
+ wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
if(mytele->param)
saycharstr(mychannel, mytele->param);
imdone = 1;
@@ -1376,7 +1393,11 @@ struct ast_channel *mychannel,*genchannel;
myrpt->mydtmf = 0;
}
ast_mutex_unlock(&myrpt->lock);
- usleep(25000);
+ if (ast_safe_sleep(mychannel,25))
+ {
+ ast_mutex_unlock(&myrpt->lock);
+ break;
+ }
ast_mutex_lock(&myrpt->lock);
}
ast_mutex_unlock(&myrpt->lock);
@@ -1410,7 +1431,7 @@ struct rpt_link *l;
if (!strcmp(l->name,myrpt->cmdnode))
{
wf.data = strdup(str);
- ast_write(l->chan,&wf);
+ if (l->chan) ast_write(l->chan,&wf);
return;
}
l = l->next;
@@ -1420,7 +1441,7 @@ struct rpt_link *l;
while(l != &myrpt->links)
{
wf.data = strdup(str);
- ast_write(l->chan,&wf);
+ if (l->chan) ast_write(l->chan,&wf);
l = l->next;
}
return;
@@ -1450,8 +1471,6 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
switch(myatoi(param)){
case 1: /* Link off */
-
-
val = ast_variable_retrieve(cfg, NODES, digitbuf);
if (!val){
if(strlen(digitbuf) >= myrpt->longestnode)
@@ -1471,8 +1490,24 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
l = l->next;
}
if (l != &myrpt->links){ /* if found */
+ struct ast_frame wf;
+
+ l->retries = MAX_RETRIES + 1;
+ l->disced = 1;
ast_mutex_unlock(&myrpt->lock);
- ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
+ wf.frametype = AST_FRAME_TEXT;
+ wf.subclass = 0;
+ wf.offset = 0;
+ wf.mallocd = 1;
+ wf.datalen = strlen(discstr) + 1;
+ wf.samples = 0;
+ wf.data = strdup(discstr);
+ if (l->chan)
+ {
+ ast_write(l->chan,&wf);
+ if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
+ ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
+ }
rpt_telemetry(myrpt, COMPLETE, NULL);
return DC_COMPLETE;
}
@@ -1501,13 +1536,13 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
if (l != &myrpt->links)
{
/* if already in this mode, just ignore */
- if (!l->mode) {
+ if ((!l->mode) || (!l->chan)) {
ast_mutex_unlock(&myrpt->lock);
rpt_telemetry(myrpt,REMALREADY,NULL);
return DC_COMPLETE;
}
- ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
+ if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
}
ast_mutex_unlock(&myrpt->lock);
/* establish call in monitor mode */
@@ -1544,6 +1579,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
}
else
{
+ rpt_telemetry(myrpt,CONNFAIL,l);
free(l);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
@@ -1596,12 +1632,12 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
/* if found */
if (l != &myrpt->links){
/* if already in this mode, just ignore */
- if (l->mode){
+ if ((l->mode) || (!l->chan)) {
ast_mutex_unlock(&myrpt->lock);
rpt_telemetry(myrpt, REMALREADY, NULL);
return DC_COMPLETE;
}
- ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
+ if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
}
ast_mutex_unlock(&myrpt->lock);
/* establish call in tranceive mode */
@@ -1613,6 +1649,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
/* zero the silly thing */
memset((char *)l,0,sizeof(struct rpt_link));
l->mode = 1;
+ l->outbound = 1;
strncpy(l->name, digitbuf, MAXNODESTR - 1);
l->isremote = (s && ast_true(s));
snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
@@ -1638,6 +1675,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
ast_call(l->chan,tele,999);
}
else{
+ rpt_telemetry(myrpt,CONNFAIL,l);
free(l);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
@@ -1703,7 +1741,7 @@ static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int co
l = myrpt->links.next;
while(l != &myrpt->links){
- ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
+ if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
l = l->next;
}
rpt_telemetry(myrpt, COMPLETE, NULL);
@@ -2282,6 +2320,13 @@ struct ast_frame wf;
wf.samples = 0;
/* put string in our buffer */
strncpy(tmp,str,sizeof(tmp) - 1);
+ if (!strcmp(tmp,discstr))
+ {
+ mylink->disced = 1;
+ mylink->retries = MAX_RETRIES + 1;
+ ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
+ return;
+ }
if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
{
ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
@@ -2311,7 +2356,7 @@ struct ast_frame wf;
/* send, but not to src */
if (strcmp(l->name,src)) {
wf.data = strdup(str);
- ast_write(l->chan,&wf);
+ if (l->chan) ast_write(l->chan,&wf);
}
return;
}
@@ -2330,7 +2375,7 @@ struct ast_frame wf;
/* send, but not to src */
if (strcmp(l->name,src)) {
wf.data = strdup(str);
- ast_write(l->chan,&wf);
+ if (l->chan) ast_write(l->chan,&wf);
}
l = l->next;
}
@@ -2830,6 +2875,57 @@ int seq,res;
return res;
}
+static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
+{
+ char *val, *s, *s1, *tele;
+ char tmp[300], deststr[300] = "";
+
+ val = ast_variable_retrieve(cfg, NODES, l->name);
+ if (!val)
+ {
+ fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
+ return -1;
+ }
+ strncpy(tmp,val,sizeof(tmp) - 1);
+ s = tmp;
+ s1 = strsep(&s,",");
+ ast_mutex_lock(&myrpt->lock);
+ snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
+ tele = strchr(deststr, '/');
+ if (!tele) {
+ fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
+ ast_mutex_unlock(&myrpt->lock);
+ return -1;
+ }
+ *tele++ = 0;
+ l->elaptime = 0;
+ l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
+ if (l->chan){
+ ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
+ ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
+ l->chan->whentohangup = 0;
+ l->chan->appl = "Apprpt";
+ l->chan->data = "(Remote Rx)";
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
+ deststr, tele, l->chan->name);
+ if(l->chan->cid.cid_num)
+ free(l->chan->cid.cid_num);
+ l->chan->cid.cid_num = strdup(myrpt->name);
+ ast_call(l->chan,tele,999);
+ }
+ else
+ {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
+ deststr,tele,l->chan->name);
+ ast_mutex_unlock(&myrpt->lock);
+ return -1;
+ }
+ ast_mutex_unlock(&myrpt->lock);
+ return 0;
+}
+
/* single thread with one file (request) to dial */
static void *rpt(void *this)
{
@@ -3217,8 +3313,11 @@ char cmd[MAXDTMF+1] = "";
l = myrpt->links.next;
while(l != &myrpt->links)
{
- cs[n++] = l->chan;
- cs[n++] = l->pchan;
+ if ((!l->disctime) && l->chan)
+ {
+ cs[n++] = l->chan;
+ cs[n++] = l->pchan;
+ }
l = l->next;
}
ast_mutex_unlock(&myrpt->lock);
@@ -3230,6 +3329,23 @@ char cmd[MAXDTMF+1] = "";
l = myrpt->links.next;
while(l != &myrpt->links)
{
+#ifdef RECONNECT_KLUDGE
+ if (l->disctime && l->chan)
+ {
+ l->disctime -= elap;
+ if (l->disctime <= 0)
+ {
+ l->disctime = 0;
+ l->disced = 1;
+ ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
+ }
+ }
+ if (l->retrytimer)
+ {
+ l->retrytimer -= elap;
+ if (l->retrytimer < 0) l->retrytimer = 0;
+ }
+#endif
/* ignore non-timing channels */
if (l->elaptime < 0)
{
@@ -3239,13 +3355,57 @@ char cmd[MAXDTMF+1] = "";
l->elaptime += elap;
/* if connection has taken too long */
if ((l->elaptime > MAXCONNECTTIME) &&
- (l->chan->_state != AST_STATE_UP))
+ ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
{
+ l->elaptime = 0;
ast_mutex_unlock(&myrpt->lock);
- ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
+ if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
+#ifndef RECONNECT_KLUDGE
rpt_telemetry(myrpt,CONNFAIL,l);
+#endif
+ ast_mutex_lock(&myrpt->lock);
+ break;
+ }
+#ifdef RECONNECT_KLUDGE
+ if ((!l->chan) && (!l->retrytimer) && l->outbound &&
+ (l->retries++ < MAX_RETRIES))
+ {
+ if (l->chan) ast_hangup(l->chan);
+ ast_mutex_unlock(&myrpt->lock);
+ if (attempt_reconnect(myrpt,l) == -1)
+ {
+ l->retrytimer = RETRY_TIMER_MS;
+ }
ast_mutex_lock(&myrpt->lock);
}
+ if ((!l->chan) && (!l->retrytimer) && l->outbound &&
+ (l->retries >= MAX_RETRIES))
+ {
+ /* remove from queue */
+ remque((struct qelem *) l);
+ if (!strcmp(myrpt->cmdnode,l->name))
+ myrpt->cmdnode[0] = 0;
+ ast_mutex_unlock(&myrpt->lock);
+ rpt_telemetry(myrpt,REMDISC,l);
+ /* hang-up on call to device */
+ ast_hangup(l->pchan);
+ free(l);
+ break;
+ }
+ if ((!l->chan) && (!l->disctime) && (!l->outbound))
+ {
+ /* remove from queue */
+ remque((struct qelem *) l);
+ if (!strcmp(myrpt->cmdnode,l->name))
+ myrpt->cmdnode[0] = 0;
+ ast_mutex_unlock(&myrpt->lock);
+ rpt_telemetry(myrpt,REMDISC,l);
+ /* hang-up on call to device */
+ ast_hangup(l->pchan);
+ free(l);
+ break;
+ }
+#endif
l = l->next;
}
if (myrpt->tailtimer) myrpt->tailtimer -= elap;
@@ -3464,6 +3624,11 @@ char cmd[MAXDTMF+1] = "";
l = myrpt->links.next;
while(l != &myrpt->links)
{
+ if (l->disctime)
+ {
+ l = l->next;
+ continue;
+ }
if (who == l->chan) /* if it was a read from rx */
{
ast_mutex_lock(&myrpt->lock);
@@ -3494,6 +3659,30 @@ char cmd[MAXDTMF+1] = "";
f = ast_read(l->chan);
if (!f)
{
+#ifdef RECONNECT_KLUDGE
+ if ((!l->disced) && (!l->outbound))
+ {
+ l->disctime = DISC_TIME;
+ ast_mutex_lock(&myrpt->lock);
+ ast_hangup(l->chan);
+ ast_mutex_unlock(&myrpt->lock);
+ l->chan = 0;
+ break;
+ }
+
+ if (l->retrytimer) break;
+ if (l->outbound && (l->retries++ < MAX_RETRIES))
+ {
+ ast_mutex_lock(&myrpt->lock);
+ ast_hangup(l->chan);
+ ast_mutex_unlock(&myrpt->lock);
+ if (attempt_reconnect(myrpt,l) == -1)
+ {
+ l->retrytimer = RETRY_TIMER_MS;
+ }
+ break;
+ }
+#endif
ast_mutex_lock(&myrpt->lock);
/* remove from queue */
remque((struct qelem *) l);
@@ -3519,9 +3708,11 @@ char cmd[MAXDTMF+1] = "";
{
if (f->subclass == AST_CONTROL_ANSWER)
{
+ char lconnected = l->connected;
l->connected = 1;
l->elaptime = -1;
- rpt_telemetry(myrpt,CONNECTED,l);
+ l->retries = 0;
+ if (!lconnected) rpt_telemetry(myrpt,CONNECTED,l);
}
/* if RX key */
if (f->subclass == AST_CONTROL_RADIO_KEY)
@@ -3538,6 +3729,30 @@ char cmd[MAXDTMF+1] = "";
if (f->subclass == AST_CONTROL_HANGUP)
{
ast_frfree(f);
+#ifdef RECONNECT_KLUDGE
+ if ((!l->outbound) && (!l->disced))
+ {
+ l->disctime = DISC_TIME;
+ ast_mutex_lock(&myrpt->lock);
+ ast_hangup(l->chan);
+ ast_mutex_unlock(&myrpt->lock);
+ l->chan = 0;
+ break;
+ }
+
+ if (l->retrytimer) break;
+ if (l->outbound && (l->retries++ < MAX_RETRIES))
+ {
+ ast_mutex_lock(&myrpt->lock);
+ ast_hangup(l->chan);
+ ast_mutex_unlock(&myrpt->lock);
+ if (attempt_reconnect(myrpt,l) == -1)
+ {
+ l->retrytimer = RETRY_TIMER_MS;
+ }
+ break;
+ }
+#endif
ast_mutex_lock(&myrpt->lock);
/* remove from queue */
remque((struct qelem *) l);
@@ -3617,7 +3832,7 @@ char cmd[MAXDTMF+1] = "";
/* remove from queue */
remque((struct qelem *) l);
/* hang-up on call to device */
- ast_hangup(l->chan);
+ if (l->chan) ast_hangup(l->chan);
ast_hangup(l->pchan);
l = l->next;
free(ll);
@@ -3867,13 +4082,7 @@ static int rpt_exec(struct ast_channel *chan, void *data)
/* if found */
if (l != &myrpt->links)
{
- /* remove from queue */
- remque((struct qelem *) l);
- ast_mutex_unlock(&myrpt->lock);
- /* hang-up on call to device */
- ast_hangup(l->chan);
- ast_hangup(l->pchan);
- free(l);
+ if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
usleep(500000);
} else
ast_mutex_unlock(&myrpt->lock);