summaryrefslogtreecommitdiff
path: root/main/cel.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/cel.c')
-rw-r--r--main/cel.c132
1 files changed, 115 insertions, 17 deletions
diff --git a/main/cel.c b/main/cel.c
index d9e1d81df..a613b7c2e 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -147,11 +147,17 @@ static struct stasis_subscription *cel_cel_forwarder;
/*! Container for primary channel/bridge ID listing for 2 party bridges */
static struct ao2_container *bridge_primaries;
+/*! The number of buckets into which bridge primary structs will be hashed */
+#define BRIDGE_PRIMARY_BUCKETS 251
+
struct stasis_message_type *cel_generic_type(void);
STASIS_MESSAGE_TYPE_DEFN(cel_generic_type);
-/*! The number of buckets into which primary channel uniqueids will be hashed */
-#define BRIDGE_PRIMARY_BUCKETS 251
+/*! Container for CEL backend information */
+static struct ao2_container *cel_backends;
+
+/*! The number of buckets into which backend names will be hashed */
+#define BACKEND_BUCKETS 13
/*! Container for dial end multichannel blobs for holding on to dial statuses */
static struct ao2_container *cel_dialstatus_store;
@@ -323,6 +329,57 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
[AST_CEL_LOCAL_OPTIMIZE] = "LOCAL_OPTIMIZE",
};
+struct cel_backend {
+ ast_cel_backend_cb callback; /*!< Callback for this backend */
+ char name[0]; /*!< Name of this backend */
+};
+
+/*! \brief Hashing function for cel_backend */
+static int cel_backend_hash(const void *obj, int flags)
+{
+ const struct cel_backend *backend;
+ const char *name;
+
+ switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+ case OBJ_POINTER:
+ backend = obj;
+ name = backend->name;
+ break;
+ case OBJ_KEY:
+ name = obj;
+ break;
+ default:
+ /* Hash can only work on something with a full key. */
+ ast_assert(0);
+ return 0;
+ }
+
+ return ast_str_hash(name);
+}
+
+/*! \brief Comparator function for cel_backend */
+static int cel_backend_cmp(void *obj, void *arg, int flags)
+{
+ struct cel_backend *backend2, *backend1 = obj;
+ const char *backend2_id, *backend1_id = backend1->name;
+
+ switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+ case OBJ_POINTER:
+ backend2 = arg;
+ backend2_id = backend2->name;
+ break;
+ case OBJ_KEY:
+ backend2_id = arg;
+ break;
+ default:
+ /* Hash can only work on something with a full key. */
+ ast_assert(0);
+ return 0;
+ }
+
+ return !strcmp(backend1_id, backend2_id) ? CMP_MATCH | CMP_STOP : 0;
+}
+
struct bridge_assoc {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(bridge_id); /*!< UniqueID of the bridge */
@@ -451,18 +508,18 @@ static int print_app(void *obj, void *arg, int flags)
return 0;
}
-static void print_cel_sub(const struct ast_event *event, void *data)
+static int event_desc_cb(void *obj, void *arg, int flags)
{
- struct ast_cli_args *a = data;
+ struct ast_cli_args *a = arg;
+ struct cel_backend *backend = obj;
- ast_cli(a->fd, "CEL Event Subscriber: %s\n",
- ast_event_get_ie_str(event, AST_EVENT_IE_DESCRIPTION));
+ ast_cli(a->fd, "CEL Event Subscriber: %s\n", backend->name);
+ return 0;
}
static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
unsigned int i;
- struct ast_event_sub *sub;
RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
switch (cmd) {
@@ -506,14 +563,7 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
}
ao2_callback(cfg->general->apps, OBJ_NODATA, print_app, a);
-
- if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
- return CLI_FAILURE;
- }
- ast_event_sub_append_ie_uint(sub, AST_EVENT_IE_EVENTTYPE, AST_EVENT_CEL);
- ast_event_report_subs(sub);
- ast_event_sub_destroy(sub);
- sub = NULL;
+ ao2_callback(cel_backends, OBJ_MULTIPLE | OBJ_NODATA, event_desc_cb, a);
return CLI_SUCCESS;
}
@@ -668,6 +718,14 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
AST_EVENT_IE_END);
}
+static int cel_backend_send_cb(void *obj, void *arg, int flags)
+{
+ struct cel_backend *backend = obj;
+
+ backend->callback(arg);
+ return 0;
+}
+
static int cel_report_event(struct ast_channel_snapshot *snapshot,
enum ast_cel_event_type event_type, const char *userdefevname,
struct ast_json *extra, const char *peer2_name)
@@ -711,11 +769,14 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
}
ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra, peer_name);
- if (ev && ast_event_queue(ev)) {
- ast_event_destroy(ev);
+ if (!ev) {
return -1;
}
+ /* Distribute event to backends */
+ ao2_callback(cel_backends, OBJ_MULTIPLE | OBJ_NODATA, cel_backend_send_cb, ev);
+ ast_event_destroy(ev);
+
return 0;
}
@@ -1543,6 +1604,11 @@ int ast_cel_engine_init(void)
return -1;
}
+ cel_backends = ao2_container_alloc(BACKEND_BUCKETS, cel_backend_hash, cel_backend_cmp);
+ if (!cel_backends) {
+ return -1;
+ }
+
cel_aggregation_topic = stasis_topic_create("cel_aggregation_topic");
if (!cel_aggregation_topic) {
return -1;
@@ -1702,3 +1768,35 @@ void ast_cel_set_config(struct ast_cel_general_config *config)
ao2_ref(mod_cfg->general, +1);
}
+int ast_cel_backend_unregister(const char *name)
+{
+ RAII_VAR(struct cel_backend *, backend, NULL, ao2_cleanup);
+
+ backend = ao2_find(cel_backends, name, OBJ_KEY | OBJ_UNLINK);
+ if (!backend) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
+{
+ RAII_VAR(struct cel_backend *, backend, NULL, ao2_cleanup);
+
+ if (ast_strlen_zero(name)) {
+ return -1;
+ }
+
+ backend = ao2_alloc(sizeof(*backend) + 1 + strlen(name), NULL);
+ if (!backend) {
+ return -1;
+ }
+
+ /* safe strcpy */
+ strcpy(backend->name, name);
+ backend->callback = backend_callback;
+ ao2_link(cel_backends, backend);
+
+ return 0;
+}