From: Terry Wilson Date: Tue, 26 Apr 2011 21:16:10 +0000 (+0000) Subject: Allow transfer loops without allowing forwarding loops X-Git-Tag: 1.4.42-rc1~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77acf5b626f624d949e1b49cdb9ae5d3969c021f;p=thirdparty%2Fasterisk.git Allow transfer loops without allowing forwarding loops We try to avoid the situation where two phones may be forwarded to each other causing an infinite loop by storing each dialed interface in a channel datastore and checking the list before dialing out. This works, but currently breaks situations like A calls B, A transfers B to C, B transfers C to A, and A transfers C to B. Since human interaction is happening here and not an automated forwarding loop, it should be allowed. This patch removes the dialed_interfaces datastore when a call is bridged (a suggestion from the brilliant mmichelson). If a call is being bridged, it should be safe to assume that we aren't stuck in a loop. Since we are now handling this is the bridge code, the previous attempts at handling it in app_dial and app_queue are removed. Review: https://reviewboard.asterisk.org/r/1195/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@315596 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/apps/app_dial.c b/apps/app_dial.c index 3f0c67082a..fec1c9b729 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1453,14 +1453,6 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags time(&start_time); peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result); - /* The ast_channel_datastore_remove() function could fail here if the - * datastore was moved to another channel during a masquerade. If this is - * the case, don't free the datastore here because later, when the channel - * to which the datastore was moved hangs up, it will attempt to free this - * datastore again, causing a crash - */ - if (!ast_channel_datastore_remove(chan, datastore)) - ast_channel_datastore_free(datastore); if (!peer) { if (result) { res = result; diff --git a/apps/app_queue.c b/apps/app_queue.c index 7f34d1fc30..a2447d43eb 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -3047,17 +3047,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce if (need_weight) AST_LIST_UNLOCK(&queues); lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); - /* The ast_channel_datastore_remove() function could fail here if the - * datastore was moved to another channel during a masquerade. If this is - * the case, don't free the datastore here because later, when the channel - * to which the datastore was moved hangs up, it will attempt to free this - * datastore again, causing a crash - */ - ast_channel_lock(qe->chan); - if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { - ast_channel_datastore_free(datastore); - } - ast_channel_unlock(qe->chan); ao2_lock(qe->parent); if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { store_next(qe, outgoing); diff --git a/res/res_features.c b/res/res_features.c index 63aafa5712..66106e851d 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -2092,6 +2092,22 @@ static void add_features_datastores(struct ast_channel *caller, struct ast_chann return; } +static void clear_dialed_interfaces(struct ast_channel *chan) +{ + struct ast_datastore *di_datastore; + + ast_channel_lock(chan); + if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) { + if (option_debug) { + ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", chan->name); + } + if (!ast_channel_datastore_remove(chan, di_datastore)) { + ast_channel_datastore_free(di_datastore); + } + } + ast_channel_unlock(chan); +} + int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config) { /* Copy voice back and forth between the two channels. Give the peer @@ -2249,6 +2265,12 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED); } + /* If we are bridging a call, stop worrying about forwarding loops. We presume that if + * a call is being bridged, that the humans in charge know what they're doing. If they + * don't, well, what can we do about that? */ + clear_dialed_interfaces(chan); + clear_dialed_interfaces(peer); + for (;;) { struct ast_channel *other; /* used later */