From: Naveen Albert Date: Sat, 1 Oct 2022 19:49:20 +0000 (+0000) Subject: app_stack: Print proper exit location for PBXless channels. X-Git-Tag: 20.1.0-rc1~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dfe2f38642099a8797037964c7dff7e15abdff56;p=thirdparty%2Fasterisk.git app_stack: Print proper exit location for PBXless channels. When gosub is executed on channels without a PBX, the context, extension, and priority are initialized to the channel driver's default location for that endpoint. As a result, the last Return will restore this location and the Gosub logs will print out bogus information about our exit point. To fix this, on channels that don't have a PBX, the execution location is left intact on the last return if there are no further stack frames left. This allows the correct location to be printed out to the user, rather than the bogus default context. ASTERISK-30076 #close Change-Id: I1d42a99c9aa9e3708d32718863175158a894e414 --- diff --git a/apps/app_stack.c b/apps/app_stack.c index a84a45c1b4..70aff6fced 100644 --- a/apps/app_stack.c +++ b/apps/app_stack.c @@ -377,6 +377,26 @@ static int pop_exec(struct ast_channel *chan, const char *data) return res; } +static int frames_left(struct ast_channel *chan) +{ + struct ast_datastore *stack_store; + struct gosub_stack_list *oldlist; + int exists; + + ast_channel_lock(chan); + stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); + if (!stack_store) { + ast_channel_unlock(chan); + return -1; + } + oldlist = stack_store->data; + AST_LIST_LOCK(oldlist); + exists = oldlist->first ? 1 : 0; + AST_LIST_UNLOCK(oldlist); + ast_channel_unlock(chan); + return exists; +} + static int return_exec(struct ast_channel *chan, const char *data) { struct ast_datastore *stack_store; @@ -384,6 +404,7 @@ static int return_exec(struct ast_channel *chan, const char *data) struct gosub_stack_list *oldlist; const char *retval = data; int res = 0; + int lastframe; ast_channel_lock(chan); if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { @@ -395,6 +416,7 @@ static int return_exec(struct ast_channel *chan, const char *data) oldlist = stack_store->data; AST_LIST_LOCK(oldlist); oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); + lastframe = oldlist->first ? 0 : 1; AST_LIST_UNLOCK(oldlist); if (!oldframe) { @@ -412,12 +434,19 @@ static int return_exec(struct ast_channel *chan, const char *data) * what was there before. Channels that do not have a PBX may * not have the context or exten set. */ - ast_channel_context_set(chan, oldframe->context); - ast_channel_exten_set(chan, oldframe->extension); - if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) { - --oldframe->priority; + if (ast_channel_pbx(chan) || !lastframe) { + /* If there's no PBX, the "old location" is simply + * the configured context for the device, such as + * for pre-dial handlers, and restoring this location + * is nonsensical. So if no PBX and there are no further + * frames, leave the location as it is. */ + ast_channel_context_set(chan, oldframe->context); + ast_channel_exten_set(chan, oldframe->extension); + if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) { + --oldframe->priority; + } + ast_channel_priority_set(chan, oldframe->priority); } - ast_channel_priority_set(chan, oldframe->priority); ast_set2_flag(ast_channel_flags(chan), oldframe->in_subroutine, AST_FLAG_SUBROUTINE_EXEC); gosub_release_frame(chan, oldframe); @@ -1068,10 +1097,13 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_ ast_channel_priority(chan), ast_channel_name(chan)); } - /* Did the routine return? */ - if (ast_channel_priority(chan) == saved_priority + /* Did the routine return? + * For things like predial where there's no PBX on the channel yet, + * the last return leaves the location alone so we can print it out correctly here. + * So to ensure we finished properly, make sure there are no frames left in that case. */ + if ((!ast_channel_pbx(chan) && !frames_left(chan)) || (ast_channel_priority(chan) == saved_priority && !strcmp(ast_channel_context(chan), saved_context) - && !strcmp(ast_channel_exten(chan), saved_exten)) { + && !strcmp(ast_channel_exten(chan), saved_exten))) { ast_verb(3, "%s Internal %s(%s) complete GOSUB_RETVAL=%s\n", ast_channel_name(chan), app_gosub, sub_args, S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));