Replace most uses of ast_register_atexit with ast_register_cleanup.
[asterisk/asterisk.git] / main / ccss.c
index 6b59a2f..7f63690 100644 (file)
@@ -45,13 +45,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/pbx.h"
 #include "asterisk/utils.h"
 #include "asterisk/taskprocessor.h"
-#include "asterisk/event.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
 #include "asterisk/cli.h"
 #include "asterisk/manager.h"
 #include "asterisk/causes.h"
+#include "asterisk/stasis_system.h"
+#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
        <application name="CallCompletionRequest" language="en_US">
@@ -1025,6 +1026,143 @@ void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char * c
        }
 }
 
+static int cc_publish(struct stasis_message_type *message_type, int core_id, struct ast_json *extras)
+{
+       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+       RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
+       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+
+       if (!message_type) {
+               return -1;
+       }
+
+       blob = ast_json_pack("{s: i}",
+               "core_id", core_id);
+       if (!blob) {
+               return -1;
+       }
+
+       if (extras) {
+               ast_json_object_update(blob, extras);
+       }
+
+       if (!(payload = ast_json_payload_create(blob))) {
+               return -1;
+       }
+
+       if (!(message = stasis_message_create(message_type, payload))) {
+               return -1;
+       }
+
+       stasis_publish(ast_system_topic(), message);
+
+       return 0;
+}
+
+static void cc_publish_available(int core_id, const char *callee, const char *service)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s, s: s}",
+               "callee", callee,
+               "service", service);
+
+       cc_publish(ast_cc_available_type(), core_id, extras);
+}
+
+static void cc_publish_offertimerstart(int core_id, const char *caller, unsigned int expires)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s, s: i}",
+               "caller", caller,
+               "expires", expires);
+
+       cc_publish(ast_cc_offertimerstart_type(), core_id, extras);
+}
+
+static void cc_publish_requested(int core_id, const char *caller, const char *callee)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s, s: s}",
+               "caller", caller,
+               "callee", callee);
+
+       cc_publish(ast_cc_requested_type(), core_id, extras);
+}
+
+static void cc_publish_requestacknowledged(int core_id, const char *caller)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s}",
+               "caller", caller);
+
+       cc_publish(ast_cc_requestacknowledged_type(), core_id, extras);
+}
+
+static void cc_publish_callerstopmonitoring(int core_id, const char *caller)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s}",
+               "caller", caller);
+
+       cc_publish(ast_cc_callerstopmonitoring_type(), core_id, extras);
+}
+
+static void cc_publish_callerstartmonitoring(int core_id, const char *caller)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s}",
+               "caller", caller);
+
+       cc_publish(ast_cc_callerstartmonitoring_type(), core_id, extras);
+}
+
+static void cc_publish_callerrecalling(int core_id, const char *caller)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s}",
+               "caller", caller);
+
+       cc_publish(ast_cc_callerrecalling_type(), core_id, extras);
+}
+
+static void cc_publish_recallcomplete(int core_id, const char *caller)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s}",
+               "caller", caller);
+
+       cc_publish(ast_cc_recallcomplete_type(), core_id, extras);
+}
+
+static void cc_publish_failure(int core_id, const char *caller, const char *reason)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s, s: s}",
+               "caller", caller,
+               "reason", reason);
+
+       cc_publish(ast_cc_failure_type(), core_id, extras);
+}
+
+static void cc_publish_monitorfailed(int core_id, const char *callee)
+{
+       RAII_VAR(struct ast_json *, extras, NULL, ast_json_unref);
+
+       extras = ast_json_pack("{s: s}",
+               "callee", callee);
+
+       cc_publish(ast_cc_monitorfailed_type(), core_id, extras);
+}
+
 struct cc_monitor_backend {
        AST_LIST_ENTRY(cc_monitor_backend) next;
        const struct ast_cc_monitor_callbacks *callbacks;
@@ -1267,7 +1405,7 @@ static void generic_monitor_instance_list_destructor(void *obj)
        ast_free((char *)generic_list->device_name);
 }
 
-static void generic_monitor_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg);
+static void generic_monitor_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg);
 static struct generic_monitor_instance_list *create_new_generic_list(struct ast_cc_monitor *monitor)
 {
        struct generic_monitor_instance_list *generic_list = ao2_t_alloc(sizeof(*generic_list),
@@ -1341,7 +1479,7 @@ static int generic_monitor_devstate_tp_cb(void *data)
        return 0;
 }
 
-static void generic_monitor_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
+static void generic_monitor_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        /* Wow, it's cool that we've picked up on a state change, but we really want
         * the actual work to be done in the core's taskprocessor execution thread
@@ -1975,7 +2113,7 @@ static struct ast_cc_monitor *cc_extension_monitor_init(const char * const exten
        cc_interface->monitor_class = AST_CC_EXTENSION_MONITOR;
        strcpy(cc_interface->device_name, ast_str_buffer(str));
        monitor->interface = cc_interface;
-       ast_log_dynamic_level(cc_logger_level, "Created an extension cc interface for '%s' with id %d and parent %d\n", cc_interface->device_name, monitor->id, monitor->parent_id);
+       ast_log_dynamic_level(cc_logger_level, "Created an extension cc interface for '%s' with id %u and parent %u\n", cc_interface->device_name, monitor->id, monitor->parent_id);
        return monitor;
 }
 
@@ -2154,7 +2292,7 @@ static struct ast_cc_monitor *cc_device_monitor_init(const char * const device_n
        monitor->interface = cc_interface;
        monitor->available_timer_id = -1;
        ast_cc_copy_config_params(cc_interface->config_params, &cc_data->config_params);
-       ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %d and parent %d\n",
+       ast_log_dynamic_level(cc_logger_level, "Core %d: Created a device cc interface for '%s' with id %u and parent %u\n",
                        monitor->core_id, cc_interface->device_name, monitor->id, monitor->parent_id);
        return monitor;
 }
@@ -2262,12 +2400,7 @@ void ast_handle_cc_control_frame(struct ast_channel *inbound, struct ast_channel
 
        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"
-               "Callee: %s\r\n"
-               "Service: %s\r\n",
-               cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service)
-       );
+       cc_publish_available(cc_interfaces->core_id, device_name, cc_service_to_string(cc_data->service));
 
        cc_unref(core_instance, "Done with core_instance after handling CC control frame");
        cc_unref(monitor, "Unref reference from allocating monitor");
@@ -2454,7 +2587,7 @@ static struct ast_cc_agent *cc_agent_init(struct ast_channel *caller_chan,
                cc_unref(agent, "Agent init callback failed.");
                return NULL;
        }
-       ast_log_dynamic_level(cc_logger_level, "Core %d: Created an agent for caller %s\n",
+       ast_log_dynamic_level(cc_logger_level, "Core %u: Created an agent for caller %s\n",
                        agent->core_id, agent->device_name);
        return agent;
 }
@@ -2559,7 +2692,7 @@ static int offer_timer_expire(const void *data)
 {
        struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
        struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
-       ast_log_dynamic_level(cc_logger_level, "Core %d: Queuing change request because offer timer has expired.\n",
+       ast_log_dynamic_level(cc_logger_level, "Core %u: Queuing change request because offer timer has expired.\n",
                        agent->core_id);
        agent_pvt->offer_timer_id = -1;
        ast_cc_failed(agent->core_id, "Generic agent %s offer timer expired", agent->device_name);
@@ -2577,7 +2710,7 @@ static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent)
        ast_assert(agent->cc_params != NULL);
 
        when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
-       ast_log_dynamic_level(cc_logger_level, "Core %d: About to schedule offer timer expiration for %d ms\n",
+       ast_log_dynamic_level(cc_logger_level, "Core %u: About to schedule offer timer expiration for %d ms\n",
                        agent->core_id, when);
        if ((sched_id = ast_sched_add(cc_sched_context, when, offer_timer_expire, cc_ref(agent, "Give scheduler an agent ref"))) == -1) {
                return -1;
@@ -2625,7 +2758,7 @@ static int cc_generic_agent_stop_ringing(struct ast_cc_agent *agent)
        return 0;
 }
 
-static void generic_agent_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
+static void generic_agent_devstate_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 {
        struct ast_cc_agent *agent = userdata;
        enum ast_device_state new_state;
@@ -2689,8 +2822,7 @@ static void *generic_recall(void *data)
        const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
        const char *callback_sub = ast_get_cc_callback_sub(agent->cc_params);
        unsigned int recall_timer = ast_get_cc_recall_timer(agent->cc_params) * 1000;
-       struct ast_format tmp_fmt;
-       struct ast_format_cap *tmp_cap = ast_format_cap_alloc_nolock();
+       struct ast_format_cap *tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
 
        if (!tmp_cap) {
                return NULL;
@@ -2701,17 +2833,17 @@ static void *generic_recall(void *data)
                *target++ = '\0';
        }
 
-       ast_format_cap_add(tmp_cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
-       if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
+       ast_format_cap_append(tmp_cap, ast_format_slin, 0);
+       if (!(chan = ast_request_and_dial(tech, tmp_cap, NULL, NULL, target, recall_timer, &reason, generic_pvt->cid_num, generic_pvt->cid_name))) {
                /* Hmm, no channel. Sucks for you, bud.
                 */
-               ast_log_dynamic_level(cc_logger_level, "Core %d: Failed to call back %s for reason %d\n",
+               ast_log_dynamic_level(cc_logger_level, "Core %u: Failed to call back %s for reason %d\n",
                                agent->core_id, agent->device_name, reason);
                ast_cc_failed(agent->core_id, "Failed to call back device %s/%s", tech, target);
-               ast_format_cap_destroy(tmp_cap);
+               ao2_ref(tmp_cap, -1);
                return NULL;
        }
-       ast_format_cap_destroy(tmp_cap);
+       ao2_ref(tmp_cap, -1);
        
        /* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
         * This will be a common task for all recall functions. If it were possible, I'd have
@@ -2729,7 +2861,7 @@ static void *generic_recall(void *data)
        pbx_builtin_setvar_helper(chan, "CC_CONTEXT", generic_pvt->context);
 
        if (!ast_strlen_zero(callback_macro)) {
-               ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback macro configured for agent %s\n",
+               ast_log_dynamic_level(cc_logger_level, "Core %u: There's a callback macro configured for agent %s\n",
                                agent->core_id, agent->device_name);
                if (ast_app_exec_macro(NULL, chan, callback_macro)) {
                        ast_cc_failed(agent->core_id, "Callback macro to %s failed. Maybe a hangup?", agent->device_name);
@@ -2739,7 +2871,7 @@ static void *generic_recall(void *data)
        }
 
        if (!ast_strlen_zero(callback_sub)) {
-               ast_log_dynamic_level(cc_logger_level, "Core %d: There's a callback subroutine configured for agent %s\n",
+               ast_log_dynamic_level(cc_logger_level, "Core %u: There's a callback subroutine configured for agent %s\n",
                                agent->core_id, agent->device_name);
                if (ast_app_exec_sub(NULL, chan, callback_sub, 0)) {
                        ast_cc_failed(agent->core_id, "Callback subroutine to %s failed. Maybe a hangup?", agent->device_name);
@@ -2868,7 +3000,7 @@ static int is_state_change_valid(enum cc_state current_state, const enum cc_stat
        int is_valid = 0;
        switch (new_state) {
        case CC_AVAILABLE:
-               ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to state %d? That should never happen.\n",
+               ast_log_dynamic_level(cc_logger_level, "Core %u: Asked to change to state %u? That should never happen.\n",
                                agent->core_id, new_state);
                break;
        case CC_CALLER_OFFERED:
@@ -2911,7 +3043,7 @@ static int is_state_change_valid(enum cc_state current_state, const enum cc_stat
                is_valid = 1;
                break;
        default:
-               ast_log_dynamic_level(cc_logger_level, "Core %d: Asked to change to unknown state %d\n",
+               ast_log_dynamic_level(cc_logger_level, "Core %u: Asked to change to unknown state %u\n",
                                agent->core_id, new_state);
                break;
        }
@@ -2933,11 +3065,7 @@ static int cc_caller_offered(struct cc_core_instance *core_instance, struct cc_s
                                core_instance->agent->device_name);
                return -1;
        }
-       manager_event(EVENT_FLAG_CC, "CCOfferTimerStart",
-               "CoreID: %d\r\n"
-               "Caller: %s\r\n"
-               "Expires: %u\r\n",
-               core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
+       cc_publish_offertimerstart(core_instance->core_id, core_instance->agent->device_name, core_instance->agent->cc_params->cc_offer_timer);
        ast_log_dynamic_level(cc_logger_level, "Core %d: Started the offer timer for the agent %s!\n",
                        core_instance->core_id, core_instance->agent->device_name);
        return 0;
@@ -2986,11 +3114,7 @@ static void request_cc(struct cc_core_instance *core_instance)
                                                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, "CCRequested",
-                                       "CoreID: %d\r\n"
-                                       "Caller: %s\r\n"
-                                       "Callee: %s\r\n",
-                                       core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
+                               cc_publish_requested(core_instance->core_id, core_instance->agent->device_name, monitor_iter->interface->device_name);
                        }
                }
        }
@@ -3048,15 +3172,9 @@ static int cc_active(struct cc_core_instance *core_instance, struct cc_state_cha
        if (previous_state == CC_CALLER_REQUESTED) {
                core_instance->agent->callbacks->respond(core_instance->agent,
                        AST_CC_AGENT_RESPONSE_SUCCESS);
-               manager_event(EVENT_FLAG_CC, "CCRequestAcknowledged",
-                       "CoreID: %d\r\n"
-                       "Caller: %s\r\n",
-                       core_instance->core_id, core_instance->agent->device_name);
+               cc_publish_requestacknowledged(core_instance->core_id, core_instance->agent->device_name);
        } else if (previous_state == CC_CALLER_BUSY) {
-               manager_event(EVENT_FLAG_CC, "CCCallerStopMonitoring",
-                       "CoreID: %d\r\n"
-                       "Caller: %s\r\n",
-                       core_instance->core_id, core_instance->agent->device_name);
+               cc_publish_callerstopmonitoring(core_instance->core_id, core_instance->agent->device_name);
                unsuspend(core_instance);
        }
        /* Not possible for previous_state to be anything else due to the is_state_change_valid check at the beginning */
@@ -3098,10 +3216,7 @@ static int cc_caller_busy(struct cc_core_instance *core_instance, struct cc_stat
         */
        suspend(core_instance);
        core_instance->agent->callbacks->start_monitoring(core_instance->agent);
-       manager_event(EVENT_FLAG_CC, "CCCallerStartMonitoring",
-               "CoreID: %d\r\n"
-               "Caller: %s\r\n",
-               core_instance->core_id, core_instance->agent->device_name);
+       cc_publish_callerstartmonitoring(core_instance->core_id, core_instance->agent->device_name);
        return 0;
 }
 
@@ -3132,10 +3247,7 @@ static int cc_recalling(struct cc_core_instance *core_instance, struct cc_state_
        /* Both caller and callee are available, call agent's recall callback
         */
        cancel_available_timer(core_instance);
-       manager_event(EVENT_FLAG_CC, "CCCallerRecalling",
-               "CoreID: %d\r\n"
-               "Caller: %s\r\n",
-               core_instance->core_id, core_instance->agent->device_name);
+       cc_publish_callerrecalling(core_instance->core_id, core_instance->agent->device_name);
        return 0;
 }
 
@@ -3143,21 +3255,14 @@ static int cc_complete(struct cc_core_instance *core_instance, struct cc_state_c
 {
        /* Recall has made progress, call agent and monitor destructor functions
         */
-       manager_event(EVENT_FLAG_CC, "CCRecallComplete",
-               "CoreID: %d\r\n"
-               "Caller: %s\r\n",
-               core_instance->core_id, core_instance->agent->device_name);
+       cc_publish_recallcomplete(core_instance->core_id, core_instance->agent->device_name);
        ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC recall has completed");
        return 0;
 }
 
 static int cc_failed(struct cc_core_instance *core_instance, struct cc_state_change_args *args, enum cc_state previous_state)
 {
-       manager_event(EVENT_FLAG_CC, "CCFailure",
-               "CoreID: %d\r\n"
-               "Caller: %s\r\n"
-               "Reason: %s\r\n",
-               core_instance->core_id, core_instance->agent->device_name, args->debug);
+       cc_publish_failure(core_instance->core_id, core_instance->agent->device_name, args->debug);
        ao2_t_unlink(cc_core_instances, core_instance, "Unlink core instance since CC failed");
        return 0;
 }
@@ -3181,7 +3286,7 @@ static int cc_do_state_change(void *datap)
        enum cc_state previous_state;
        int res;
 
-       ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %d requested. Reason: %s\n",
+       ast_log_dynamic_level(cc_logger_level, "Core %d: State change to %u requested. Reason: %s\n",
                        args->core_id, args->state, args->debug);
 
        core_instance = args->core_instance;
@@ -3811,10 +3916,7 @@ static int cc_monitor_failed(void *data)
                                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);
-                               manager_event(EVENT_FLAG_CC, "CCMonitorFailed",
-                                       "CoreID: %d\r\n"
-                                       "Callee: %s\r\n",
-                                       monitor_iter->core_id, monitor_iter->interface->device_name);
+                               cc_publish_monitorfailed(monitor_iter->core_id, monitor_iter->interface->device_name);
                                cc_unref(monitor_iter, "Monitor reported failure. Unref list's reference.");
                        }
                }
@@ -4586,7 +4688,7 @@ int ast_cc_init(void)
        initialize_cc_devstate_map();
        res |= ast_devstate_prov_add("ccss", ccss_device_state);
 
-       ast_register_atexit(cc_shutdown);
+       ast_register_cleanup(cc_shutdown);
 
        return res;
 }