From be74e6f16ec133cad88776ee107125aee42ad58f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 16 Dec 2011 23:58:44 +0000 Subject: Clean-up on isle five for __ast_request_and_dial() and ast_call_forward(). * Add locking when a channel inherits variables and datastores in __ast_request_and_dial() and ast_call_forward(). Note: The involved channels are not active so there was minimal potential for problems. * Remove calls to ast_set_callerid() in __ast_request_and_dial() and ast_call_forward() because the set information is for the wrong direction. * Don't use C++ keywords for variable names in ast_call_forward(). * Run the redirecting interception macro if defined when forwarding a call in ast_call_forward(). Note: Currently will never execute because the only callers that supply a calling channel supply a hungup or zombie channel. * Make feature_request_and_dial() put the transferee into autoservice when it calls ast_call_forward() in case a redirection interception macro is run. Note: Currently will never happen because the caller channel (Party B) is always hungup at this time. * Make feature_request_and_dial() ignore the AST_CONTROL_PROCEEDING frame to silence a log message. ........ Merged revisions 348464 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 348465 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@348466 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/channel.c | 103 +++++++++++++++++++++++++++++++++++++------------------- main/features.c | 6 +++- 2 files changed, 73 insertions(+), 36 deletions(-) (limited to 'main') diff --git a/main/channel.c b/main/channel.c index 54a102d22..017fba98d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5389,11 +5389,47 @@ static void handle_cause(int cause, int *outstate) } } +/*! + * \internal + * \brief Helper function to inherit info from parent channel. + * + * \param new_chan Channel inheriting information. + * \param parent Channel new_chan inherits information. + * \param orig Channel being replaced by the call forward channel. + * + * \return Nothing + */ +static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channel *parent, struct ast_channel *orig) +{ + if (!ast_test_flag(parent, AST_FLAG_ZOMBIE) && !ast_check_hangup(parent)) { + struct ast_party_redirecting redirecting; + + /* + * The parent is not a ZOMBIE or hungup so update it with the + * original channel's redirecting information. + */ + ast_party_redirecting_init(&redirecting); + ast_channel_lock(orig); + ast_party_redirecting_copy(&redirecting, &orig->redirecting); + ast_channel_unlock(orig); + if (ast_channel_redirecting_macro(orig, parent, &redirecting, 1, 0)) { + ast_channel_update_redirecting(parent, &redirecting, NULL); + } + ast_party_redirecting_free(&redirecting); + } + + /* Safely inherit variables and datastores from the parent channel. */ + ast_channel_lock_both(parent, new_chan); + ast_channel_inherit_variables(parent, new_chan); + ast_channel_datastore_inherit(parent, new_chan); + ast_channel_unlock(new_chan); + ast_channel_unlock(parent); +} + struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, struct ast_format_cap *cap, struct outgoing_helper *oh, int *outstate) { char tmpchan[256]; - struct ast_channel *new = NULL; - struct ast_party_redirecting *apr = &orig->redirecting; + struct ast_channel *new_chan = NULL; char *data, *type; int cause = 0; int res; @@ -5412,64 +5448,52 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan data = tmpchan; type = "Local"; } - if (!(new = ast_request(type, cap, orig, data, &cause))) { + if (!(new_chan = ast_request(type, cap, orig, data, &cause))) { ast_log(LOG_NOTICE, "Unable to create channel for call forward to '%s/%s' (cause = %d)\n", type, data, cause); handle_cause(cause, outstate); ast_hangup(orig); return NULL; } - ast_channel_set_redirecting(new, apr, NULL); - /* Copy/inherit important information into new channel */ if (oh) { if (oh->vars) { - ast_set_variables(new, oh->vars); - } - if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) { - ast_set_callerid(new, oh->cid_num, oh->cid_name, oh->cid_num); + ast_set_variables(new_chan, oh->vars); } if (oh->parent_channel) { - ast_channel_update_redirecting(oh->parent_channel, apr, NULL); - ast_channel_inherit_variables(oh->parent_channel, new); - ast_channel_datastore_inherit(oh->parent_channel, new); + call_forward_inherit(new_chan, oh->parent_channel, orig); } if (oh->account) { - ast_channel_lock(new); - ast_cdr_setaccount(new, oh->account); - ast_channel_unlock(new); + ast_channel_lock(new_chan); + ast_cdr_setaccount(new_chan, oh->account); + ast_channel_unlock(new_chan); } } else if (caller) { /* no outgoing helper so use caller if avaliable */ - ast_channel_update_redirecting(caller, apr, NULL); - ast_channel_inherit_variables(caller, new); - ast_channel_datastore_inherit(caller, new); + call_forward_inherit(new_chan, caller, orig); } - ast_channel_lock(orig); - while (ast_channel_trylock(new)) { - CHANNEL_DEADLOCK_AVOIDANCE(orig); - } - ast_copy_flags(new->cdr, orig->cdr, AST_CDR_FLAG_ORIGINATED); - ast_string_field_set(new, accountcode, orig->accountcode); - ast_party_caller_copy(&new->caller, &orig->caller); - ast_party_connected_line_copy(&new->connected, &orig->connected); - ast_channel_unlock(new); + ast_channel_lock_both(orig, new_chan); + ast_copy_flags(new_chan->cdr, orig->cdr, AST_CDR_FLAG_ORIGINATED); + ast_string_field_set(new_chan, accountcode, orig->accountcode); + ast_party_connected_line_copy(&new_chan->connected, &orig->connected); + ast_party_redirecting_copy(&new_chan->redirecting, &orig->redirecting); + ast_channel_unlock(new_chan); ast_channel_unlock(orig); /* call new channel */ - res = ast_call(new, data, 0); + res = ast_call(new_chan, data, 0); if (timeout) { *timeout = res; } if (res) { ast_log(LOG_NOTICE, "Unable to call forward to channel %s/%s\n", type, (char *)data); ast_hangup(orig); - ast_hangup(new); + ast_hangup(new_chan); return NULL; } ast_hangup(orig); - return new; + return new_chan; } struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh) @@ -5494,14 +5518,24 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c } if (oh) { - if (oh->vars) + if (oh->vars) { ast_set_variables(chan, oh->vars); - /* XXX why is this necessary, for the parent_channel perhaps ? */ - if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) - ast_set_callerid(chan, oh->cid_num, oh->cid_name, oh->cid_num); + } + if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) { + /* + * Use the oh values instead of the function parameters for the + * outgoing CallerID. + */ + cid_num = oh->cid_num; + cid_name = oh->cid_name; + } if (oh->parent_channel) { + /* Safely inherit variables and datastores from the parent channel. */ + ast_channel_lock_both(oh->parent_channel, chan); ast_channel_inherit_variables(oh->parent_channel, chan); ast_channel_datastore_inherit(oh->parent_channel, chan); + ast_channel_unlock(oh->parent_channel); + ast_channel_unlock(chan); } if (oh->account) { ast_channel_lock(chan); @@ -5510,7 +5544,6 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c } } - ast_set_callerid(chan, cid_num, cid_name, cid_num); ast_set_flag(chan->cdr, AST_CDR_FLAG_ORIGINATED); ast_party_connected_line_set_init(&connected, &chan->connected); if (cid_num) { diff --git a/main/features.c b/main/features.c index bb925f73d..ca6286bdc 100644 --- a/main/features.c +++ b/main/features.c @@ -3538,7 +3538,9 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, } else if (chan == active_channel) { if (!ast_strlen_zero(chan->call_forward)) { state = 0; + ast_autoservice_start(transferee); chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state); + ast_autoservice_stop(transferee); if (!chan) { break; } @@ -3613,7 +3615,9 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, } ast_autoservice_stop(transferee); } - } else if (f->subclass.integer != -1 && f->subclass.integer != AST_CONTROL_PROGRESS) { + } else if (f->subclass.integer != -1 + && f->subclass.integer != AST_CONTROL_PROGRESS + && f->subclass.integer != AST_CONTROL_PROCEEDING) { ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); } /* else who cares */ -- cgit v1.2.3