[svn-commits] mmichelson: branch group/CCSS r247656 - in /team/group/CCSS: apps/ include/as...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Feb 18 14:05:33 CST 2010


Author: mmichelson
Date: Thu Feb 18 14:05:28 2010
New Revision: 247656

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=247656
Log:
Add unmonitored extensions to CC_INTERFACES chanvar.

This is one of the last major missing pieces for CCSS. Prior
to this change, only monitored devices were added to the
CC_INTERFACES channel variable during a recall. However, our
design was for all originally-dialed devices to be represented
in this variable. This set of changes allows for that to occur.
The comments in the code, especially for the extension_child_dialstring
structure should explain how this works pretty well.

The next major item for me to look at is going to be lock order. The
monitor restructuring that was done several weeks ago added locking
where previously there was none. I'm going to look for specific areas
where lock order may be an issue.


Modified:
    team/group/CCSS/apps/app_dial.c
    team/group/CCSS/include/asterisk/ccss.h
    team/group/CCSS/main/ccss.c

Modified: team/group/CCSS/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/apps/app_dial.c?view=diff&rev=247656&r1=247655&r2=247656
==============================================================================
--- team/group/CCSS/apps/app_dial.c (original)
+++ team/group/CCSS/apps/app_dial.c Thu Feb 18 14:05:28 2010
@@ -1726,6 +1726,7 @@
 	struct ast_datastore *datastore = NULL;
 	int fulldial = 0, num_dialed = 0;
 	int ignore_cc = 0;
+	char device_name[AST_CHANNEL_NAME];
 
 	/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
 	pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
@@ -1946,10 +1947,14 @@
 				chan->hangupcause = cause;
 			chanlist_free(tmp);
 			if (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION) {
-				ast_cc_callback(chan, tech, numsubst, ast_cc_busy_interface);
+				if (!ast_cc_callback(chan, tech, numsubst, ast_cc_busy_interface)) {
+					ast_cc_extension_monitor_add_dialstring(chan, interface, "");
+				}
 			}
 			continue;
 		}
+		ast_channel_get_device_name(tc, device_name, sizeof(device_name));
+		ast_cc_extension_monitor_add_dialstring(chan, interface, device_name);
 		pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
 
 		ast_channel_lock(tc);

Modified: team/group/CCSS/include/asterisk/ccss.h
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/include/asterisk/ccss.h?view=diff&rev=247656&r1=247655&r2=247656
==============================================================================
--- team/group/CCSS/include/asterisk/ccss.h (original)
+++ team/group/CCSS/include/asterisk/ccss.h Thu Feb 18 14:05:28 2010
@@ -704,6 +704,8 @@
  * \retval -1 Failure
  */
 int ast_cc_call_init(struct ast_channel *chan, int *ignore_cc);
+
+void ast_cc_extension_monitor_add_dialstring(struct ast_channel *incoming, const char * const dialstring, const char * const device_name);
 
 /*!
  * \since 1.8

Modified: team/group/CCSS/main/ccss.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/main/ccss.c?view=diff&rev=247656&r1=247655&r2=247656
==============================================================================
--- team/group/CCSS/main/ccss.c (original)
+++ team/group/CCSS/main/ccss.c Thu Feb 18 14:05:28 2010
@@ -1255,6 +1255,99 @@
 	ast_cc_config_params_destroy(interface->config_params);
 }
 
+/*!
+ * \brief Data regarding an extension monitor's child's dialstrings
+ *
+ * \details
+ * In developing CCSS, we had most aspects of its operation finished,
+ * but there was one looming problem that we had failed to get right.
+ * In our design document, we stated that when a CC recall occurs, all
+ * endpoints that had been dialed originally would be called back.
+ * Unfortunately, our implementation only allowed for devices which had
+ * active monitors to inhabit the CC_INTERFACES channel variable, thus
+ * making the automated recall only call monitored devices.
+ *
+ * Devices that were not CC-capable, or devices which failed CC at some
+ * point during the process would not make it into the CC_INTERFACES
+ * channel variable. This struct is meant as a remedy for the problem.
+ */
+struct extension_child_dialstring {
+	/*!
+	 * \brief the original dialstring used to call a particular device
+	 *
+	 * \details
+	 * When someone dials a particular endpoint, the dialstring used in
+	 * the dialplan is copied into this buffer. What's important here is
+	 * that this is the ORIGINAL dialstring, not the dialstring saved on
+	 * a device monitor. The dialstring on a device monitor is what should
+	 * be used when recalling that device. The two dialstrings may not be
+	 * the same.
+	 *
+	 * By keeping a copy of the original dialstring used, we can fall back
+	 * to using it if the device either does not ever offer CC or if the
+	 * device at some point fails for some reason, such as a timer expiration.
+	 */
+	char original_dialstring[AST_CHANNEL_NAME];
+	/*!
+	 * \brief The name of the device being dialed
+	 *
+	 * \details
+	 * This serves mainly as a key when searching for a particular dialstring.
+	 * For instance, let's say that we have called device SIP/400 at somepeer. This
+	 * device offers call completion, but then due to some unforeseen circumstance,
+	 * this device backs out and makes CC unavailable. When that happens, we need
+	 * to find the dialstring that corresponds to that device, and we use the
+	 * stored device name as a way to find it.
+	 *
+	 * Note that there is one particular case where the device name stored here
+	 * will be empty. This is the case where we fail to request a channel, but we
+	 * still can make use of generic call completion. In such a case, since we never
+	 * were able to request the channel, we can't find what its device name is. In
+	 * this case, however, it is not important because the dialstring is guaranteed
+	 * to be the same both here and in the device monitor.
+	 */
+	char device_name[AST_CHANNEL_NAME];
+	/*!
+	 * \brief Is this structure valid for use in CC_INTERFACES?
+	 *
+	 * \details
+	 * When this structure is first created, all information stored here is planned
+	 * to be used, so we set the is_valid flag. However, if a device offers call
+	 * completion, it will potentially have its own dialstring to use for the recall,
+	 * so we find this structure and clear the is_valid flag. By clearing the is_valid
+	 * flag, we won't try to populate the CC_INTERFACES variable with the dialstring
+	 * stored in this struct. Now, if later, the device which had offered CC should fail,
+	 * perhaps due to a timer expiration, then we need to re-set the is_valid flag. This
+	 * way, we still will end up placing a call to the device again, and the dialstring
+	 * used will be the same as was originally used.
+	 */
+	int is_valid;
+	AST_LIST_ENTRY(extension_child_dialstring) next;
+};
+
+/*!
+ * \brief Private data for an extension monitor
+ */
+struct extension_monitor_pvt {
+	AST_LIST_HEAD(, extension_child_dialstring) child_dialstrings;
+};
+
+static void cc_extension_monitor_destructor(void *private_data)
+{
+	struct extension_monitor_pvt *extension_pvt = private_data;
+	struct extension_child_dialstring *child_dialstring;
+
+	/* This shouldn't be possible, but I'm paranoid */
+	if (!extension_pvt) {
+		return;
+	}
+
+	while ((child_dialstring = AST_LIST_REMOVE_HEAD(&extension_pvt->child_dialstrings, next))) {
+		ast_free(child_dialstring);
+	}
+	ast_free(extension_pvt);
+}
+
 static void cc_monitor_destroy(void *data)
 {
 	struct ast_cc_monitor *monitor = data;
@@ -1265,6 +1358,9 @@
 	 * to destroy one of them.
 	 */
 	ast_log_dynamic_level(cc_logger_level, "Calling destructor for monitor %s, core ID %d\n", monitor->interface->device_name, monitor->core_id);
+	if (monitor->interface->monitor_class == AST_CC_EXTENSION_MONITOR) {
+		cc_extension_monitor_destructor(monitor->private_data);
+	}
 	if (monitor->callbacks) {
 		monitor->callbacks->destructor(monitor->private_data);
 	}
@@ -1434,6 +1530,75 @@
 	return;
 }
 
+static struct extension_monitor_pvt *extension_monitor_pvt_init(void)
+{
+	struct extension_monitor_pvt *ext_pvt = ast_calloc(1, sizeof(*ext_pvt));
+	if (!ext_pvt) {
+		return NULL;
+	}
+	AST_LIST_HEAD_INIT(&ext_pvt->child_dialstrings);
+	return ext_pvt;
+}
+
+void ast_cc_extension_monitor_add_dialstring(struct ast_channel *incoming, const char * const dialstring, const char * const device_name)
+{
+	struct ast_datastore *cc_datastore;
+	struct dialed_cc_interfaces *cc_interfaces;
+	struct ast_cc_monitor *monitor;
+	struct extension_monitor_pvt *extension_pvt;
+	struct extension_child_dialstring *child_dialstring;
+
+	if (!(cc_datastore = ast_channel_datastore_find(incoming, &dialed_cc_interfaces_info, NULL))) {
+		return;
+	}
+
+	cc_interfaces = cc_datastore->data;
+	AST_DLLIST_TRAVERSE(cc_interfaces->interface_tree, monitor, next) {
+		if (monitor->id == cc_interfaces->dial_parent_id) {
+			ast_log(LOG_NOTICE, "Found monitor named %s\n", monitor->interface->device_name);
+			break;
+		}
+	}
+
+	if (!monitor) {
+		return;
+	}
+
+	extension_pvt = monitor->private_data;
+	if (!(child_dialstring = ast_calloc(1, sizeof(*child_dialstring)))) {
+		return;
+	}
+	ast_copy_string(child_dialstring->original_dialstring, dialstring, sizeof(child_dialstring->original_dialstring));
+	ast_copy_string(child_dialstring->device_name, device_name, sizeof(child_dialstring->device_name));
+	child_dialstring->is_valid = 1;
+	AST_LIST_INSERT_TAIL(&extension_pvt->child_dialstrings, child_dialstring, next);
+}
+
+static void cc_extension_monitor_change_is_valid(struct cc_core_instance *core_instance, unsigned int parent_id, const char * const device_name, int is_valid)
+{
+	struct ast_cc_monitor *monitor_iter;
+	struct extension_monitor_pvt *extension_pvt;
+	struct extension_child_dialstring *child_dialstring;
+
+	AST_DLLIST_TRAVERSE(core_instance->monitors, monitor_iter, next) {
+		if (monitor_iter->id == parent_id) {
+			break;
+		}
+	}
+
+	if (!monitor_iter) {
+		return;
+	}
+	extension_pvt = monitor_iter->private_data;
+
+	AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
+		if (!strcmp(child_dialstring->device_name, device_name)) {
+			child_dialstring->is_valid = is_valid;
+			break;
+		}
+	}
+}
+
 /*!
  * \internal
  * \brief Allocate and initialize an "extension" interface for CC purposes
@@ -1463,6 +1628,11 @@
 	if (!(monitor = ao2_alloc(sizeof(*monitor), cc_monitor_destroy))) {
 		cc_unref(cc_interface, "failed to allocate the tree item, so unref the interface");
 		return NULL;
+	}
+
+	if (!(monitor->private_data = extension_monitor_pvt_init())) {
+		cc_unref(monitor, "Failed to initialize extension monitor private data. uref monitor");
+		cc_unref(cc_interface, "Failed to initialize extension monitor private data. unref cc_interface");
 	}
 
 	monitor->id = ast_atomic_fetchadd_int(&dialed_cc_interface_counter, +1);
@@ -1757,6 +1927,8 @@
 	cc_ref(monitor, "Interface tree's reference to the monitor");
 	AST_DLLIST_INSERT_TAIL(cc_interfaces->interface_tree, monitor, next);
 	AST_DLLIST_UNLOCK(cc_interfaces->interface_tree);
+
+	cc_extension_monitor_change_is_valid(core_instance, monitor->parent_id, monitor->interface->device_name, 0);
 
 	manager_event(EVENT_FLAG_CC, "CCAvailable",
 		"CoreID: %d\r\n"
@@ -2380,16 +2552,35 @@
 	return 0;
 }
 
-static int has_children(struct ast_cc_monitor *monitor)
-{
-	struct ast_cc_monitor *iter = monitor;
-
-	while ((iter = AST_DLLIST_NEXT(iter, next))) {
-		if (iter->parent_id == monitor->id) {
-			return 1;
+/*!
+ * \brief check if the core instance has any device monitors
+ *
+ * In any case where we end up removing a device monitor from the
+ * list of device monitors, it is important to see what the state
+ * of the list is afterwards. If we find that we only have extension
+ * monitors left, then no devices are actually being monitored.
+ * In such a case, we need to declare that CC has failed for this
+ * call. This function helps those cases to determine if they should
+ * declare failure.
+ *
+ * \param core_instance The core instance we are checking for the existence
+ * of device monitors
+ * \retval 0 No device monitors exist on this core_instance
+ * \retval 1 There is still at least 1 device monitor remaining
+ */
+static int has_device_monitors(struct cc_core_instance *core_instance)
+{
+	struct ast_cc_monitor *iter;
+	int res = 0;
+
+	AST_DLLIST_TRAVERSE(core_instance->monitors, iter, next) {
+		if (iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
+			res = 1;
+			break;
 		}
 	}
-	return 0;
+	
+	return res;
 }
 
 static void request_cc(struct cc_core_instance *core_instance)
@@ -2400,6 +2591,8 @@
 		if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
 			if (monitor_iter->callbacks->request_cc(monitor_iter, &monitor_iter->available_timer_id)) {
 				AST_DLLIST_REMOVE_CURRENT(next);
+				cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id, 
+						monitor_iter->interface->device_name, 1);
 				cc_unref(monitor_iter, "request_cc failed. Unref list's reference to monitor");
 			} else {
 				manager_event(EVENT_FLAG_CC, "CCRequestSent",
@@ -2408,14 +2601,11 @@
 					"Callee: %s\r\n",
 					core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
 			}
-		} else if (!has_children(monitor_iter)) {
-			AST_DLLIST_REMOVE_CURRENT(next);
-			cc_unref(monitor_iter, "request_cc failed on all children. Unref list's reference to monitor");
 		}
 	}
 	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
 
-	if (AST_DLLIST_EMPTY(core_instance->monitors)) {
+	if (!has_device_monitors(core_instance)) {
 		ast_cc_failed(core_instance->core_id, "All device monitors failed to request CC");
 	}
 	AST_DLLIST_UNLOCK(core_instance->monitors);
@@ -2445,16 +2635,15 @@
 		if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
 			if (monitor_iter->callbacks->unsuspend(monitor_iter)) {
 				AST_DLLIST_REMOVE_CURRENT(next);
+				cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id, 
+						monitor_iter->interface->device_name, 1);
 				cc_unref(monitor_iter, "unsuspend failed. Unref list's reference to monitor");
 			}
-		} else if (!has_children(monitor_iter)) {
-			AST_DLLIST_REMOVE_CURRENT(next);
-			cc_unref(monitor_iter, "unsuspend failed on all children. Unref list's reference to monitor");
 		}
 	}
 	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
 
-	if (AST_DLLIST_EMPTY(core_instance->monitors)) {
+	if (!has_device_monitors(core_instance)) {
 		ast_cc_failed(core_instance->core_id, "All device monitors failed to unsuspend CC");
 	}
 	AST_DLLIST_UNLOCK(core_instance->monitors);
@@ -2496,16 +2685,15 @@
 		if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
 			if (monitor_iter->callbacks->suspend(monitor_iter)) {
 				AST_DLLIST_REMOVE_CURRENT(next);
+				cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id, 
+						monitor_iter->interface->device_name, 1);
 				cc_unref(monitor_iter, "suspend failed. Unref list's reference to monitor");
 			}
-		} else if (!has_children(monitor_iter)) {
-			AST_DLLIST_REMOVE_CURRENT(next);
-			cc_unref(monitor_iter, "suspend failed on all children. Unref list's reference to monitor");
 		}
 	}
 	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
 
-	if (AST_DLLIST_EMPTY(core_instance->monitors)) {
+	if (!has_device_monitors(core_instance)) {
 		ast_cc_failed(core_instance->core_id, "All device monitors failed to suspend CC");
 	}
 	AST_DLLIST_UNLOCK(core_instance->monitors);
@@ -2533,16 +2721,15 @@
 		if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
 			if (monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id)) {
 				AST_DLLIST_REMOVE_CURRENT(next);
+				cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id, 
+						monitor_iter->interface->device_name, 1);
 				cc_unref(monitor_iter, "cancel_available_timer failed. Unref list's reference to monitor");
 			}
-		} else if (!has_children(monitor_iter)) {
-			AST_DLLIST_REMOVE_CURRENT(next);
-			cc_unref(monitor_iter, "cancel_available_timer failed on all children. Unref list's reference to monitor");
 		}
 	}
 	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
 
-	if (AST_DLLIST_EMPTY(core_instance->monitors)) {
+	if (!has_device_monitors(core_instance)) {
 		ast_cc_failed(core_instance->core_id, "All device monitors failed to cancel their available timers");
 	}
 	AST_DLLIST_UNLOCK(core_instance->monitors);
@@ -2836,63 +3023,90 @@
 	return monitor_iter;
 }
 
+static void cc_unique_append(struct ast_str *str, const char * const dialstring)
+{
+	char dialstring_search[AST_CHANNEL_NAME];
+
+	snprintf(dialstring_search, sizeof(dialstring_search), "%s%c", dialstring, '&');
+	ast_log(LOG_NOTICE, "dialstring_search set to %s\n", dialstring_search);
+	if (strstr(ast_str_buffer(str), dialstring_search)) {
+		ast_log(LOG_NOTICE, "Found dialstring in the buffer?\n");
+		return;
+	}
+	ast_str_append(&str, 0, "%s", dialstring_search);
+}
+
+static void set_cc_interfaces_chanvar(struct ast_cc_monitor *starting_point, struct ast_channel *chan)
+{
+	struct extension_monitor_pvt *extension_pvt;
+	struct extension_child_dialstring *child_dialstring;
+	struct ast_cc_monitor *monitor_iter = starting_point;
+	int top_level_id = starting_point->id;
+	struct ast_str *var_value = ast_str_create(64);
+
+	/* First we need to take all of the is_valid child_dialstrings from
+	 * the extension monitor we found and add them to the CC_INTERFACES
+	 * chanvar
+	 */
+	extension_pvt = starting_point->private_data;
+	AST_LIST_TRAVERSE(&extension_pvt->child_dialstrings, child_dialstring, next) {
+		if (child_dialstring->is_valid) {
+			cc_unique_append(var_value, child_dialstring->original_dialstring);
+		}
+	}
+
+	/* And now we get the dialstrings from each of the device monitors */
+	while ((monitor_iter = AST_DLLIST_NEXT(monitor_iter, next))) {
+		if (monitor_iter->parent_id == top_level_id) {
+			cc_unique_append(var_value, monitor_iter->dialstring);
+		}
+	}
+
+	/* var_value will have an extra '&' tacked onto the end of it, so we need
+	 * to get rid of that.
+	 */
+	ast_str_truncate(var_value, ast_str_strlen(var_value) - 1);
+
+	pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(var_value));
+	ast_log_dynamic_level(cc_logger_level, "CC_INTERFACES set to %s\n", ast_str_buffer(var_value));
+	ast_free(var_value);
+}
+
 int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan)
+{
+	struct ast_datastore *recall_datastore;
+	struct ast_cc_interface_tree *interface_tree;
+	struct ast_cc_monitor *monitor;
+	struct cc_recall_ds_data *recall_data;
+
+	ast_channel_lock(chan);
+	if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
+		ast_channel_unlock(chan);
+		return -1;
+	}
+	recall_data = recall_datastore->data;
+	interface_tree = cc_ref(recall_data->interface_tree, "Getting ref of recall interface tree");
+	ast_channel_unlock(chan);
+
+	AST_DLLIST_LOCK(interface_tree);
+	monitor = AST_DLLIST_FIRST(interface_tree);
+	set_cc_interfaces_chanvar(monitor, chan);
+	AST_DLLIST_UNLOCK(interface_tree);
+
+	cc_unref(interface_tree, "Done with interface tree while setting CC_INTERFACES");
+	return 0;
+}
+
+int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char * const extension)
 {
 	struct ast_datastore *recall_datastore;
 	struct ast_cc_interface_tree *interface_tree;
 	struct ast_cc_monitor *monitor_iter;
 	struct cc_recall_ds_data *recall_data;
-	struct ast_str *var_value = ast_str_create(64);
-	int multi = 0;
-	char previous_dialstring[AST_CHANNEL_NAME] = "";
-	int top_level_id;
 
 	ast_channel_lock(chan);
 	if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
 		ast_channel_unlock(chan);
-		ast_free(var_value);
-		return -1;
-	}
-	recall_data = recall_datastore->data;
-	interface_tree = cc_ref(recall_data->interface_tree, "Getting ref of recall interface tree");
-	ast_channel_unlock(chan);
-
-	AST_DLLIST_LOCK(interface_tree);
-	monitor_iter = AST_DLLIST_FIRST(interface_tree);
-	top_level_id = monitor_iter->id;
-
-	while ((monitor_iter = AST_DLLIST_NEXT(monitor_iter, next))) {
-		if (monitor_iter->parent_id == top_level_id && strcmp(monitor_iter->dialstring, previous_dialstring)) {
-			char *dialstring = monitor_iter->dialstring;
-			ast_str_append(&var_value, 0, "%s%s", multi ? "&" : "", dialstring);
-			multi = 1;
-			ast_copy_string(previous_dialstring, dialstring, sizeof(previous_dialstring));
-		}
-	}
-	AST_DLLIST_UNLOCK(interface_tree);
-
-	pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(var_value));
-	ast_log_dynamic_level(cc_logger_level, "CC_INTERFACES set to %s\n", ast_str_buffer(var_value));
-	ast_free(var_value);
-	cc_unref(interface_tree, "Done with interface tree while setting CC_INTERFACES");
-	return 0;
-}
-
-int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char * const extension)
-{
-	struct ast_datastore *recall_datastore;
-	struct ast_cc_interface_tree *interface_tree;
-	struct ast_cc_monitor *monitor_iter;
-	struct cc_recall_ds_data *recall_data;
-	unsigned int exten_id = 0;
-	struct ast_str *var_value = ast_str_create(64);
-	int multi = 0;
-	char previous_dialstring[AST_CHANNEL_NAME] = "";
-
-	ast_channel_lock(chan);
-	if (!(recall_datastore = ast_channel_datastore_find(chan, &recall_ds_info, NULL))) {
-		ast_channel_unlock(chan);
-		ast_free(var_value);
 		return -1;
 	}
 	recall_data = recall_datastore->data;
@@ -2902,37 +3116,22 @@
 	AST_DLLIST_LOCK(interface_tree);
 	AST_DLLIST_TRAVERSE(interface_tree, monitor_iter, next) {
 		if (!strcmp(monitor_iter->interface->device_name, extension)) {
-			exten_id = monitor_iter->id;
 			break;
 		}
 	}
 
-	if (!exten_id) {
+	if (!monitor_iter) {
 		/* We couldn't find this extension. This may be because
-		 * we have been directed into an unexected extension because
+		 * we have been directed into an unexpected extension because
 		 * the admin has changed a CC_INTERFACES variable at some point.
 		 */
-		ast_free(var_value);
 		AST_DLLIST_UNLOCK(interface_tree);
 		cc_unref(interface_tree, "Couldn't find the extension specified");
 		return -1;
 	}
 
-	/* I kind of feel wrong re-using monitor_iter here, but eh, it works
-	 */
-	while ((monitor_iter = AST_DLLIST_NEXT(monitor_iter, next))) {
-		if (monitor_iter->parent_id == exten_id && strcmp(monitor_iter->dialstring, previous_dialstring)) {
-			char *dialstring = monitor_iter->dialstring;
-			ast_str_append(&var_value, 0, "%s%s", multi ? "&" : "", dialstring);
-			multi = 1;
-			ast_copy_string(previous_dialstring, dialstring, sizeof(previous_dialstring));
-		}
-	}
+	set_cc_interfaces_chanvar(monitor_iter, chan);
 	AST_DLLIST_UNLOCK(interface_tree);
-
-	pbx_builtin_setvar_helper(chan, "CC_INTERFACES", ast_str_buffer(var_value));
-	ast_log_dynamic_level(cc_logger_level, "CC_INTERFACES set to %s\n", ast_str_buffer(var_value));
-	ast_free(var_value);
 	cc_unref(interface_tree, "Done writing the CC_INTERFACES channel variable");
 	return 0;
 }
@@ -3136,17 +3335,16 @@
 		if (monitor_iter->interface->monitor_class == AST_CC_DEVICE_MONITOR) {
 			if (!strcmp(monitor_iter->interface->device_name, failure_data->device_name)) {
 				AST_DLLIST_REMOVE_CURRENT(next);
+				cc_extension_monitor_change_is_valid(core_instance, monitor_iter->parent_id, 
+						monitor_iter->interface->device_name, 1);
 				monitor_iter->callbacks->cancel_available_timer(monitor_iter, &monitor_iter->available_timer_id);
 				cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
 			}
-		} else if (!has_children(monitor_iter)) {
-			AST_DLLIST_REMOVE_CURRENT(next);
-			cc_unref(monitor_iter, "All of monitor's children reported failure. Unref list's reference.");
 		}
 	}
 	AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
 
-	if (AST_DLLIST_EMPTY(core_instance->monitors)) {
+	if (!has_device_monitors(core_instance)) {
 		ast_cc_failed(core_instance->core_id, "All monitors have failed\n");
 	}
 	AST_DLLIST_UNLOCK(core_instance->monitors);




More information about the svn-commits mailing list