Merge "asterisk.c: When astcanary dies on linux, reset priority on all threads."
[asterisk/asterisk.git] / main / parking.c
index 2a5b72e..61a4896 100644 (file)
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ASTERISK_REGISTER_FILE()
 
 #include "asterisk/_private.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/pbx.h"
-#include "asterisk/bridging.h"
+#include "asterisk/bridge.h"
 #include "asterisk/parking.h"
 #include "asterisk/channel.h"
+#include "asterisk/_private.h"
+#include "asterisk/module.h"
 
 /*! \brief Message type for parked calls */
-static struct stasis_message_type *parked_call_type;
+STASIS_MESSAGE_TYPE_DEFN(ast_parked_call_type);
 
 /*! \brief Topic for parking lots */
 static struct stasis_topic *parking_topic;
 
-/*! \brief Function Callback for handling blind transfers to park applications */
-static ast_park_blind_xfer_fn ast_park_blind_xfer_func = NULL;
-
-/*! \brief Function Callback for handling a bridge channel trying to park itself */
-static ast_bridge_channel_park_fn ast_bridge_channel_park_func = NULL;
-
-void ast_parking_stasis_init(void)
-{
-       parked_call_type = stasis_message_type_create("ast_parked_call");
-       parking_topic = stasis_topic_create("ast_parking");
-}
+/*! \brief The container for the parking provider */
+static AO2_GLOBAL_OBJ_STATIC(parking_provider);
 
-void ast_parking_stasis_disable(void)
+static void parking_stasis_cleanup(void)
 {
-       ao2_cleanup(parked_call_type);
+       STASIS_MESSAGE_TYPE_CLEANUP(ast_parked_call_type);
        ao2_cleanup(parking_topic);
-       parked_call_type = NULL;
        parking_topic = NULL;
 }
 
-struct stasis_topic *ast_parking_topic(void)
+int ast_parking_stasis_init(void)
 {
-       return parking_topic;
+       if (STASIS_MESSAGE_TYPE_INIT(ast_parked_call_type)) {
+               return -1;
+       }
+
+       parking_topic = stasis_topic_create("ast_parking");
+       if (!parking_topic) {
+               return -1;
+       }
+       ast_register_cleanup(parking_stasis_cleanup);
+       return 0;
 }
 
-struct stasis_message_type *ast_parked_call_type(void)
+struct stasis_topic *ast_parking_topic(void)
 {
-       return parked_call_type;
+       return parking_topic;
 }
 
 /*! \brief Destructor for parked_call_payload objects */
@@ -76,12 +77,12 @@ static void parked_call_payload_destructor(void *obj)
        struct ast_parked_call_payload *park_obj = obj;
 
        ao2_cleanup(park_obj->parkee);
-       ao2_cleanup(park_obj->parker);
+       ao2_cleanup(park_obj->retriever);
        ast_string_field_free_memory(park_obj);
 }
 
 struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type,
-               struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot,
+               struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string,
                struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
                unsigned int parkingspace, unsigned long int timeout,
                unsigned long int duration)
@@ -102,11 +103,6 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c
        ao2_ref(parkee_snapshot, +1);
        payload->parkee = parkee_snapshot;
 
-       if (parker_snapshot) {
-               ao2_ref(parker_snapshot, +1);
-               payload->parker = parker_snapshot;
-       }
-
        if (retriever_snapshot) {
                ao2_ref(retriever_snapshot, +1);
                payload->retriever = retriever_snapshot;
@@ -116,6 +112,10 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c
                ast_string_field_set(payload, parkinglot, parkinglot);
        }
 
+       if (parker_dial_string) {
+               ast_string_field_set(payload, parker_dial_string, parker_dial_string);
+       }
+
        payload->parkingspace = parkingspace;
        payload->timeout = timeout;
        payload->duration = duration;
@@ -125,67 +125,125 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c
        return payload;
 }
 
-void ast_install_park_blind_xfer_func(ast_park_blind_xfer_fn park_blind_xfer_func)
+int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
 {
-       ast_park_blind_xfer_func = park_blind_xfer_func;
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       if (!table || !table->parking_park_bridge_channel) {
+               return -1;
+       }
+
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
+               return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
+       }
+
+       return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
 }
 
-void ast_install_bridge_channel_park_func(ast_bridge_channel_park_fn bridge_channel_park_func)
+int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
+       const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
+       struct transfer_channel_data *parked_channel_data)
 {
-       ast_bridge_channel_park_func = bridge_channel_park_func;
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       if (!table || !table->parking_blind_transfer_park) {
+               return -1;
+       }
+
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
+               return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
+       }
+
+       return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
 }
 
-void ast_uninstall_park_blind_xfer_func(void)
+int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
 {
-       ast_park_blind_xfer_func = NULL;
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       if (!table || !table->parking_park_call) {
+               return -1;
+       }
+
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
+               return table->parking_park_call(parker, exten, length);
+       }
+
+       return table->parking_park_call(parker, exten, length);
 }
 
-void ast_uninstall_bridge_channel_park_func(void)
+int ast_parking_is_exten_park(const char *context, const char *exten)
 {
-       ast_bridge_channel_park_func = NULL;
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       if (!table || !table->parking_is_exten_park) {
+               return -1;
+       }
+
+       if (table->module) {
+               SCOPED_MODULE_USE(table->module);
+               return table->parking_is_exten_park(context, exten);
+       }
+
+       return table->parking_is_exten_park(context, exten);
 }
 
-int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel *parker,
-               struct ast_exten *park_exten)
+int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table)
 {
-       static int warned = 0;
-       if (ast_park_blind_xfer_func) {
-               return ast_park_blind_xfer_func(bridge, parker, park_exten);
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, wrapper,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       if (fn_table->module_version != PARKING_MODULE_VERSION) {
+               ast_log(AST_LOG_WARNING, "Parking module provided incorrect parking module "
+                       "version: %u (expected: %d)\n", fn_table->module_version, PARKING_MODULE_VERSION);
+               return -1;
+       }
+
+       if (wrapper) {
+               ast_log(AST_LOG_WARNING, "Parking provider already registered by %s!\n",
+                       wrapper->module_name);
+               return -1;
        }
 
-       if (warned++ % 10 == 0) {
-               ast_verb(3, "%s attempted to blind transfer to a parking extension, but no parking blind transfer function is loaded.\n",
-                       ast_channel_name(parker->chan));
+       wrapper = ao2_alloc(sizeof(*wrapper), NULL);
+       if (!wrapper) {
+               return -1;
        }
+       *wrapper = *fn_table;
 
-       return -1;
+       ao2_global_obj_replace_unref(parking_provider, wrapper);
+       return 0;
 }
 
-struct ast_exten *ast_get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context)
+int ast_parking_unregister_bridge_features(const char *module_name)
 {
-       struct ast_exten *exten;
-       struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
-       const char *app_at_exten;
-
-       ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
-       exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
-               E_MATCH);
-       if (!exten) {
-               return NULL;
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, wrapper,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       if (!wrapper) {
+               return -1;
        }
 
-       app_at_exten = ast_get_extension_app(exten);
-       if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) {
-               return NULL;
+       if (strcmp(wrapper->module_name, module_name)) {
+               ast_log(AST_LOG_WARNING, "%s has not registered the parking provider\n", module_name);
+               return -1;
        }
 
-       return exten;
+       ao2_global_obj_release(parking_provider);
+       return 0;
 }
 
-void ast_bridge_channel_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
+int ast_parking_provider_registered(void)
 {
-       /* Run installable function */
-       if (ast_bridge_channel_park_func) {
-               return ast_bridge_channel_park_func(bridge_channel, parkee_uuid, parker_uuid, app_data);
-       }
+       RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
+               ao2_global_obj_ref(parking_provider), ao2_cleanup);
+
+       return !!table;
 }