From 882eea1390e00092f1cea5b984093c7c74610022 Mon Sep 17 00:00:00 2001 From: Jim Dixon Date: Sun, 15 May 2005 21:49:35 +0000 Subject: Fixed transmit/link hang problem and autopatch wierdness git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5682 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_rpt.c | 376 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 280 insertions(+), 96 deletions(-) (limited to 'apps') diff --git a/apps/app_rpt.c b/apps/app_rpt.c index 2595bbbd7..44f6a802d 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.23 01/28/05 + * version 0.24 05/15/05 * * See http://www.zapatatelephony.org/app_rpt.html * @@ -120,19 +120,20 @@ enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT}; enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM}; -#include "asterisk/utils.h" -#include "asterisk/lock.h" -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/callerid.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/translate.h" -#include "asterisk/options.h" -#include "asterisk/config.h" -#include "asterisk/say.h" -#include "asterisk/localtime.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -153,7 +154,7 @@ enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM}; #include #include -static char *tdesc = "Radio Repeater / Remote Base version 0.23 01/28/2005"; +static char *tdesc = "Radio Repeater / Remote Base version 0.24 05/15/2005"; static char *app = "Rpt"; @@ -257,6 +258,8 @@ static struct rpt int hangtime; int totime; int idtime; + int unkeytocttimer; + char keyed; char exttx; char localtx; char remoterx; @@ -293,9 +296,33 @@ static struct rpt char stopgen; int link_longestfunc; int longestfunc; - int longestnode; + int longestnode; + int threadrestarts; + time_t disgorgetime; + time_t lastthreadrestarttime; } rpt_vars[MAXRPTS]; +/* +* CLI extensions +*/ + +/* Debug mode */ +static int rpt_do_debug(int fd, int argc, char *argv[]); + +static char debug_usage[] = +"Usage: rpt debug level {0-7}\n" +" Enables debug messages in app_rpt\n"; + +static struct ast_cli_entry cli_debug = + { { "rpt", "debug", "level" }, rpt_do_debug, "Enable app_rpt debugging", debug_usage }; + + + +/* +* Telemetry defaults +*/ + + static struct telem_defaults tele_defs[] = { {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"}, {"ct2","|t(660,880,150,3072)"}, @@ -347,10 +374,34 @@ static int myatoi(char *str) int ret; if (str == NULL) return -1; - if (sscanf(str,"%d",&ret) != 1) return -1; + if (sscanf(str,"%i",&ret) != 1) return -1; return ret; } +/* +* Enable or disable debug output at a given level at the console +*/ + +static int rpt_do_debug(int fd, int argc, char *argv[]) +{ + int newlevel; + + if (argc != 4) + return RESULT_SHOWUSAGE; + newlevel = myatoi(argv[3]); + if((newlevel < 0) || (newlevel > 7)) + return RESULT_SHOWUSAGE; + if(newlevel) + ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel); + else + ast_cli(fd, "app_rpt Debugging disabled\n"); + + debug = newlevel; + return RESULT_SUCCESS; +} + + + static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude) { int flags = ZT_IOMUX_WRITEEMPTY; @@ -710,6 +761,63 @@ static int telem_lookup(struct ast_channel *chan, char *node, char *name) return res; } +/* +* Retrieve a wait interval +*/ + +static int get_wait_interval(struct rpt *myrpt, int type) +{ + int interval; + char *wait_times; + char *wait_times_save; + + wait_times_save = NULL; + wait_times = ast_variable_retrieve(cfg, myrpt->name, "wait_times"); + + if(wait_times){ + wait_times_save = ast_strdupa(wait_times); + if(!wait_times_save){ + ast_log(LOG_WARNING, "Out of memory in wait_interval()\n"); + wait_times = NULL; + } + } + + switch(type){ + case DLY_TELEM: + if(wait_times) + interval = retrieve_astcfgint(wait_times_save, "telemwait", 500, 5000, 1000); + else + interval = 1000; + break; + + case DLY_ID: + if(wait_times) + interval = retrieve_astcfgint(wait_times_save, "idwait",250,5000,500); + else + interval = 500; + break; + + case DLY_UNKEY: + if(wait_times) + interval = retrieve_astcfgint(wait_times_save, "unkeywait",500,5000,1000); + else + interval = 1000; + break; + + case DLY_CALLTERM: + if(wait_times) + interval = retrieve_astcfgint(wait_times_save, "calltermwait",500,5000,1500); + else + interval = 1500; + break; + + default: + return 0; + } + return interval; +} + + /* * Wait a configurable interval of time */ @@ -718,63 +826,16 @@ static int telem_lookup(struct ast_channel *chan, char *node, char *name) static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan) { int interval; - char *wait_times; - char *wait_times_save; - - wait_times_save = NULL; - wait_times = ast_variable_retrieve(cfg, myrpt->name, "wait_times"); - - if(wait_times){ - wait_times_save = ast_strdupa(wait_times); - if(!wait_times_save){ - ast_log(LOG_WARNING, "Out of memory in wait_interval()\n"); - wait_times = NULL; - } - } - - switch(type){ - case DLY_TELEM: - if(wait_times) - interval = retrieve_astcfgint(wait_times_save, "telemwait", 500, 5000, 1000); - else - interval = 1000; - break; - - case DLY_ID: - if(wait_times) - interval = retrieve_astcfgint(wait_times_save, "idwait",250,5000,500); - else - interval = 500; - break; - - case DLY_UNKEY: - if(wait_times) - interval = retrieve_astcfgint(wait_times_save, "unkeywait",500,5000,1000); - else - interval = 1000; - break; - - case DLY_CALLTERM: - if(wait_times) - interval = retrieve_astcfgint(wait_times_save, "calltermwait",500,5000,1500); - else - interval = 1500; - break; - - default: - return; - } - - ast_safe_sleep(chan,interval); + if((interval = get_wait_interval(myrpt, type))) + ast_safe_sleep(chan,interval); return; } - static void *rpt_tele_thread(void *this) { ZT_CONFINFO ci; /* conference info */ -int res = 0,hastx,imdone = 0, unkeys_queued; +int res = 0,hastx,imdone = 0, unkeys_queued, x; struct rpt_tele *mytele = (struct rpt_tele *)this; struct rpt_tele *tlist; struct rpt *myrpt; @@ -867,7 +928,16 @@ struct tm localtm; case UNKEY: /* - * if there's one already queued, don't do another + * Reset the Unkey to CT timer + */ + + x = get_wait_interval(myrpt, DLY_UNKEY); + ast_mutex_lock(&myrpt->lock); + myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */ + ast_mutex_unlock(&myrpt->lock); + + /* + * If there's one already queued, don't do another */ tlist = myrpt->tele.next; @@ -886,11 +956,37 @@ struct tm localtm; break; } - /* wait a little bit */ - wait_interval(myrpt, DLY_UNKEY, mychannel); + /* Wait for the telemetry timer to expire */ + /* Periodically check the timer since it can be re-initialized above */ + + while(myrpt->unkeytocttimer) + { + int ctint; + if(myrpt->unkeytocttimer > 100) + ctint = 100; + else + ctint = myrpt->unkeytocttimer; + ast_safe_sleep(mychannel, ctint); + ast_mutex_lock(&myrpt->lock); + if(myrpt->unkeytocttimer < ctint) + myrpt->unkeytocttimer = 0; + else + myrpt->unkeytocttimer -= ctint; + ast_mutex_unlock(&myrpt->lock); + } + + + /* + * Now, the carrier on the rptr rx should be gone. + * If it re-appeared, then forget about sending the CT + */ + if(myrpt->keyed){ + imdone = 1; + break; + } + hastx = 0; - l = myrpt->links.next; if (l != &myrpt->links) { @@ -1369,11 +1465,12 @@ struct ast_channel *mychannel,*genchannel; ast_mutex_unlock(&myrpt->lock); pthread_exit(NULL); } + usleep(10000); ast_mutex_lock(&myrpt->lock); myrpt->callmode = 3; while(myrpt->callmode) { - if ((!mychannel->pvt) && (myrpt->callmode != 4)) + if ((!mychannel->pbx) && (myrpt->callmode != 4)) { myrpt->callmode = 4; ast_mutex_unlock(&myrpt->lock); @@ -1401,7 +1498,7 @@ struct ast_channel *mychannel,*genchannel; } ast_mutex_unlock(&myrpt->lock); tone_zone_play_tone(genchannel->fds[0],-1); - if (mychannel->pvt) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV); + if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV); ast_hangup(genchannel); ast_mutex_lock(&myrpt->lock); myrpt->callmode = 0; @@ -1895,6 +1992,9 @@ static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int comm rpt_telemetry(myrpt, TEST_TONE, NULL); return DC_COMPLETE; + case 5: /* Disgorge variables to log for debug purposes */ + myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */ + return DC_COMPLETE; } return DC_INDETERMINATE; } @@ -2910,6 +3010,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l) fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name); return -1; } + ast_mutex_lock(&myrpt->lock); /* remove from queue */ remque((struct qelem *) l); @@ -2938,7 +3039,8 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l) 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); + ast_call(l->chan,tele,999); + } else { @@ -2951,6 +3053,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l) /* put back in queue queue */ insque((struct qelem *)l,(struct qelem *)myrpt->links.next); ast_mutex_unlock(&myrpt->lock); + ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name); return 0; } @@ -2959,7 +3062,7 @@ static void *rpt(void *this) { struct rpt *myrpt = (struct rpt *)this; char *tele,*idtalkover; -int ms = MSWAIT,lasttx,keyed,val,remrx,identqueued,nonidentqueued,res; +int ms = MSWAIT,lasttx=0,val,remrx=0,identqueued,nonidentqueued,res; struct ast_channel *who; ZT_CONFINFO ci; /* conference info */ time_t dtmf_time,t; @@ -3164,7 +3267,7 @@ char cmd[MAXDTMF+1] = ""; myrpt->tonotify = 0; myrpt->retxtimer = 0; lasttx = 0; - keyed = 0; + myrpt->keyed = 0; idtalkover = ast_variable_retrieve(cfg, myrpt->name, "idtalkover"); myrpt->dtmfidx = -1; myrpt->dtmfbuf[0] = 0; @@ -3173,6 +3276,7 @@ char cmd[MAXDTMF+1] = ""; dtmf_time = 0; myrpt->rem_dtmf_time = 0; myrpt->enable = 1; + myrpt->disgorgetime = 0; ast_mutex_unlock(&myrpt->lock); val = 0; ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0); @@ -3182,14 +3286,70 @@ char cmd[MAXDTMF+1] = ""; { struct ast_frame *f; struct ast_channel *cs[300]; - int totx,elap,n,toexit; + int totx=0,elap=0,n,toexit=0; + + /* DEBUG Dump */ + if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){ + struct rpt_link *zl; + struct rpt_tele *zt; + + myrpt->disgorgetime = 0; + ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n"); + ast_log(LOG_NOTICE,"totx = %d\n",totx); + ast_log(LOG_NOTICE,"remrx = %d\n",remrx); + ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx); + ast_log(LOG_NOTICE,"elap = %d\n",elap); + ast_log(LOG_NOTICE,"toexit = %d\n",toexit); + + ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed); + ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx); + ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode); + ast_log(LOG_NOTICE,"myrpt->enable = %d\n",myrpt->enable); + ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid); + ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed); + ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify); + ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer); + ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer); + ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer); + + zl = myrpt->links.next; + while(zl != &myrpt->links){ + ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name); + ast_log(LOG_NOTICE," link->lasttx %d\n",zl->lasttx); + ast_log(LOG_NOTICE," link->lastrx %d\n",zl->lastrx); + ast_log(LOG_NOTICE," link->connected %d\n",zl->connected); + ast_log(LOG_NOTICE," link->hasconnected %d\n",zl->hasconnected); + ast_log(LOG_NOTICE," link->outbound %d\n",zl->outbound); + ast_log(LOG_NOTICE," link->disced %d\n",zl->disced); + ast_log(LOG_NOTICE," link->killme %d\n",zl->killme); + ast_log(LOG_NOTICE," link->disctime %ld\n",zl->disctime); + ast_log(LOG_NOTICE," link->retrytimer %ld\n",zl->retrytimer); + ast_log(LOG_NOTICE," link->retries = %d\n",zl->retries); + + zl = zl->next; + } + + zt = myrpt->tele.next; + if(zt != &myrpt->tele) + ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n"); + while(zt != &myrpt->tele){ + ast_log(LOG_NOTICE," Telemetry mode: %d\n",zt->mode); + zt = zt->next; + } + ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n"); + + } + + + + ast_mutex_lock(&myrpt->lock); if (ast_check_hangup(myrpt->rxchannel)) break; if (ast_check_hangup(myrpt->txchannel)) break; if (ast_check_hangup(myrpt->pchannel)) break; if (ast_check_hangup(myrpt->txpchannel)) break; - myrpt->localtx = keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]); + myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]); /* If someone's connected, and they're transmitting from their end to us, set remrx true */ @@ -3203,9 +3363,9 @@ char cmd[MAXDTMF+1] = ""; /* Create a "must_id" flag for the cleanup ID */ - myrpt->mustid |= (myrpt->idtimer) && (keyed || remrx) ; + myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ; - /* Build a fresh totx from keyed and autopatch activated */ + /* Build a fresh totx from myrpt->keyed and autopatch activated */ totx = myrpt->localtx || myrpt->callmode; @@ -3255,7 +3415,7 @@ char cmd[MAXDTMF+1] = ""; } /* if wants to transmit and in phone call, but timed out, reset time-out timer if keyed */ - if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!keyed)) + if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed)) { myrpt->tounkeyed = 1; } @@ -3277,7 +3437,7 @@ char cmd[MAXDTMF+1] = ""; /* if not timed-out, add in tail */ if (myrpt->totimer) totx = totx || myrpt->tailtimer; /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */ - if (identqueued && (keyed || remrx) && idtalkover) { + if (identqueued && (myrpt->keyed || remrx) && idtalkover) { int hasid = 0,hastalkover = 0; telem = myrpt->tele.next; @@ -3336,7 +3496,9 @@ char cmd[MAXDTMF+1] = ""; { myrpt->rem_dtmfidx = -1; myrpt->rem_dtmfbuf[0] = 0; - } + } + + /* Reconnect kludge */ l = myrpt->links.next; while(l != &myrpt->links) { @@ -3391,16 +3553,13 @@ char cmd[MAXDTMF+1] = ""; } } else l->retxtimer = 0; #ifdef RECONNECT_KLUDGE - if (l->disctime && l->chan) + if (l->disctime) /* Disconnect timer active on a channel ? */ { l->disctime -= elap; - if (l->disctime <= 0) - { - l->disctime = 0; - l->disced = 1; - ast_softhangup(l->chan,AST_SOFTHANGUP_DEV); - } + if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */ + l->disctime = 0; /* Yep */ } + if (l->retrytimer) { l->retrytimer -= elap; @@ -3625,7 +3784,7 @@ char cmd[MAXDTMF+1] = ""; } if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) { - myrpt->mydtmf = f->subclass; + myrpt->mydtmf = c; } ast_mutex_unlock(&myrpt->lock); continue; @@ -3642,16 +3801,16 @@ char cmd[MAXDTMF+1] = ""; if (f->subclass == AST_CONTROL_RADIO_KEY) { if (debug) printf("@@@@ rx key\n"); - keyed = 1; + myrpt->keyed = 1; } /* if RX un-key */ if (f->subclass == AST_CONTROL_RADIO_UNKEY) { if (debug) printf("@@@@ rx un-key\n"); - if(keyed) { + if(myrpt->keyed) { rpt_telemetry(myrpt,UNKEY,NULL); } - keyed = 0; + myrpt->keyed = 0; } } ast_frfree(f); @@ -4103,6 +4262,23 @@ pthread_attr_t attr; rv = pthread_kill(rpt_vars[i].rpt_thread,0); if (rv) { + if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15) + { + if(rpt_vars[i].threadrestarts >= 5) + { + ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n"); + exit(1); /* Stuck in a restart loop, kill Asterisk and start over */ + } + else + { + ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name); + rpt_vars[i].threadrestarts++; + } + } + else + rpt_vars[i].threadrestarts = 0; + + rpt_vars[i].lastthreadrestarttime = time(NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]); @@ -4518,13 +4694,21 @@ int unload_module(void) if (!strcmp(rpt_vars[i].name,NODES)) continue; ast_mutex_destroy(&rpt_vars[i].lock); } - return ast_unregister_application(app); - return 0; + i = ast_unregister_application(app); + + /* Unregister cli extensions */ + ast_cli_unregister(&cli_debug); + + return i; } int load_module(void) { ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL); + + /* Register cli extensions */ + ast_cli_register(&cli_debug); + return ast_register_application(app, rpt_exec, synopsis, descrip); } -- cgit v1.2.3