From 06f4f80a63092845a3e86fc827b025854beaf4b4 Mon Sep 17 00:00:00 2001 From: Richard Mudgett <rmudgett@digium.com> Date: Tue, 22 Sep 2015 17:08:49 -0500 Subject: [PATCH] app_page.c: Fix crash when forwarding with a predial handler. Page uses the async method of dialing with the dial API. When a call gets forwarded there is no calling channel available. If the predial handler was set then the calling channel could not be put into auto-service for the forwarded call because it doesn't exist. A crash is the result. * Moved the callee predial parameter string processing to before the string is passed to the dial API rather than having the dial API do it. There are a few benefits do doing this. The first is the predial parameter string processing doesn't need to be done for each channel called by the dial API. The second is in async mode and the forwarded channel is to have the predial handler executed on it then the non-existent calling channel does not need to be present to process the predial parameter string. * Don't start auto-service on a non-existent calling channel to execute the predial handler when the dial API is in async mode and forwarding a call. ASTERISK-25384 #close Reported by: Chet Stevens Change-Id: If53892b286d29f6cf955e2545b03dcffa2610981 --- apps/app_page.c | 28 ++++++++++++++++++++++------ main/dial.c | 25 ++++++------------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/apps/app_page.c b/apps/app_page.c index cea75cb5e4..10a96b61be 100644 --- a/apps/app_page.c +++ b/apps/app_page.c @@ -249,12 +249,18 @@ static void page_state_callback(struct ast_dial *dial) static int page_exec(struct ast_channel *chan, const char *data) { - char *tech, *resource, *tmp; - char confbridgeopts[128], originator[AST_CHANNEL_NAME]; + char *tech; + char *resource; + char *tmp; + char *predial_callee = NULL; + char confbridgeopts[128]; + char originator[AST_CHANNEL_NAME]; struct page_options options = { { 0, }, { 0, } }; unsigned int confid = ast_random(); struct ast_app *app; - int res = 0, pos = 0, i = 0; + int res = 0; + int pos = 0; + int i = 0; struct ast_dial **dial_list; unsigned int num_dials; int timeout = 0; @@ -310,6 +316,15 @@ static int page_exec(struct ast_channel *chan, const char *data) return -1; } + /* PREDIAL: Preprocess any callee gosub arguments. */ + if (ast_test_flag(&options.flags, PAGE_PREDIAL_CALLEE) + && !ast_strlen_zero(options.opts[OPT_ARG_PREDIAL_CALLEE])) { + ast_replace_subargument_delimiter(options.opts[OPT_ARG_PREDIAL_CALLEE]); + predial_callee = + (char *) ast_app_expand_sub_args(chan, options.opts[OPT_ARG_PREDIAL_CALLEE]); + } + + /* PREDIAL: Run gosub on the caller's channel */ if (ast_test_flag(&options.flags, PAGE_PREDIAL_CALLER) && !ast_strlen_zero(options.opts[OPT_ARG_PREDIAL_CALLER])) { ast_replace_subargument_delimiter(options.opts[OPT_ARG_PREDIAL_CALLER]); @@ -360,9 +375,8 @@ static int page_exec(struct ast_channel *chan, const char *data) /* Set ANSWER_EXEC as global option */ ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, confbridgeopts); - if (ast_test_flag(&options.flags, PAGE_PREDIAL_CALLEE) - && !ast_strlen_zero(options.opts[OPT_ARG_PREDIAL_CALLEE])) { - ast_dial_option_global_enable(dial, AST_DIAL_OPTION_PREDIAL, options.opts[OPT_ARG_PREDIAL_CALLEE]); + if (predial_callee) { + ast_dial_option_global_enable(dial, AST_DIAL_OPTION_PREDIAL, predial_callee); } if (timeout) { @@ -383,6 +397,8 @@ static int page_exec(struct ast_channel *chan, const char *data) dial_list[pos++] = dial; } + ast_free(predial_callee); + if (!ast_test_flag(&options.flags, PAGE_QUIET)) { res = ast_streamfile(chan, "beep", ast_channel_language(chan)); if (!res) diff --git a/main/dial.c b/main/dial.c index b935b6d8b6..34d2f70551 100644 --- a/main/dial.c +++ b/main/dial.c @@ -378,14 +378,13 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe ast_channel_unlock(channel->owner); if (!ast_strlen_zero(predial_string)) { - const char *predial_callee = ast_app_expand_sub_args(chan, predial_string); - if (!predial_callee) { - ast_log(LOG_ERROR, "Could not expand subroutine arguments in predial request '%s'\n", predial_string); + if (chan) { + ast_autoservice_start(chan); + } + ast_pre_call(channel->owner, predial_string); + if (chan) { + ast_autoservice_stop(chan); } - ast_autoservice_start(chan); - ast_pre_call(channel->owner, predial_callee); - ast_autoservice_stop(chan); - ast_free((char *) predial_callee); } return 0; @@ -397,10 +396,6 @@ int ast_dial_prerun(struct ast_dial *dial, struct ast_channel *chan, struct ast_ int res = -1; char *predial_string = dial->options[AST_DIAL_OPTION_PREDIAL]; - if (!ast_strlen_zero(predial_string)) { - ast_replace_subargument_delimiter(predial_string); - } - AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if ((res = begin_dial_prerun(channel, chan, cap, predial_string))) { @@ -450,10 +445,6 @@ static int begin_dial(struct ast_dial *dial, struct ast_channel *chan, int async int success = 0; char *predial_string = dial->options[AST_DIAL_OPTION_PREDIAL]; - if (!ast_strlen_zero(predial_string)) { - ast_replace_subargument_delimiter(predial_string); - } - /* Iterate through channel list, requesting and calling each one */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { @@ -473,10 +464,6 @@ static int handle_call_forward(struct ast_dial *dial, struct ast_dial_channel *c char *tech = "Local", *device = tmp, *stuff; char *predial_string = dial->options[AST_DIAL_OPTION_PREDIAL]; - if (!ast_strlen_zero(predial_string)) { - ast_replace_subargument_delimiter(predial_string); - } - /* If call forwarding is disabled just drop the original channel and don't attempt to dial the new one */ if (FIND_RELATIVE_OPTION(dial, channel, AST_DIAL_OPTION_DISABLE_CALL_FORWARDING)) { ast_hangup(original); -- GitLab