aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/ccss.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/main/ccss.c b/main/ccss.c
index ad1d76ed5..583c7389c 100644
--- a/main/ccss.c
+++ b/main/ccss.c
@@ -990,6 +990,22 @@ struct generic_monitor_instance {
struct generic_monitor_instance_list {
const char *device_name;
enum ast_device_state current_state;
+ /* If there are multiple instances monitoring the
+ * same device and one should fail, we need to know
+ * whether to signal that the device can be recalled.
+ * The problem is that the device state is not enough
+ * to check. If a caller has requested CCNR, then the
+ * fact that the device is available does not indicate
+ * that the device is ready to be recalled. Instead, as
+ * soon as one instance of the monitor becomes available
+ * for a recall, we mark the entire list as being fit
+ * for recall. If a CCNR request comes in, then we will
+ * have to mark the list as unfit for recall since this
+ * is a clear indicator that the person at the monitored
+ * device has gone away and is actuall not fit to be
+ * recalled
+ */
+ int fit_for_recall;
struct ast_event_sub *sub;
AST_LIST_HEAD_NOLOCK(, generic_monitor_instance) list;
};
@@ -1112,6 +1128,7 @@ static int generic_monitor_devstate_tp_cb(void *data)
AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
if (!generic_instance->is_suspended && generic_instance->monitoring) {
generic_instance->monitoring = 0;
+ generic_list->fit_for_recall = 1;
ast_cc_monitor_callee_available(generic_instance->core_id, "Generic monitored party has become available");
break;
}
@@ -1209,6 +1226,12 @@ static int cc_generic_monitor_request_cc(struct ast_cc_monitor *monitor, int *av
cc_unref(generic_list, "Failed to schedule available timer. (generic_list)");
return -1;
}
+ /* If the new instance was created as CCNR, then that means this device is not currently
+ * fit for recall even if it previously was.
+ */
+ if (service == AST_CC_CCNR || service == AST_CC_CCNL) {
+ generic_list->fit_for_recall = 0;
+ }
ast_cc_monitor_request_acked(monitor->core_id, "Generic monitor for %s subscribed to device state.",
monitor->interface->device_name);
cc_unref(generic_list, "Finished with monitor instance reference in request cc callback");
@@ -1343,6 +1366,27 @@ static void cc_generic_monitor_destructor(void *private_data)
* list from the container
*/
ao2_t_unlink(generic_monitors, generic_list, "Generic list is empty. Unlink it from the container");
+ } else {
+ /* There are still instances for this particular device. The situation
+ * may be that we were attempting a CC recall and a failure occurred, perhaps
+ * on the agent side. If a failure happens here and the device being monitored
+ * is available, then we need to signal on the first unsuspended instance that
+ * the device is available for recall.
+ */
+
+ /* First things first. We don't even want to consider this action if
+ * the device in question isn't available right now.
+ */
+ if (generic_list->fit_for_recall && (generic_list->current_state == AST_DEVICE_NOT_INUSE ||
+ generic_list->current_state == AST_DEVICE_UNKNOWN)) {
+ AST_LIST_TRAVERSE(&generic_list->list, generic_instance, next) {
+ if (!generic_instance->is_suspended && generic_instance->monitoring) {
+ ast_cc_monitor_callee_available(generic_instance->core_id, "Signaling generic monitor "
+ "availability due to other instance's failure.");
+ break;
+ }
+ }
+ }
}
cc_unref(generic_list, "Done with generic list in generic monitor destructor");
ast_free((char *)gen_mon_pvt->device_name);
@@ -2848,8 +2892,6 @@ static int cc_complete(struct cc_core_instance *core_instance, struct cc_state_c
static int cc_failed(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
{
- /* Something along the way failed, call agent and monitor destructor functions
- */
manager_event(EVENT_FLAG_CC, "CCFailure",
"CoreID: %d\r\n"
"Caller: %s\r\n"