Good day list,
I am hopeful that someone in here can assist me with determining how to get my asterisk box to NOT crash if an extension begins to unpark a call and then subsequently hangs up during the process.
I am using the valet_parking application in release 1.09.
I have enclosed some of the information related to this issue below.
What I am in search of is some magical pixie dust to sprinkle on the code, or at the very least a point or nudge in the right direction for some code or function that I can call to make sure that a channel is still up and functional prior to completing a bridge of the channels.
Thanks again for your assistance.
~ron
Problem: Asterisk crashes if an extension hangsup in the middle of unparking a call.
Solution: Would it be possible to make sure that the channel for the extension is still valid right before performing the actual bridge, or is there a way to make sure that an attempted bridge does not
fail if the "UNPARKING" extension hangsup during the unpark.
Duplicatable: Method of duplicating this behaviour Follows
Get a call parked in extension 903 in lot receiver.
NExt go to an extension and unpark the call, however when alison says "Please wait while your call is connected", the extension hangs up.
CLI OUTPUT:
Executing ValetParkCall("Zap/3-2", "903|receiver|0|201") in new stack
-- Attempting native bridge of Zap/25-1 and Zap/3-1
-- Executing ValetUnparkCall("SIP/206-36c3", "903|receiver") in new stack
-- Call is Valet Parked Here [903] we should wait
-- Playing 'pls-wait-connect-call' (language 'en')
-- Call is Valet Parked Here [903] we finished waiting
-- Debug Step 1 903
-- Debug Step 2 903
-- Debug Step 3 903
-- Debug Step 4 903
-- Channel SIP/206-36c3 connected to Valet Parked call -1 in lot receiver
-- Debug Step 5 903
-- Debug Step 6 903
-- Debug Step 7 903
-- Hungup 'Zap/3-2'
-- Debug Step 8 903
-- Debug Step 9 903
== Spawn extension (from-internal-dispatch, *903, 1) exited non-zero on 'SIP/206-36c3'
-- Executing Macro("SIP/206-36c3", "hangupcall") in new stack
-- Executing ResetCDR("SIP/206-36c3", "w") in new stack
-- Executing NoCDR("SIP/206-36c3", "") in new stack
-- Executing Wait("SIP/206-36c3", "5") in new stack
== Spawn extension (macro-hangupcall, s, 3) exited non-zero on 'SIP/206-36c3' in macro 'hangupcall'
== Spawn extension (from-internal-dispatch, h, 1) exited non-zero on 'SIP/206-36c3'
-- Attempting native bridge of Zap/25-1 and Zap/3-1
*CLI>
Disconnected from Asterisk server
/usr/sbin/safe_asterisk: line 83: 29001 Segmentation fault (core dumped) asterisk ${CLIARGS} ${ASTARGS} 1>&/dev/${TTY} </dev/${TTY}
Asterisk ended with exit status 139
Asterisk exited on signal 11.
Automatically restarting Asterisk.
Source Code that got us here:
app_valetparking.c
Function in question?
static int valetunpark_call(struct ast_channel *chan, void *data) {
int res=0;
struct localuser *u;
struct ast_channel *peer=NULL;
int valetpark=-1;
int dres;
struct ast_bridge_config config;
char *exten,*lotname;
if (!data) {
ast_log(LOG_WARNING, "ValetUnpark requires an argument (extension number)\n");
return -1;
}
exten=lotname=NULL;
if(!data || !(exten = ast_strdupa(data))) {
ast_log(LOG_WARNING,"No Memory!\n");
return -1;
}
if((lotname=strchr(exten,'|'))) {
*lotname = '\0';
*lotname++;
}
if(!lotname) {
ast_log(LOG_WARNING,"Please specify a lotname in the dialplan.");
return -1;
}
LOCAL_USER_ADD(u);
ast_answer(chan);
/* JK02: it helps to answer the channel if not already up */
if (chan->_state != AST_STATE_UP) {
ast_answer(chan);
}
/* check to see if a call is in the parking slot if not do not even try to unpark it */
if(ast_is_valetparked(exten , lotname)) {
ast_verbose(VERBOSE_PREFIX_3 "Call is Valet Parked Here [%s] we should wait\n", exten);
/* ANNOUNCE TO THE CALLER THAT WE ARE ABOUT TO UNPARK THE CALL */
/*main reason for this is to allow the parking application the opportunity to complete finish its parking tasks prior to us unparking it */
dres = ast_streamfile(chan, "pls-wait-connect-call", chan->language);
if (!dres) {
dres = ast_waitstream(chan, "");
} else {
ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
res = 0;
}
/* final place where we take a fast nap to let things settle down a bit */
ast_safe_sleep(chan, 500);
ast_verbose(VERBOSE_PREFIX_3 "Call is Valet Parked Here [%s] we finished waiting\n", exten);
peer = do_valetunpark(chan, exten, lotname);
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 1 %s\n", exten);
if (peer) {
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 2 %s\n", exten);
ast_moh_stop(peer);
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 3 %s\n", exten);
res = ast_channel_make_compatible(chan, peer);
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 4 %s\n", exten);
if (res < 0) {
ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
ast_hangup(peer);
LOCAL_USER_REMOVE(u);
return -1;
}
/* This runs sorta backwards, since we give the incoming channel control, as if it
were the person called. */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to Valet Parked call %d in lot %s\n", chan->name, valetpark,lotname);
memset(&config,0,sizeof(struct ast_bridge_config));
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 5 %s\n", exten);
/* DIABLE BOTH TRANSFER METHODS */
config.allowredirect_in = config.allowredirect_out = 0;
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 6 %s\n", exten);
res = ast_bridge_call(chan,peer,&config);
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 7 %s\n", exten);
if (res != AST_PBX_NO_HANGUP_PEER)
ast_hangup(peer);
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 8 %s\n", exten);
LOCAL_USER_REMOVE(u);
ast_verbose(VERBOSE_PREFIX_3 "Debug Step 9 %s\n", exten);
return res;
} else {
/* XXX Play a message XXX */
dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
if (!dres) {
dres = ast_waitstream(chan, "");
} else {
ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
res = 0;
}
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant Valet Parked call %d\n", chan->name, valetpark);
res = -1;
}
}
else
{
/* XXX Play a message XXX */
dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
if (!dres) {
dres = ast_waitstream(chan, "");
} else {
ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
res = 0;
}
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant Valet Parked call %d\n", chan->name, valetpark);
res = -1;
}
LOCAL_USER_REMOVE(u);
return res;
}