Fixed transmit/link hang problem and autopatch wierdness

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5682 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Jim Dixon 20 years ago
parent e4e9f26cf0
commit 882eea1390

@ -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 <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/cli.h>
#include <asterisk/config.h>
#include <asterisk/say.h>
#include <asterisk/localtime.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
@ -153,7 +154,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.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);
}

Loading…
Cancel
Save