Thu Apr 28 2011 16:57:09

Asterisk developer's documentation


evt.c File Reference

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"
Include dependency graph for evt.c:

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 __fini_event_channels (void)
static void __init_event_channels (void)
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: 271869 $")
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

Detailed Description

Usage of the SAForum AIS (Application Interface Specification)

Author:
Russell Bryant <russell@digium.com>

This file contains the code specific to the use of the EVT (Event) Service.

Definition in file evt.c.


Define Documentation

#define AST_MODULE   "res_ais"

Definition at line 54 of file evt.c.


Function Documentation

static void __fini_event_channels ( void  ) [static]

Definition at line 106 of file evt.c.

{
static void __init_event_channels ( void  ) [static]

Definition at line 106 of file evt.c.

{
static void add_publish_event ( struct event_channel event_channel,
const char *  event_type 
) [static]

Definition at line 301 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, 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 363 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 243 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 show evt event channels";
      e->usage =
         "Usage: ais show evt 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 542 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 558 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 173 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: 271869 $"   
)
static void build_event_channel ( struct ast_config cfg,
const char *  cat 
) [static]

Definition at line 404 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]
static void event_channel_destroy ( struct event_channel event_channel) [static]

Definition at line 511 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 
)

Definition at line 108 of file evt.c.

{

}
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_eid_cmp(), ast_eid_default, ast_event_get_ie_raw(), AST_EVENT_IE_EID, ast_log(), ast_malloc, buf, 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;
   }

   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 456 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 489 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 ast_event_queue_and_cache(), and 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 336 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 496 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 158 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;
}

Variable Documentation

struct ast_cli_entry ais_cli[] [static]
Initial value:
 {
   AST_CLI_DEFINE(ais_evt_show_event_channels, "Show configured event channels"),
}

Definition at line 297 of file evt.c.

struct event_channels event_channels [static]
const SaEvtCallbacksT evt_callbacks [static]
Initial value:
 {
   .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().

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().

const char* str

Definition at line 71 of file evt.c.

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().