[asterisk-commits] rmudgett: branch rmudgett/bridge_tasks r383515 - in /team/rmudgett/bridge_tas...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Mar 21 11:10:43 CDT 2013


Author: rmudgett
Date: Thu Mar 21 11:10:39 2013
New Revision: 383515

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383515
Log:
* Make DTMF, hangup, and interval hooks ao2 objects.

* Protect interval hooks from other threads adding/removing interval
hooks.

* Made callers of ast_bridge_features_init() check its return value.

Modified:
    team/rmudgett/bridge_tasks/apps/app_bridgewait.c
    team/rmudgett/bridge_tasks/apps/app_confbridge.c
    team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c
    team/rmudgett/bridge_tasks/bridges/bridge_builtin_interval_features.c
    team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
    team/rmudgett/bridge_tasks/main/bridging.c
    team/rmudgett/bridge_tasks/main/features.c

Modified: team/rmudgett/bridge_tasks/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/apps/app_bridgewait.c?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/apps/app_bridgewait.c (original)
+++ team/rmudgett/bridge_tasks/apps/app_bridgewait.c Thu Mar 21 11:10:39 2013
@@ -200,7 +200,6 @@
 			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM, NULL);
 	}
 	ast_mutex_unlock(&bridgewait_lock);
-
 	if (!holding_bridge) {
 		ast_log(LOG_ERROR, "Could not create holding bridge for '%s'.\n", ast_channel_name(chan));
 		return -1;
@@ -209,7 +208,10 @@
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	ast_bridge_features_init(&chan_features);
+	if (ast_bridge_features_init(&chan_features)) {
+		ast_bridge_features_cleanup(&chan_features);
+		return -1;
+	}
 
 	if (args.options) {
 		char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };

Modified: team/rmudgett/bridge_tasks/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/apps/app_confbridge.c?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/apps/app_confbridge.c (original)
+++ team/rmudgett/bridge_tasks/apps/app_confbridge.c Thu Mar 21 11:10:39 2013
@@ -1644,10 +1644,14 @@
 		AST_APP_ARG(u_profile_name);
 		AST_APP_ARG(menu_name);
 	);
-	ast_bridge_features_init(&user.features);
 
 	if (ast_channel_state(chan) != AST_STATE_UP) {
 		ast_answer(chan);
+	}
+
+	if (ast_bridge_features_init(&user.features)) {
+		res = -1;
+		goto confbridge_cleanup;
 	}
 
 	if (ast_strlen_zero(data)) {

Modified: team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c (original)
+++ team/rmudgett/bridge_tasks/bridges/bridge_builtin_features.c Thu Mar 21 11:10:39 2013
@@ -269,16 +269,41 @@
 	/* Get a channel that is the destination we wish to call */
 	peer = dial_transfer(bridge_channel->chan, exten, context);
 	if (!peer) {
+/* BUGBUG beeperr needs to be configurable from features.conf */
 		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
 		return 0;
 	}
 
-/* BUGBUG we need to wait for Party C (peer) to answer before dumping into the transient B-C bridge. */
+/* BUGBUG bridging API features does not support features.conf featuremap */
+/* BUGBUG bridging API features does not support the features.conf atxfer bounce between C & B channels */
+	/* Setup a DTMF menu to control the transfer. */
+	if (ast_bridge_features_init(&caller_features)
+		|| ast_bridge_hangup_hook(&caller_features,
+			attended_transfer_complete, &transfer_code, NULL)
+		|| ast_bridge_dtmf_hook(&caller_features,
+			attended_transfer && !ast_strlen_zero(attended_transfer->abort)
+				? attended_transfer->abort : "*1",
+			attended_transfer_abort, &transfer_code, NULL)
+		|| ast_bridge_dtmf_hook(&caller_features,
+			attended_transfer && !ast_strlen_zero(attended_transfer->complete)
+				? attended_transfer->complete : "*2",
+			attended_transfer_complete, &transfer_code, NULL)
+		|| ast_bridge_dtmf_hook(&caller_features,
+			attended_transfer && !ast_strlen_zero(attended_transfer->threeway)
+				? attended_transfer->threeway : "*3",
+			attended_transfer_threeway, &transfer_code, NULL)) {
+		ast_bridge_features_cleanup(&caller_features);
+		ast_hangup(peer);
+/* BUGBUG beeperr needs to be configurable from features.conf */
+		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
+		return 0;
+	}
 
 	/* Create a bridge to use to talk to the person we are calling */
 	attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX,
 		AST_BRIDGE_FLAG_DISSOLVE_HANGUP, NULL);
 	if (!attended_bridge) {
+		ast_bridge_features_cleanup(&caller_features);
 		ast_hangup(peer);
 /* BUGBUG beeperr needs to be configurable from features.conf */
 		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
@@ -289,29 +314,12 @@
 /* BUGBUG we should impart the peer as an independent and move it to the original bridge. */
 	if (ast_bridge_impart(attended_bridge, peer, NULL, NULL, 0)) {
 		ast_bridge_destroy(attended_bridge);
+		ast_bridge_features_cleanup(&caller_features);
 		ast_hangup(peer);
+/* BUGBUG beeperr needs to be configurable from features.conf */
 		ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_NONE);
 		return 0;
 	}
-
-	/* Setup a DTMF menu to control the transfer. */
-	ast_bridge_features_init(&caller_features);
-/* BUGBUG bridging API features does not support features.conf featuremap */
-/* BUGBUG bridging API features does not support the features.conf atxfer bounce between C & B channels */
-	ast_bridge_hangup_hook(&caller_features,
-		attended_transfer_complete, &transfer_code, NULL);
-	ast_bridge_dtmf_hook(&caller_features,
-		attended_transfer && !ast_strlen_zero(attended_transfer->abort)
-			? attended_transfer->abort : "*1",
-		attended_transfer_abort, &transfer_code, NULL);
-	ast_bridge_dtmf_hook(&caller_features,
-		attended_transfer && !ast_strlen_zero(attended_transfer->complete)
-			? attended_transfer->complete : "*2",
-		attended_transfer_complete, &transfer_code, NULL);
-	ast_bridge_dtmf_hook(&caller_features,
-		attended_transfer && !ast_strlen_zero(attended_transfer->threeway)
-			? attended_transfer->threeway : "*3",
-		attended_transfer_threeway, &transfer_code, NULL);
 
 	/*
 	 * For the caller we want to join the bridge in a blocking
@@ -329,8 +337,8 @@
 	}
 
 	/* Now that all channels are out of it we can destroy the bridge and the feature structures */
+	ast_bridge_destroy(attended_bridge);
 	ast_bridge_features_cleanup(&caller_features);
-	ast_bridge_destroy(attended_bridge);
 
 	xfer_failed = -1;
 	switch (transfer_code) {

Modified: team/rmudgett/bridge_tasks/bridges/bridge_builtin_interval_features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/bridges/bridge_builtin_interval_features.c?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/bridges/bridge_builtin_interval_features.c (original)
+++ team/rmudgett/bridge_tasks/bridges/bridge_builtin_interval_features.c Thu Mar 21 11:10:39 2013
@@ -125,11 +125,7 @@
 		limits_interval_playback(bridge, bridge_channel, limits, limits->warning_sound);
 	}
 
-	if (limits->frequency) {
-		ast_bridge_interval_hook_update(bridge_channel, limits->frequency);
-	}
-
-	return !limits->frequency ? -1 : 0;
+	return !limits->frequency ? -1 : limits->frequency;
 }
 
 static void copy_bridge_features_limits(struct ast_bridge_features_limits *dst, struct ast_bridge_features_limits *src)
@@ -169,6 +165,7 @@
 	copy_bridge_features_limits(feature_limits, limits);
 	features->limits = feature_limits;
 
+/* BUGBUG feature interval hooks need to be reimplemented to be more stand alone. */
 	if (ast_bridge_interval_hook(features, feature_limits->duration,
 		bridge_features_duration_callback, feature_limits, NULL)) {
 		ast_log(LOG_ERROR, "Failed to schedule the duration limiter to the bridge channel.\n");

Modified: team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h (original)
+++ team/rmudgett/bridge_tasks/include/asterisk/bridging_features.h Thu Mar 21 11:10:39 2013
@@ -106,6 +106,12 @@
  * \param bridge_channel Channel executing the feature
  * \param hook_pvt Private data passed in when the hook was created
  *
+ * For interval hooks:
+ * \retval 0 Setup to fire again at the last interval.
+ * \retval positive Setup to fire again at the new interval returned.
+ * \retval -1 Remove the callback hook.
+ *
+ * For other hooks:
  * \retval 0 Keep the callback hook.
  * \retval -1 Remove the callback hook.
  */
@@ -152,7 +158,7 @@
 	/*! Time at which the hook should actually trip */
 	struct timeval trip_time;
 	/*! Heap index for interval hook */
-	ssize_t __heap_index;
+	ssize_t heap_index;
 	/*! Interval that the hook should execute at in milliseconds */
 	unsigned int interval;
 	/*! Sequence number for the hook to ensure expiration ordering */
@@ -426,28 +432,6 @@
 	ast_bridge_hook_pvt_destructor destructor);
 
 /*!
- * \brief Update the interval on an interval hook that is currently executing a callback
- *
- * \param bridge_channel The bridge channel that is executing the callback
- * \param interval The new interval value or 0 to remove the interval hook
- *
- * \retval 0 on success
- * \retval 1 on failure
- *
- * Example usage:
- *
- * \code
- * ast_bridge_interval_hook_update(bridge_channel, 10000);
- * \endcode
- *
- * This updates the executing interval hook so that it will be triggered next in 10 seconds.
- *
- * \note This can only be called from the context of the interval hook callback itself. If this
- *       is called outside the callback then behavior is undefined.
- */
-int ast_bridge_interval_hook_update(struct ast_bridge_channel *bridge_channel, unsigned int interval);
-
-/*!
  * \brief Set a callback on the features structure to receive talking notifications on.
  *
  * \param features Bridge features structure

Modified: team/rmudgett/bridge_tasks/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/bridging.c?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/main/bridging.c (original)
+++ team/rmudgett/bridge_tasks/main/bridging.c Thu Mar 21 11:10:39 2013
@@ -574,10 +574,7 @@
 				ast_debug(1, "Hangup hook %p is being removed from bridge channel %p(%s)\n",
 					hook, bridge_channel, ast_channel_name(bridge_channel->chan));
 				AST_LIST_REMOVE_CURRENT(entry);
-				if (hook->destructor) {
-					hook->destructor(hook->hook_pvt);
-				}
-				ast_free(hook);
+				ao2_ref(hook, -1);
 			}
 		}
 		AST_LIST_TRAVERSE_SAFE_END;
@@ -591,18 +588,19 @@
 {
 	struct ast_bridge_features *features;
 	struct ast_bridge_hook *hook;
+	int ready;
 
 	features = bridge_channel->features;
 	if (!features || !features->interval_hooks) {
 		return 0;
 	}
 
+	ast_heap_wrlock(features->interval_hooks);
 	hook = ast_heap_peek(features->interval_hooks, 1);
-	if (!hook || ast_tvdiff_ms(hook->parms.timer.trip_time, ast_tvnow()) > 0) {
-		return 0;
-	}
-
-	return 1;
+	ready = hook && ast_tvdiff_ms(hook->parms.timer.trip_time, ast_tvnow()) <= 0;
+	ast_heap_unlock(features->interval_hooks);
+
+	return ready;
 }
 
 /*! \brief Internal function used to determine whether a control frame should be dropped or not */
@@ -1369,52 +1367,72 @@
 static void bridge_channel_interval(struct ast_bridge_channel *bridge_channel)
 {
 	struct ast_bridge_hook *hook;
-
+	struct timeval start;
+
+	ast_heap_wrlock(bridge_channel->features->interval_hooks);
+	start = ast_tvnow();
 	while ((hook = ast_heap_peek(bridge_channel->features->interval_hooks, 1))) {
-		int res;
-		struct timeval start = ast_tvnow();
-		int execution_time = 0;
+		int interval;
+		unsigned int execution_time;
 
 		if (ast_tvdiff_ms(hook->parms.timer.trip_time, start) > 0) {
 			ast_debug(1, "Hook %p on bridge channel %p(%s) wants to happen in the future, stopping our traversal\n",
 				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
 			break;
 		}
+		ao2_ref(hook, +1);
+		ast_heap_unlock(bridge_channel->features->interval_hooks);
 
 		ast_debug(1, "Executing hook %p on bridge channel %p(%s)\n",
 			hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-		res = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
-
-		/*
-		 * Must be popped after the callback.  The callback could call
-		 * ast_bridge_interval_hook_update().
-		 */
-		ast_heap_pop(bridge_channel->features->interval_hooks);
-
-		if (res || !hook->parms.timer.interval) {
-			ast_debug(1, "Interval hook %p is being removed from bridge channel %p(%s)\n",
+		interval = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
+
+		ast_heap_wrlock(bridge_channel->features->interval_hooks);
+		if (ast_heap_peek(bridge_channel->features->interval_hooks,
+			hook->parms.timer.heap_index) != hook
+			|| !ast_heap_remove(bridge_channel->features->interval_hooks, hook)) {
+			/* Interval hook is already removed from the bridge_channel. */
+			ao2_ref(hook, -1);
+			continue;
+		}
+		ao2_ref(hook, -1);
+
+		if (interval < 0) {
+			ast_debug(1, "Removed interval hook %p from bridge channel %p(%s)\n",
 				hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-			if (hook->destructor) {
-				hook->destructor(hook->hook_pvt);
-			}
-			ast_free(hook);
+			ao2_ref(hook, -1);
 			continue;
+		}
+		if (interval) {
+			/* Set new interval for the hook. */
+			hook->parms.timer.interval = interval;
 		}
 
 		ast_debug(1, "Updating interval hook %p with interval %u on bridge channel %p(%s)\n",
 			hook, hook->parms.timer.interval, bridge_channel,
 			ast_channel_name(bridge_channel->chan));
 
-		execution_time = ast_tvdiff_ms(ast_tvnow(), start);
-
 		/* resetting start */
 		start = ast_tvnow();
 
+		/*
+		 * Resetup the interval hook for the next interval.  We may need
+		 * to skip over any missed intervals because the hook was
+		 * delayed or took too long.
+		 */
+		execution_time = ast_tvdiff_ms(start, hook->parms.timer.trip_time);
+		while (hook->parms.timer.interval < execution_time) {
+			execution_time -= hook->parms.timer.interval;
+		}
 		hook->parms.timer.trip_time = ast_tvadd(start, ast_samp2tv(hook->parms.timer.interval - execution_time, 1000));
-
 		hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &bridge_channel->features->interval_sequence, +1);
-		ast_heap_push(bridge_channel->features->interval_hooks, hook);
-	}
+
+		if (ast_heap_push(bridge_channel->features->interval_hooks, hook)) {
+			/* Could not push the hook back onto the heap. */
+			ao2_ref(hook, -1);
+		}
+	}
+	ast_heap_unlock(bridge_channel->features->interval_hooks);
 }
 
 /*!
@@ -1504,10 +1522,7 @@
 					ast_debug(1, "DTMF hook %p is being removed from bridge channel %p(%s)\n",
 						hook, bridge_channel, ast_channel_name(bridge_channel->chan));
 					AST_LIST_REMOVE_CURRENT(entry);
-					if (hook->destructor) {
-						hook->destructor(hook->hook_pvt);
-					}
-					ast_free(hook);
+					ao2_ref(hook, -1);
 					break;
 				}
 			}
@@ -2610,6 +2625,52 @@
 
 }
 
+/*!
+ * \internal
+ * \brief Bridge hook destructor.
+ * \since 12.0.0
+ *
+ * \param vhook Object to destroy.
+ *
+ * \return Nothing
+ */
+static void bridge_hook_destroy(void *vhook)
+{
+	struct ast_bridge_hook *hook = vhook;
+
+	if (hook->destructor) {
+		hook->destructor(hook->hook_pvt);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Allocate and setup a generic bridge hook.
+ * \since 12.0.0
+ *
+ * \param size How big an object to allocate.
+ * \param callback Function to execute upon activation
+ * \param hook_pvt Unique data
+ * \param destructor Optional destructor callback for hook_pvt data
+ *
+ * \retval hook on success.
+ * \retval NULL on error.
+ */
+static struct ast_bridge_hook *bridge_hook_generic(size_t size, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor)
+{
+	struct ast_bridge_hook *hook;
+
+	/* Allocate new hook and setup it's basic variables */
+	hook = ao2_alloc_options(size, bridge_hook_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (hook) {
+		hook->callback = callback;
+		hook->destructor = destructor;
+		hook->hook_pvt = hook_pvt;
+	}
+
+	return hook;
+}
+
 int ast_bridge_dtmf_hook(struct ast_bridge_features *features,
 	const char *dtmf,
 	ast_bridge_hook_callback callback,
@@ -2618,15 +2679,12 @@
 {
 	struct ast_bridge_hook *hook;
 
-	/* Allocate new memory and setup it's various variables */
-	hook = ast_calloc(1, sizeof(*hook));
+	/* Allocate new hook and setup it's various variables */
+	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor);
 	if (!hook) {
 		return -1;
 	}
 	ast_copy_string(hook->parms.dtmf.code, dtmf, sizeof(hook->parms.dtmf.code));
-	hook->callback = callback;
-	hook->destructor = destructor;
-	hook->hook_pvt = hook_pvt;
 
 	/* Once done we add it onto the list. */
 	AST_LIST_INSERT_TAIL(&features->dtmf_hooks, hook, entry);
@@ -2641,14 +2699,11 @@
 {
 	struct ast_bridge_hook *hook;
 
-	/* Allocate new memory and setup it's various variables */
-	hook = ast_calloc(1, sizeof(*hook));
+	/* Allocate new hook and setup it's various variables */
+	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor);
 	if (!hook) {
 		return -1;
 	}
-	hook->callback = callback;
-	hook->destructor = destructor;
-	hook->hook_pvt = hook_pvt;
 
 	/* Once done we add it onto the list. */
 	AST_LIST_INSERT_TAIL(&features->hangup_hooks, hook, entry);
@@ -2672,49 +2727,36 @@
 	void *hook_pvt,
 	ast_bridge_hook_pvt_destructor destructor)
 {
-	struct ast_bridge_hook *hook = NULL;
-
-	if (!interval || !callback || !features || !features->interval_hooks
-		|| !(hook = ast_calloc(1, sizeof(*hook)))) {
+	struct ast_bridge_hook *hook;
+
+	if (!interval || !callback || !features || !features->interval_hooks) {
 		return -1;
 	}
 
 	if (!features->interval_timer) {
 		if (!(features->interval_timer = ast_timer_open())) {
 			ast_log(LOG_ERROR, "Failed to open a timer when adding a timed bridging feature.\n");
-			ast_free(hook);
 			return -1;
 		}
 		ast_timer_set_rate(features->interval_timer, BRIDGE_FEATURES_INTERVAL_RATE);
 	}
 
+	/* Allocate new hook and setup it's various variables */
+	hook = bridge_hook_generic(sizeof(*hook), callback, hook_pvt, destructor);
+	if (!hook) {
+		return -1;
+	}
 	hook->parms.timer.interval = interval;
-	hook->callback = callback;
-	hook->destructor = destructor;
-	hook->hook_pvt = hook_pvt;
+	hook->parms.timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->parms.timer.interval, 1000));
+	hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1);
 
 	ast_debug(1, "Putting interval hook %p with interval %u in the heap on features %p\n",
 		hook, hook->parms.timer.interval, features);
-	hook->parms.timer.trip_time = ast_tvadd(ast_tvnow(), ast_samp2tv(hook->parms.timer.interval, 1000));
-	hook->parms.timer.seqno = ast_atomic_fetchadd_int((int *) &features->interval_sequence, +1);
-	ast_heap_push(features->interval_hooks, hook);
-
-	return 0;
-}
-
-int ast_bridge_interval_hook_update(struct ast_bridge_channel *bridge_channel, unsigned int interval)
-{
-	struct ast_bridge_hook *hook;
-
-	if (!bridge_channel->features || !bridge_channel->features->interval_hooks) {
-		return -1;
-	}
-
-	hook = ast_heap_peek(bridge_channel->features->interval_hooks, 1);
-	if (!hook) {
-		return -1;
-	}
-	hook->parms.timer.interval = interval;
+	ast_heap_wrlock(features->interval_hooks);
+	if (ast_heap_push(features->interval_hooks, hook)) {
+		ao2_ref(hook, -1);
+	}
+	ast_heap_unlock(features->interval_hooks);
 
 	return 0;
 }
@@ -2809,7 +2851,10 @@
 
 	/* Initialize the interval hook heap */
 	features->interval_hooks = ast_heap_create(8, interval_hook_time_cmp,
-		offsetof(struct ast_bridge_hook, parms.timer.__heap_index));
+		offsetof(struct ast_bridge_hook, parms.timer.heap_index));
+	if (features->interval_hooks) {
+		return -1;
+	}
 
 	return 0;
 }
@@ -2822,12 +2867,8 @@
 	/* Destroy each interval hook. */
 	if (features->interval_hooks) {
 		while ((hook = ast_heap_pop(features->interval_hooks))) {
-			if (hook->destructor) {
-				hook->destructor(hook->hook_pvt);
-			}
-			ast_free(hook);
-		}
-
+			ao2_ref(hook, -1);
+		}
 		features->interval_hooks = ast_heap_destroy(features->interval_hooks);
 	}
 	if (features->interval_timer) {
@@ -2849,19 +2890,22 @@
 
 	/* Destroy each hangup hook. */
 	while ((hook = AST_LIST_REMOVE_HEAD(&features->hangup_hooks, entry))) {
-		if (hook->destructor) {
-			hook->destructor(hook->hook_pvt);
-		}
-		ast_free(hook);
+		ao2_ref(hook, -1);
 	}
 
 	/* Destroy each DTMF feature hook. */
 	while ((hook = AST_LIST_REMOVE_HEAD(&features->dtmf_hooks, entry))) {
-		if (hook->destructor) {
-			hook->destructor(hook->hook_pvt);
-		}
-		ast_free(hook);
-	}
+		ao2_ref(hook, -1);
+	}
+}
+
+void ast_bridge_features_destroy(struct ast_bridge_features *features)
+{
+	if (!features) {
+		return;
+	}
+	ast_bridge_features_cleanup(features);
+	ast_free(features);
 }
 
 struct ast_bridge_features *ast_bridge_features_new(void)
@@ -2870,19 +2914,13 @@
 
 	features = ast_malloc(sizeof(*features));
 	if (features) {
-		ast_bridge_features_init(features);
+		if (ast_bridge_features_init(features)) {
+			ast_bridge_features_destroy(features);
+			features = NULL;
+		}
 	}
 
 	return features;
-}
-
-void ast_bridge_features_destroy(struct ast_bridge_features *features)
-{
-	if (!features) {
-		return;
-	}
-	ast_bridge_features_cleanup(features);
-	ast_free(features);
 }
 
 int ast_bridge_dtmf_stream(struct ast_bridge *bridge, const char *dtmf, struct ast_channel *chan)

Modified: team/rmudgett/bridge_tasks/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_tasks/main/features.c?view=diff&rev=383515&r1=383514&r2=383515
==============================================================================
--- team/rmudgett/bridge_tasks/main/features.c (original)
+++ team/rmudgett/bridge_tasks/main/features.c Thu Mar 21 11:10:39 2013
@@ -4428,6 +4428,7 @@
 	pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
 	pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
 
+/* BUGBUG revisit how BLINDTRANSFER operates with the new bridging model. */
 	/* Clear any BLINDTRANSFER since the transfer has completed. */
 	pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
 	pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
@@ -4477,9 +4478,9 @@
 	clear_dialed_interfaces(peer);
 
 	/* Setup DTMF features. */
-	ast_bridge_features_init(&chan_features);
+	res = ast_bridge_features_init(&chan_features);
 	peer_features = ast_bridge_features_new();
-	if (!peer_features
+	if (res || !peer_features
 		|| setup_bridge_channel_features(peer_features, &config->features_callee)
 		|| setup_bridge_channel_features(&chan_features, &config->features_caller)) {
 		ast_bridge_features_destroy(peer_features);




More information about the asterisk-commits mailing list