From 8d2a71877a184a70f8be64afe3500ea27a215e71 Mon Sep 17 00:00:00 2001
From: Terry Wilson <twilson@digium.com>
Date: Tue, 26 Apr 2011 22:26:37 +0000
Subject: [PATCH] Merged revisions 315644 via svnmerge from
 https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r315644 | twilson | 2011-04-26 14:39:01 -0700 (Tue, 26 Apr 2011) | 32 lines

  Merged revisions 315643 via svnmerge from
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2

  ................
    r315643 | twilson | 2011-04-26 14:27:44 -0700 (Tue, 26 Apr 2011) | 25 lines

    Merged revisions 315596 via svnmerge from
    https://origsvn.digium.com/svn/asterisk/branches/1.4

    ........
      r315596 | twilson | 2011-04-26 14:16:10 -0700 (Tue, 26 Apr 2011) | 18 lines

      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/trunk@315670 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/app_dial.c  |  8 --------
 apps/app_queue.c | 11 -----------
 main/features.c  | 23 +++++++++++++++++++++++
 3 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/apps/app_dial.c b/apps/app_dial.c
index d76a0cf6aa..b43674088a 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -2395,14 +2395,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
 	peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result,
 		dtmf_progress, ignore_cc, &forced_clid, &stored_clid);
 
-	/* 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_datastore_free(datastore);
 	if (!peer) {
 		if (result) {
 			res = result;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 5c348b7523..465356e610 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -4567,17 +4567,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
 	if (need_weight)
 		ao2_unlock(queues);
 	lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
-	/* 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_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_rr(qe, outgoing);
diff --git a/main/features.c b/main/features.c
index cf08c68aba..f779623475 100644
--- a/main/features.c
+++ b/main/features.c
@@ -3416,6 +3416,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_datastore_free(di_datastore);
+		}
+	}
+	ast_channel_unlock(chan);
+}
+
 /*!
  * \brief bridge the call and set CDR
  * \param chan,peer,config
@@ -3601,6 +3617,13 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
 		ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
 	}
 	ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL);
+
+	/* 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 */
 	
-- 
GitLab