Usage of the SAForum AIS (Application Interface Specification) More...
#include "asterisk.h"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <errno.h>#include "ais.h"#include "asterisk/module.h"#include "asterisk/utils.h"#include "asterisk/cli.h"#include "asterisk/logger.h"#include "asterisk/event.h"#include "asterisk/config.h"#include "asterisk/linkedlists.h"#include "asterisk/devicestate.h"
Go to the source code of this file.
Data Structures | |
| struct | event_channel |
| struct | event_channels |
| struct | publish_event |
| struct | subscribe_event |
Defines | |
| #define | AST_MODULE "res_ais" |
Functions | |
| static void | add_publish_event (struct event_channel *event_channel, const char *event_type) |
| static void | add_subscribe_event (struct event_channel *event_channel, const char *event_type) |
| static char * | ais_evt_show_event_channels (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| int | ast_ais_evt_load_module (void) |
| int | ast_ais_evt_unload_module (void) |
| static void | ast_event_cb (const struct ast_event *ast_event, void *data) |
| ASTERISK_FILE_VERSION (__FILE__,"$Revision: 335497 $") | |
| static void | build_event_channel (struct ast_config *cfg, const char *cat) |
| static void | destroy_event_channels (void) |
| static void | event_channel_destroy (struct event_channel *event_channel) |
| void | evt_channel_open_cb (SaInvocationT invocation, SaEvtChannelHandleT channel_handle, SaAisErrorT error) |
| void | evt_event_deliver_cb (SaEvtSubscriptionIdT subscription_id, const SaEvtEventHandleT event_handle, const SaSizeT event_datalen) |
| static void | load_config (void) |
| static void | publish_event_destroy (struct publish_event *publish_event) |
| static void | queue_event (struct ast_event *ast_event) |
| static SaAisErrorT | set_egress_subscription (struct event_channel *event_channel, struct subscribe_event *subscribe_event) |
| static void | subscribe_event_destroy (const struct event_channel *event_channel, struct subscribe_event *subscribe_event) |
| static const char * | type_to_filter_str (enum ast_event_type type) |
Variables | |
| static struct ast_cli_entry | ais_cli [] |
| static struct event_channels | event_channels |
| static const SaEvtCallbacksT | evt_callbacks |
| SaEvtHandleT | evt_handle |
| static SaAisErrorT | evt_init_res |
| struct { | |
| const char * str | |
| enum ast_event_type type | |
| } | supported_event_types [] |
| static int | unique_id |
Usage of the SAForum AIS (Application Interface Specification)
This file contains the code specific to the use of the EVT (Event) Service.
Definition in file evt.c.
| static void add_publish_event | ( | struct event_channel * | event_channel, |
| const char * | event_type | ||
| ) | [static] |
Definition at line 308 of file evt.c.
References ARRAY_LEN, ast_calloc, ast_enable_distributed_devstate(), ast_event_cb(), AST_EVENT_DEVICE_STATE_CHANGE, ast_event_dump_cache(), AST_EVENT_IE_END, ast_event_subscribe(), AST_LIST_INSERT_TAIL, ast_log(), LOG_DEBUG, LOG_WARNING, event_channel::publish_events, str, publish_event::sub, supported_event_types, subscribe_event::type, and publish_event::type.
Referenced by build_event_channel().
{
int i;
enum ast_event_type type = -1;
struct publish_event *publish_event;
for (i = 0; i < ARRAY_LEN(supported_event_types); i++) {
if (!strcasecmp(event_type, supported_event_types[i].str)) {
type = supported_event_types[i].type;
break;
}
}
if (type == -1) {
ast_log(LOG_WARNING, "publish_event option given with invalid value '%s'\n", event_type);
return;
}
if (type == AST_EVENT_DEVICE_STATE_CHANGE && ast_enable_distributed_devstate()) {
return;
}
if (!(publish_event = ast_calloc(1, sizeof(*publish_event)))) {
return;
}
publish_event->type = type;
ast_log(LOG_DEBUG, "Subscribing to event type %d\n", type);
publish_event->sub = ast_event_subscribe(type, ast_event_cb, "AIS", event_channel,
AST_EVENT_IE_END);
ast_event_dump_cache(publish_event->sub);
AST_LIST_INSERT_TAIL(&event_channel->publish_events, publish_event, entry);
}
| static void add_subscribe_event | ( | struct event_channel * | event_channel, |
| const char * | event_type | ||
| ) | [static] |
Definition at line 370 of file evt.c.
References ais_err2str(), ARRAY_LEN, ast_atomic_fetchadd_int(), ast_calloc, ast_enable_distributed_devstate(), AST_EVENT_DEVICE_STATE_CHANGE, AST_LIST_INSERT_TAIL, ast_log(), free, subscribe_event::id, LOG_ERROR, LOG_WARNING, set_egress_subscription(), str, event_channel::subscribe_events, supported_event_types, subscribe_event::type, and unique_id.
Referenced by build_event_channel().
{
int i;
enum ast_event_type type = -1;
struct subscribe_event *subscribe_event;
SaAisErrorT ais_res;
for (i = 0; i < ARRAY_LEN(supported_event_types); i++) {
if (!strcasecmp(event_type, supported_event_types[i].str)) {
type = supported_event_types[i].type;
break;
}
}
if (type == -1) {
ast_log(LOG_WARNING, "subscribe_event option given with invalid value '%s'\n", event_type);
return;
}
if (type == AST_EVENT_DEVICE_STATE_CHANGE && ast_enable_distributed_devstate()) {
return;
}
if (!(subscribe_event = ast_calloc(1, sizeof(*subscribe_event)))) {
return;
}
subscribe_event->type = type;
subscribe_event->id = ast_atomic_fetchadd_int(&unique_id, +1);
ais_res = set_egress_subscription(event_channel, subscribe_event);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error setting up egress subscription: %s\n",
ais_err2str(ais_res));
free(subscribe_event);
return;
}
AST_LIST_INSERT_TAIL(&event_channel->subscribe_events, subscribe_event, entry);
}
| static char* ais_evt_show_event_channels | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 250 of file evt.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, event_channel::name, event_channel::publish_events, event_channel::subscribe_events, subscribe_event::type, publish_event::type, type_to_filter_str(), and ast_cli_entry::usage.
{
struct event_channel *event_channel;
switch (cmd) {
case CLI_INIT:
e->command = "ais evt show event channels";
e->usage =
"Usage: ais evt show event channels\n"
" List configured event channels for the (EVT) Eventing service.\n";
return NULL;
case CLI_GENERATE:
return NULL; /* no completion */
}
if (a->argc != e->args)
return CLI_SHOWUSAGE;
ast_cli(a->fd, "\n"
"=============================================================\n"
"=== Event Channels ==========================================\n"
"=============================================================\n"
"===\n");
AST_RWLIST_RDLOCK(&event_channels);
AST_RWLIST_TRAVERSE(&event_channels, event_channel, entry) {
struct publish_event *publish_event;
struct subscribe_event *subscribe_event;
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
"=== Event Channel Name: %s\n", event_channel->name);
AST_LIST_TRAVERSE(&event_channel->publish_events, publish_event, entry) {
ast_cli(a->fd, "=== ==> Publishing Event Type: %s\n",
type_to_filter_str(publish_event->type));
}
AST_LIST_TRAVERSE(&event_channel->subscribe_events, subscribe_event, entry) {
ast_cli(a->fd, "=== ==> Subscribing to Event Type: %s\n",
type_to_filter_str(subscribe_event->type));
}
ast_cli(a->fd, "=== ---------------------------------------------------------\n"
"===\n");
}
AST_RWLIST_UNLOCK(&event_channels);
ast_cli(a->fd, "=============================================================\n"
"\n");
return CLI_SUCCESS;
}
| int ast_ais_evt_load_module | ( | void | ) |
Definition at line 549 of file evt.c.
References ais_err2str(), ais_version, ARRAY_LEN, ast_cli_register_multiple(), ast_log(), evt_callbacks, evt_handle, evt_init_res, load_config(), and LOG_ERROR.
Referenced by load_module().
{
evt_init_res = saEvtInitialize(&evt_handle, &evt_callbacks, &ais_version);
if (evt_init_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Could not initialize eventing service: %s\n",
ais_err2str(evt_init_res));
return -1;
}
load_config();
ast_cli_register_multiple(ais_cli, ARRAY_LEN(ais_cli));
return 0;
}
| int ast_ais_evt_unload_module | ( | void | ) |
Definition at line 565 of file evt.c.
References ais_err2str(), ast_log(), destroy_event_channels(), evt_handle, evt_init_res, and LOG_ERROR.
Referenced by load_module(), and unload_module().
{
SaAisErrorT ais_res;
if (evt_init_res != SA_AIS_OK) {
return 0;
}
destroy_event_channels();
ais_res = saEvtFinalize(evt_handle);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Problem stopping eventing service: %s\n",
ais_err2str(ais_res));
return -1;
}
return 0;
}
| static void ast_event_cb | ( | const struct ast_event * | ast_event, |
| void * | data | ||
| ) | [static] |
/todo Make retention time configurable /todo Make event priorities configurable
Definition at line 180 of file evt.c.
References ais_err2str(), ast_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), ast_event_get_size(), ast_event_get_type(), AST_EVENT_IE_EID, ast_log(), clm_handle, event_channel::handle, len(), LOG_DEBUG, LOG_ERROR, and type_to_filter_str().
Referenced by add_publish_event().
{
SaEvtEventHandleT event_handle;
SaAisErrorT ais_res;
struct event_channel *event_channel = data;
SaClmClusterNodeT local_node;
SaEvtEventPatternArrayT pattern_array;
SaEvtEventPatternT pattern;
SaSizeT len;
const char *filter_str;
SaEvtEventIdT event_id;
ast_log(LOG_DEBUG, "Got an event to forward\n");
if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
/* If the event didn't originate from this server, don't send it back out. */
ast_log(LOG_DEBUG, "Returning here\n");
return;
}
ais_res = saEvtEventAllocate(event_channel->handle, &event_handle);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error allocating event: %s\n", ais_err2str(ais_res));
ast_log(LOG_DEBUG, "Returning here\n");
return;
}
ais_res = saClmClusterNodeGet(clm_handle, SA_CLM_LOCAL_NODE_ID,
SA_TIME_ONE_SECOND, &local_node);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error getting local node name: %s\n", ais_err2str(ais_res));
goto return_event_free;
}
filter_str = type_to_filter_str(ast_event_get_type(ast_event));
len = strlen(filter_str) + 1;
pattern.pattern = (SaUint8T *) filter_str;
pattern.patternSize = len;
pattern.allocatedSize = len;
pattern_array.allocatedNumber = 1;
pattern_array.patternsNumber = 1;
pattern_array.patterns = &pattern;
/*!
* /todo Make retention time configurable
* /todo Make event priorities configurable
*/
ais_res = saEvtEventAttributesSet(event_handle, &pattern_array,
SA_EVT_LOWEST_PRIORITY, SA_TIME_ONE_MINUTE, &local_node.nodeName);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error setting event attributes: %s\n", ais_err2str(ais_res));
goto return_event_free;
}
ais_res = saEvtEventPublish(event_handle,
ast_event, ast_event_get_size(ast_event), &event_id);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error publishing event: %s\n", ais_err2str(ais_res));
goto return_event_free;
}
return_event_free:
ais_res = saEvtEventFree(event_handle);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error freeing allocated event: %s\n", ais_err2str(ais_res));
}
ast_log(LOG_DEBUG, "Returning here (event_free)\n");
}
| ASTERISK_FILE_VERSION | ( | __FILE__ | , |
| "$Revision: 335497 $" | |||
| ) |
| static void build_event_channel | ( | struct ast_config * | cfg, |
| const char * | cat | ||
| ) | [static] |
Definition at line 411 of file evt.c.
References add_publish_event(), add_subscribe_event(), ais_err2str(), ast_calloc, ast_copy_string(), ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_variable_browse(), evt_handle, free, event_channel::handle, LOG_ERROR, LOG_WARNING, ast_variable::name, event_channel::name, ast_variable::next, ast_variable::value, and var.
Referenced by load_config().
{
struct ast_variable *var;
struct event_channel *event_channel;
SaAisErrorT ais_res;
SaNameT sa_name = { 0, };
AST_RWLIST_WRLOCK(&event_channels);
AST_RWLIST_TRAVERSE(&event_channels, event_channel, entry) {
if (!strcasecmp(event_channel->name, cat))
break;
}
AST_RWLIST_UNLOCK(&event_channels);
if (event_channel) {
ast_log(LOG_WARNING, "Event channel '%s' was specified twice in "
"configuration. Second instance ignored.\n", cat);
return;
}
if (!(event_channel = ast_calloc(1, sizeof(*event_channel) + strlen(cat))))
return;
strcpy(event_channel->name, cat);
ast_copy_string((char *) sa_name.value, cat, sizeof(sa_name.value));
sa_name.length = strlen((char *) sa_name.value);
ais_res = saEvtChannelOpen(evt_handle, &sa_name,
SA_EVT_CHANNEL_PUBLISHER | SA_EVT_CHANNEL_SUBSCRIBER | SA_EVT_CHANNEL_CREATE,
SA_TIME_MAX, &event_channel->handle);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error opening event channel: %s\n", ais_err2str(ais_res));
free(event_channel);
return;
}
for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
if (!strcasecmp(var->name, "type")) {
continue;
} else if (!strcasecmp(var->name, "publish_event")) {
add_publish_event(event_channel, var->value);
} else if (!strcasecmp(var->name, "subscribe_event")) {
add_subscribe_event(event_channel, var->value);
} else {
ast_log(LOG_WARNING, "Event channel '%s' contains invalid option '%s'\n",
event_channel->name, var->name);
}
}
AST_RWLIST_WRLOCK(&event_channels);
AST_RWLIST_INSERT_TAIL(&event_channels, event_channel, entry);
AST_RWLIST_UNLOCK(&event_channels);
}
| static void destroy_event_channels | ( | void | ) | [static] |
Definition at line 538 of file evt.c.
References AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and event_channel_destroy().
Referenced by ast_ais_evt_unload_module().
{
struct event_channel *event_channel;
AST_RWLIST_WRLOCK(&event_channels);
while ((event_channel = AST_RWLIST_REMOVE_HEAD(&event_channels, entry))) {
event_channel_destroy(event_channel);
}
AST_RWLIST_UNLOCK(&event_channels);
}
| static void event_channel_destroy | ( | struct event_channel * | event_channel | ) | [static] |
Definition at line 518 of file evt.c.
References ais_err2str(), AST_LIST_REMOVE_HEAD, ast_log(), free, event_channel::handle, LOG_ERROR, event_channel::name, publish_event_destroy(), event_channel::publish_events, subscribe_event_destroy(), and event_channel::subscribe_events.
Referenced by destroy_event_channels().
{
struct publish_event *publish_event;
struct subscribe_event *subscribe_event;
SaAisErrorT ais_res;
while ((publish_event = AST_LIST_REMOVE_HEAD(&event_channel->publish_events, entry)))
publish_event_destroy(publish_event);
while ((subscribe_event = AST_LIST_REMOVE_HEAD(&event_channel->subscribe_events, entry)))
subscribe_event_destroy(event_channel, subscribe_event);
ais_res = saEvtChannelClose(event_channel->handle);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error closing event channel '%s': %s\n",
event_channel->name, ais_err2str(ais_res));
}
free(event_channel);
}
| void evt_channel_open_cb | ( | SaInvocationT | invocation, |
| SaEvtChannelHandleT | channel_handle, | ||
| SaAisErrorT | error | ||
| ) |
| void evt_event_deliver_cb | ( | SaEvtSubscriptionIdT | subscription_id, |
| const SaEvtEventHandleT | event_handle, | ||
| const SaSizeT | event_datalen | ||
| ) |
Definition at line 119 of file evt.c.
References ais_err2str(), ast_debug, ast_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), AST_EVENT_IE_EID, ast_event_minimum_length(), ast_log(), ast_malloc, len(), LOG_ERROR, and queue_event().
{
/* It is important to note that this works because we *know* that this
* function will only be called by a single thread, the dispatch_thread.
* If this module gets changed such that this is no longer the case, this
* should get changed to a thread-local buffer, instead. */
static unsigned char buf[4096];
struct ast_event *event_dup, *event = (void *) buf;
SaAisErrorT ais_res;
SaSizeT len = sizeof(buf);
if (event_datalen > len) {
ast_log(LOG_ERROR, "Event received with size %u, which is too big\n"
"for the allocated size %u. Change the code to increase the size.\n",
(unsigned int) event_datalen, (unsigned int) len);
return;
}
if (event_datalen < ast_event_minimum_length()) {
ast_debug(1, "Ignoring event that's too small. %u < %u\n",
(unsigned int) event_datalen,
(unsigned int) ast_event_minimum_length());
return;
}
ais_res = saEvtEventDataGet(event_handle, event, &len);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error retrieving event payload: %s\n",
ais_err2str(ais_res));
return;
}
if (!ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
/* Don't feed events back in that originated locally. */
return;
}
if (!(event_dup = ast_malloc(len)))
return;
memcpy(event_dup, event, len);
queue_event(event_dup);
}
| static void load_config | ( | void | ) | [static] |
Definition at line 463 of file evt.c.
References ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log(), ast_variable_retrieve(), build_event_channel(), CONFIG_STATUS_FILEINVALID, LOG_WARNING, and subscribe_event::type.
Referenced by ast_ais_evt_load_module().
{
static const char filename[] = "ais.conf";
struct ast_config *cfg;
const char *cat = NULL;
struct ast_flags config_flags = { 0 };
if (!(cfg = ast_config_load(filename, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID)
return;
while ((cat = ast_category_browse(cfg, cat))) {
const char *type;
if (!strcasecmp(cat, "general"))
continue;
if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
filename);
continue;
}
if (!strcasecmp(type, "event_channel")) {
build_event_channel(cfg, cat);
} else {
ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'\n",
filename, type);
}
}
ast_config_destroy(cfg);
}
| static void publish_event_destroy | ( | struct publish_event * | publish_event | ) | [static] |
Definition at line 496 of file evt.c.
References ast_event_unsubscribe(), free, and publish_event::sub.
Referenced by event_channel_destroy().
{
ast_event_unsubscribe(publish_event->sub);
free(publish_event);
}
| static void queue_event | ( | struct ast_event * | ast_event | ) | [static] |
Definition at line 114 of file evt.c.
References ast_event_queue_and_cache().
Referenced by evt_event_deliver_cb().
{
ast_event_queue_and_cache(ast_event);
}
| static SaAisErrorT set_egress_subscription | ( | struct event_channel * | event_channel, |
| struct subscribe_event * | subscribe_event | ||
| ) | [static] |
Definition at line 343 of file evt.c.
References filter(), event_channel::handle, subscribe_event::id, len(), subscribe_event::type, and type_to_filter_str().
Referenced by add_subscribe_event().
{
SaAisErrorT ais_res;
SaEvtEventFilterArrayT filter_array;
SaEvtEventFilterT filter;
const char *filter_str = NULL;
SaSizeT len;
/* We know it's going to be valid. It was checked earlier. */
filter_str = type_to_filter_str(subscribe_event->type);
filter.filterType = SA_EVT_EXACT_FILTER;
len = strlen(filter_str) + 1;
filter.filter.allocatedSize = len;
filter.filter.patternSize = len;
filter.filter.pattern = (SaUint8T *) filter_str;
filter_array.filtersNumber = 1;
filter_array.filters = &filter;
ais_res = saEvtEventSubscribe(event_channel->handle, &filter_array,
subscribe_event->id);
return ais_res;
}
| static void subscribe_event_destroy | ( | const struct event_channel * | event_channel, |
| struct subscribe_event * | subscribe_event | ||
| ) | [static] |
Definition at line 503 of file evt.c.
References ais_err2str(), ast_log(), free, event_channel::handle, subscribe_event::id, and LOG_ERROR.
Referenced by event_channel_destroy().
{
SaAisErrorT ais_res;
/* saEvtChannelClose() will actually do this automatically, but it just
* feels cleaner to go ahead and do it manually ... */
ais_res = saEvtEventUnsubscribe(event_channel->handle, subscribe_event->id);
if (ais_res != SA_AIS_OK) {
ast_log(LOG_ERROR, "Error unsubscribing: %s\n", ais_err2str(ais_res));
}
free(subscribe_event);
}
| static const char* type_to_filter_str | ( | enum ast_event_type | type | ) | [static] |
Definition at line 165 of file evt.c.
References ARRAY_LEN, and supported_event_types.
Referenced by ais_evt_show_event_channels(), ast_event_cb(), and set_egress_subscription().
{
const char *filter_str = NULL;
int i;
for (i = 0; i < ARRAY_LEN(supported_event_types); i++) {
if (supported_event_types[i].type == type) {
filter_str = supported_event_types[i].str;
break;
}
}
return filter_str;
}
struct ast_cli_entry ais_cli[] [static] |
{
AST_CLI_DEFINE(ais_evt_show_event_channels, "Show configured event channels"),
}
struct event_channels event_channels [static] |
const SaEvtCallbacksT evt_callbacks [static] |
{
.saEvtChannelOpenCallback = evt_channel_open_cb,
.saEvtEventDeliverCallback = evt_event_deliver_cb,
}
Definition at line 65 of file evt.c.
Referenced by ast_ais_evt_load_module().
| SaEvtHandleT evt_handle |
Definition at line 57 of file evt.c.
Referenced by ast_ais_evt_load_module(), ast_ais_evt_unload_module(), build_event_channel(), and dispatch_thread_handler().
SaAisErrorT evt_init_res [static] |
Definition at line 58 of file evt.c.
Referenced by ast_ais_evt_load_module(), and ast_ais_evt_unload_module().
struct { ... } supported_event_types[] [static] |
Referenced by add_publish_event(), add_subscribe_event(), and type_to_filter_str().
| enum ast_event_type type |
int unique_id [static] |
Used to provide unique id's to egress subscriptions
Definition at line 79 of file evt.c.
Referenced by add_subscribe_event().