aboutsummaryrefslogtreecommitdiffstats
path: root/main/pbx.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2011-07-06 04:52:35 +0200
committerPatrick McHardy <kaber@trash.net>2011-07-06 04:52:35 +0200
commit916e420bf0c8db7a8cb1f60557cd2807652142cf (patch)
treeece8aaf3f22e6e1cc545a858cad9e05c34713426 /main/pbx.c
parent9364aaccb699c6d19ac2cbe760c208b34ba7838a (diff)
parent357b97fb29d196a5f336d6a2879278ea135ab08c (diff)
Merge branch 'master' of 192.168.0.100:/repos/git/asterisk
Diffstat (limited to 'main/pbx.c')
-rw-r--r--main/pbx.c111
1 files changed, 69 insertions, 42 deletions
diff --git a/main/pbx.c b/main/pbx.c
index b9c853505..821fdbfad 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -252,7 +252,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>If the location that is put into the channel information is bogus, and asterisk cannot
find that location in the dialplan, then the execution engine will try to find and execute the code in
the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
- <literal>h</literal> extension. If either or neither the <literal>h</literal> or <literal>i</literal> extensions
+ <literal>h</literal> extension. If neither the <literal>h</literal> nor <literal>i</literal> extensions
have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
What this means is that, for example, you specify a context that does not exist, then
it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
@@ -289,7 +289,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
next instruction. If the target location is bogus, and does not exist, the execution engine will try
to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
If that does not exist, it will try to execute the <literal>h</literal> extension.
- If either or neither the <literal>h</literal> or <literal>i</literal> extensions have been defined,
+ If neither the <literal>h</literal> nor <literal>i</literal> extensions have been defined,
the channel is hung up, and the execution of instructions on the channel is terminated.
Remember that this command can set the current context, and if the context specified
does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
@@ -7949,55 +7949,82 @@ int ast_explicit_goto(struct ast_channel *chan, const char *context, const char
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
{
int res = 0;
+ struct ast_channel *tmpchan;
+ struct {
+ char *accountcode;
+ char *exten;
+ char *context;
+ char *linkedid;
+ char *name;
+ struct ast_cdr *cdr;
+ int amaflags;
+ int state;
+ struct ast_format readformat;
+ struct ast_format writeformat;
+ } tmpvars = { 0, };
ast_channel_lock(chan);
-
if (chan->pbx) { /* This channel is currently in the PBX */
ast_explicit_goto(chan, context, exten, priority + 1);
ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
+ ast_channel_unlock(chan);
+ return res;
+ }
+
+ /* In order to do it when the channel doesn't really exist within
+ * the PBX, we have to make a new channel, masquerade, and start the PBX
+ * at the new location */
+ tmpvars.accountcode = ast_strdupa(chan->accountcode);
+ tmpvars.exten = ast_strdupa(chan->exten);
+ tmpvars.context = ast_strdupa(chan->context);
+ tmpvars.linkedid = ast_strdupa(chan->linkedid);
+ tmpvars.name = ast_strdupa(chan->name);
+ tmpvars.amaflags = chan->amaflags;
+ tmpvars.state = chan->_state;
+ ast_format_copy(&tmpvars.writeformat, &chan->writeformat);
+ ast_format_copy(&tmpvars.readformat, &chan->readformat);
+ tmpvars.cdr = chan->cdr ? ast_cdr_dup(chan->cdr) : NULL;
+
+ ast_channel_unlock(chan);
+
+ /* Do not hold any channel locks while calling channel_alloc() since the function
+ * locks the channel container when linking the new channel in. */
+ if (!(tmpchan = ast_channel_alloc(0, tmpvars.state, 0, 0, tmpvars.accountcode, tmpvars.exten, tmpvars.context, tmpvars.linkedid, tmpvars.amaflags, "AsyncGoto/%s", tmpvars.name))) {
+ ast_cdr_discard(tmpvars.cdr);
+ return -1;
+ }
+
+ /* copy the cdr info over */
+ if (tmpvars.cdr) {
+ ast_cdr_discard(tmpchan->cdr);
+ tmpchan->cdr = tmpvars.cdr;
+ tmpvars.cdr = NULL;
+ }
+
+ /* Make formats okay */
+ ast_format_copy(&tmpchan->readformat, &tmpvars.readformat);
+ ast_format_copy(&tmpchan->writeformat, &tmpvars.writeformat);
+
+ /* Setup proper location. Never hold another channel lock while calling this function. */
+ ast_explicit_goto(tmpchan, S_OR(context, tmpvars.context), S_OR(exten, tmpvars.exten), priority);
+
+ /* Masquerade into tmp channel */
+ if (ast_channel_masquerade(tmpchan, chan)) {
+ /* Failed to set up the masquerade. It's probably chan_local
+ * in the middle of optimizing itself out. Sad. :( */
+ ast_hangup(tmpchan);
+ tmpchan = NULL;
+ res = -1;
} else {
- /* In order to do it when the channel doesn't really exist within
- the PBX, we have to make a new channel, masquerade, and start the PBX
- at the new location */
- struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->linkedid, chan->amaflags, "AsyncGoto/%s", chan->name);
- if (!tmpchan) {
+ ast_do_masquerade(tmpchan);
+ /* Start the PBX going on our stolen channel */
+ if (ast_pbx_start(tmpchan)) {
+ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
+ ast_hangup(tmpchan);
res = -1;
- } else {
- if (chan->cdr) {
- ast_cdr_discard(tmpchan->cdr);
- tmpchan->cdr = ast_cdr_dup(chan->cdr); /* share the love */
- }
- /* Make formats okay */
- tmpchan->readformat = chan->readformat;
- tmpchan->writeformat = chan->writeformat;
- /* Setup proper location */
- ast_explicit_goto(tmpchan,
- S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
-
- /* Masquerade into temp channel */
- if (ast_channel_masquerade(tmpchan, chan)) {
- /* Failed to set up the masquerade. It's probably chan_local
- * in the middle of optimizing itself out. Sad. :( */
- ast_hangup(tmpchan);
- tmpchan = NULL;
- res = -1;
- } else {
- /* it may appear odd to unlock chan here since the masquerade is on
- * tmpchan, but no channel locks should be held when doing a masquerade
- * since a masquerade requires a lock on the channels ao2 container. */
- ast_channel_unlock(chan);
- ast_do_masquerade(tmpchan);
- ast_channel_lock(chan);
- /* Start the PBX going on our stolen channel */
- if (ast_pbx_start(tmpchan)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
- ast_hangup(tmpchan);
- res = -1;
- }
- }
}
}
- ast_channel_unlock(chan);
+
return res;
}