00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 359053 $");
00034
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <unistd.h>
00039 #include <errno.h>
00040
00041 #include "ais.h"
00042
00043 #include "asterisk/module.h"
00044 #include "asterisk/utils.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/event.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/linkedlists.h"
00050 #include "asterisk/devicestate.h"
00051
00052 #ifndef AST_MODULE
00053
00054 #define AST_MODULE "res_ais"
00055 #endif
00056
00057 SaEvtHandleT evt_handle;
00058 static SaAisErrorT evt_init_res;
00059
00060 void evt_channel_open_cb(SaInvocationT invocation, SaEvtChannelHandleT channel_handle,
00061 SaAisErrorT error);
00062 void evt_event_deliver_cb(SaEvtSubscriptionIdT subscription_id,
00063 const SaEvtEventHandleT event_handle, const SaSizeT event_datalen);
00064
00065 static const SaEvtCallbacksT evt_callbacks = {
00066 .saEvtChannelOpenCallback = evt_channel_open_cb,
00067 .saEvtEventDeliverCallback = evt_event_deliver_cb,
00068 };
00069
00070 static const struct {
00071 const char *str;
00072 enum ast_event_type type;
00073 } supported_event_types[] = {
00074 { "mwi", AST_EVENT_MWI },
00075 { "device_state", AST_EVENT_DEVICE_STATE_CHANGE },
00076 };
00077
00078
00079 static int unique_id;
00080
00081 struct subscribe_event {
00082 AST_LIST_ENTRY(subscribe_event) entry;
00083
00084
00085
00086 SaEvtSubscriptionIdT id;
00087 enum ast_event_type type;
00088 };
00089
00090 struct publish_event {
00091 AST_LIST_ENTRY(publish_event) entry;
00092
00093
00094 struct ast_event_sub *sub;
00095 enum ast_event_type type;
00096 };
00097
00098 struct event_channel {
00099 AST_RWLIST_ENTRY(event_channel) entry;
00100 AST_LIST_HEAD_NOLOCK(, subscribe_event) subscribe_events;
00101 AST_LIST_HEAD_NOLOCK(, publish_event) publish_events;
00102 SaEvtChannelHandleT handle;
00103 char name[1];
00104 };
00105
00106 static AST_RWLIST_HEAD_STATIC(event_channels, event_channel);
00107
00108 void evt_channel_open_cb(SaInvocationT invocation, SaEvtChannelHandleT channel_handle,
00109 SaAisErrorT error)
00110 {
00111
00112 }
00113
00114 static void queue_event(struct ast_event *ast_event)
00115 {
00116 ast_event_queue_and_cache(ast_event);
00117 }
00118
00119 void evt_event_deliver_cb(SaEvtSubscriptionIdT sub_id,
00120 const SaEvtEventHandleT event_handle, const SaSizeT event_datalen)
00121 {
00122
00123
00124
00125
00126 static unsigned char buf[4096];
00127 struct ast_event *event_dup, *event = (void *) buf;
00128 SaAisErrorT ais_res;
00129 SaSizeT len = sizeof(buf);
00130
00131 if (event_datalen > len) {
00132 ast_log(LOG_ERROR, "Event received with size %u, which is too big\n"
00133 "for the allocated size %u. Change the code to increase the size.\n",
00134 (unsigned int) event_datalen, (unsigned int) len);
00135 return;
00136 }
00137
00138 if (event_datalen < ast_event_minimum_length()) {
00139 ast_debug(1, "Ignoring event that's too small. %u < %u\n",
00140 (unsigned int) event_datalen,
00141 (unsigned int) ast_event_minimum_length());
00142 return;
00143 }
00144
00145 ais_res = saEvtEventDataGet(event_handle, event, &len);
00146 if (ais_res != SA_AIS_OK) {
00147 ast_log(LOG_ERROR, "Error retrieving event payload: %s\n",
00148 ais_err2str(ais_res));
00149 return;
00150 }
00151
00152 if (!ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
00153
00154 return;
00155 }
00156
00157 if (!(event_dup = ast_malloc(len)))
00158 return;
00159
00160 memcpy(event_dup, event, len);
00161
00162 queue_event(event_dup);
00163 }
00164
00165 static const char *type_to_filter_str(enum ast_event_type type)
00166 {
00167 const char *filter_str = NULL;
00168 int i;
00169
00170 for (i = 0; i < ARRAY_LEN(supported_event_types); i++) {
00171 if (supported_event_types[i].type == type) {
00172 filter_str = supported_event_types[i].str;
00173 break;
00174 }
00175 }
00176
00177 return filter_str;
00178 }
00179
00180 static void ast_event_cb(const struct ast_event *ast_event, void *data)
00181 {
00182 SaEvtEventHandleT event_handle;
00183 SaAisErrorT ais_res;
00184 struct event_channel *event_channel = data;
00185 SaClmClusterNodeT local_node;
00186 SaEvtEventPatternArrayT pattern_array;
00187 SaEvtEventPatternT pattern;
00188 SaSizeT len;
00189 const char *filter_str;
00190 SaEvtEventIdT event_id;
00191
00192 ast_log(LOG_DEBUG, "Got an event to forward\n");
00193
00194 if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) {
00195
00196 ast_log(LOG_DEBUG, "Returning here\n");
00197 return;
00198 }
00199
00200 ais_res = saEvtEventAllocate(event_channel->handle, &event_handle);
00201 if (ais_res != SA_AIS_OK) {
00202 ast_log(LOG_ERROR, "Error allocating event: %s\n", ais_err2str(ais_res));
00203 ast_log(LOG_DEBUG, "Returning here\n");
00204 return;
00205 }
00206
00207 ais_res = saClmClusterNodeGet(clm_handle, SA_CLM_LOCAL_NODE_ID,
00208 SA_TIME_ONE_SECOND, &local_node);
00209 if (ais_res != SA_AIS_OK) {
00210 ast_log(LOG_ERROR, "Error getting local node name: %s\n", ais_err2str(ais_res));
00211 goto return_event_free;
00212 }
00213
00214 filter_str = type_to_filter_str(ast_event_get_type(ast_event));
00215 len = strlen(filter_str) + 1;
00216 pattern.pattern = (SaUint8T *) filter_str;
00217 pattern.patternSize = len;
00218 pattern.allocatedSize = len;
00219
00220 pattern_array.allocatedNumber = 1;
00221 pattern_array.patternsNumber = 1;
00222 pattern_array.patterns = &pattern;
00223
00224
00225
00226
00227
00228 ais_res = saEvtEventAttributesSet(event_handle, &pattern_array,
00229 SA_EVT_LOWEST_PRIORITY, SA_TIME_ONE_MINUTE, &local_node.nodeName);
00230 if (ais_res != SA_AIS_OK) {
00231 ast_log(LOG_ERROR, "Error setting event attributes: %s\n", ais_err2str(ais_res));
00232 goto return_event_free;
00233 }
00234
00235 for (;;) {
00236 ais_res = saEvtEventPublish(event_handle,
00237 ast_event, ast_event_get_size(ast_event), &event_id);
00238 if (ais_res != SA_AIS_ERR_TRY_AGAIN) {
00239 break;
00240 }
00241 sched_yield();
00242 }
00243
00244 if (ais_res != SA_AIS_OK) {
00245 ast_log(LOG_ERROR, "Error publishing event: %s\n", ais_err2str(ais_res));
00246 goto return_event_free;
00247 }
00248
00249 return_event_free:
00250 ais_res = saEvtEventFree(event_handle);
00251 if (ais_res != SA_AIS_OK) {
00252 ast_log(LOG_ERROR, "Error freeing allocated event: %s\n", ais_err2str(ais_res));
00253 }
00254 ast_log(LOG_DEBUG, "Returning here (event_free)\n");
00255 }
00256
00257 static char *ais_evt_show_event_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00258 {
00259 struct event_channel *event_channel;
00260
00261 switch (cmd) {
00262 case CLI_INIT:
00263 e->command = "ais evt show event channels";
00264 e->usage =
00265 "Usage: ais evt show event channels\n"
00266 " List configured event channels for the (EVT) Eventing service.\n";
00267 return NULL;
00268
00269 case CLI_GENERATE:
00270 return NULL;
00271 }
00272
00273 if (a->argc != e->args)
00274 return CLI_SHOWUSAGE;
00275
00276 ast_cli(a->fd, "\n"
00277 "=============================================================\n"
00278 "=== Event Channels ==========================================\n"
00279 "=============================================================\n"
00280 "===\n");
00281
00282 AST_RWLIST_RDLOCK(&event_channels);
00283 AST_RWLIST_TRAVERSE(&event_channels, event_channel, entry) {
00284 struct publish_event *publish_event;
00285 struct subscribe_event *subscribe_event;
00286
00287 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
00288 "=== Event Channel Name: %s\n", event_channel->name);
00289
00290 AST_LIST_TRAVERSE(&event_channel->publish_events, publish_event, entry) {
00291 ast_cli(a->fd, "=== ==> Publishing Event Type: %s\n",
00292 type_to_filter_str(publish_event->type));
00293 }
00294
00295 AST_LIST_TRAVERSE(&event_channel->subscribe_events, subscribe_event, entry) {
00296 ast_cli(a->fd, "=== ==> Subscribing to Event Type: %s\n",
00297 type_to_filter_str(subscribe_event->type));
00298 }
00299
00300 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
00301 "===\n");
00302 }
00303 AST_RWLIST_UNLOCK(&event_channels);
00304
00305 ast_cli(a->fd, "=============================================================\n"
00306 "\n");
00307
00308 return CLI_SUCCESS;
00309 }
00310
00311 static struct ast_cli_entry ais_cli[] = {
00312 AST_CLI_DEFINE(ais_evt_show_event_channels, "Show configured event channels"),
00313 };
00314
00315 void ast_ais_evt_membership_changed(void)
00316 {
00317 struct event_channel *ec;
00318
00319 AST_RWLIST_RDLOCK(&event_channels);
00320 AST_RWLIST_TRAVERSE(&event_channels, ec, entry) {
00321 struct publish_event *pe;
00322
00323 AST_LIST_TRAVERSE(&ec->publish_events, pe, entry) {
00324 ast_debug(1, "Dumping cache for event channel '%s'\n", ec->name);
00325 ast_event_dump_cache(pe->sub);
00326 }
00327 }
00328 AST_RWLIST_UNLOCK(&event_channels);
00329 }
00330
00331 static void add_publish_event(struct event_channel *event_channel, const char *event_type)
00332 {
00333 int i;
00334 enum ast_event_type type = -1;
00335 struct publish_event *publish_event;
00336
00337 for (i = 0; i < ARRAY_LEN(supported_event_types); i++) {
00338 if (!strcasecmp(event_type, supported_event_types[i].str)) {
00339 type = supported_event_types[i].type;
00340 break;
00341 }
00342 }
00343
00344 if (type == -1) {
00345 ast_log(LOG_WARNING, "publish_event option given with invalid value '%s'\n", event_type);
00346 return;
00347 }
00348
00349 if (type == AST_EVENT_DEVICE_STATE_CHANGE && ast_enable_distributed_devstate()) {
00350 return;
00351 }
00352
00353 if (!(publish_event = ast_calloc(1, sizeof(*publish_event)))) {
00354 return;
00355 }
00356
00357 publish_event->type = type;
00358 ast_log(LOG_DEBUG, "Subscribing to event type %d\n", type);
00359 publish_event->sub = ast_event_subscribe(type, ast_event_cb, "AIS", event_channel,
00360 AST_EVENT_IE_END);
00361 ast_event_dump_cache(publish_event->sub);
00362
00363 AST_LIST_INSERT_TAIL(&event_channel->publish_events, publish_event, entry);
00364 }
00365
00366 static SaAisErrorT set_egress_subscription(struct event_channel *event_channel,
00367 struct subscribe_event *subscribe_event)
00368 {
00369 SaAisErrorT ais_res;
00370 SaEvtEventFilterArrayT filter_array;
00371 SaEvtEventFilterT filter;
00372 const char *filter_str = NULL;
00373 SaSizeT len;
00374
00375
00376 filter_str = type_to_filter_str(subscribe_event->type);
00377
00378 filter.filterType = SA_EVT_EXACT_FILTER;
00379 len = strlen(filter_str) + 1;
00380 filter.filter.allocatedSize = len;
00381 filter.filter.patternSize = len;
00382 filter.filter.pattern = (SaUint8T *) filter_str;
00383
00384 filter_array.filtersNumber = 1;
00385 filter_array.filters = &filter;
00386
00387 ais_res = saEvtEventSubscribe(event_channel->handle, &filter_array,
00388 subscribe_event->id);
00389
00390 return ais_res;
00391 }
00392
00393 static void add_subscribe_event(struct event_channel *event_channel, const char *event_type)
00394 {
00395 int i;
00396 enum ast_event_type type = -1;
00397 struct subscribe_event *subscribe_event;
00398 SaAisErrorT ais_res;
00399
00400 for (i = 0; i < ARRAY_LEN(supported_event_types); i++) {
00401 if (!strcasecmp(event_type, supported_event_types[i].str)) {
00402 type = supported_event_types[i].type;
00403 break;
00404 }
00405 }
00406
00407 if (type == -1) {
00408 ast_log(LOG_WARNING, "subscribe_event option given with invalid value '%s'\n", event_type);
00409 return;
00410 }
00411
00412 if (type == AST_EVENT_DEVICE_STATE_CHANGE && ast_enable_distributed_devstate()) {
00413 return;
00414 }
00415
00416 if (!(subscribe_event = ast_calloc(1, sizeof(*subscribe_event)))) {
00417 return;
00418 }
00419
00420 subscribe_event->type = type;
00421 subscribe_event->id = ast_atomic_fetchadd_int(&unique_id, +1);
00422
00423 ais_res = set_egress_subscription(event_channel, subscribe_event);
00424 if (ais_res != SA_AIS_OK) {
00425 ast_log(LOG_ERROR, "Error setting up egress subscription: %s\n",
00426 ais_err2str(ais_res));
00427 free(subscribe_event);
00428 return;
00429 }
00430
00431 AST_LIST_INSERT_TAIL(&event_channel->subscribe_events, subscribe_event, entry);
00432 }
00433
00434 static void build_event_channel(struct ast_config *cfg, const char *cat)
00435 {
00436 struct ast_variable *var;
00437 struct event_channel *event_channel;
00438 SaAisErrorT ais_res;
00439 SaNameT sa_name = { 0, };
00440
00441 AST_RWLIST_WRLOCK(&event_channels);
00442 AST_RWLIST_TRAVERSE(&event_channels, event_channel, entry) {
00443 if (!strcasecmp(event_channel->name, cat))
00444 break;
00445 }
00446 AST_RWLIST_UNLOCK(&event_channels);
00447 if (event_channel) {
00448 ast_log(LOG_WARNING, "Event channel '%s' was specified twice in "
00449 "configuration. Second instance ignored.\n", cat);
00450 return;
00451 }
00452
00453 if (!(event_channel = ast_calloc(1, sizeof(*event_channel) + strlen(cat))))
00454 return;
00455
00456 strcpy(event_channel->name, cat);
00457 ast_copy_string((char *) sa_name.value, cat, sizeof(sa_name.value));
00458 sa_name.length = strlen((char *) sa_name.value);
00459 ais_res = saEvtChannelOpen(evt_handle, &sa_name,
00460 SA_EVT_CHANNEL_PUBLISHER | SA_EVT_CHANNEL_SUBSCRIBER | SA_EVT_CHANNEL_CREATE,
00461 SA_TIME_MAX, &event_channel->handle);
00462 if (ais_res != SA_AIS_OK) {
00463 ast_log(LOG_ERROR, "Error opening event channel: %s\n", ais_err2str(ais_res));
00464 free(event_channel);
00465 return;
00466 }
00467
00468 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
00469 if (!strcasecmp(var->name, "type")) {
00470 continue;
00471 } else if (!strcasecmp(var->name, "publish_event")) {
00472 add_publish_event(event_channel, var->value);
00473 } else if (!strcasecmp(var->name, "subscribe_event")) {
00474 add_subscribe_event(event_channel, var->value);
00475 } else {
00476 ast_log(LOG_WARNING, "Event channel '%s' contains invalid option '%s'\n",
00477 event_channel->name, var->name);
00478 }
00479 }
00480
00481 AST_RWLIST_WRLOCK(&event_channels);
00482 AST_RWLIST_INSERT_TAIL(&event_channels, event_channel, entry);
00483 AST_RWLIST_UNLOCK(&event_channels);
00484 }
00485
00486 static void load_config(void)
00487 {
00488 static const char filename[] = "ais.conf";
00489 struct ast_config *cfg;
00490 const char *cat = NULL;
00491 struct ast_flags config_flags = { 0 };
00492
00493 if (!(cfg = ast_config_load(filename, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID)
00494 return;
00495
00496 while ((cat = ast_category_browse(cfg, cat))) {
00497 const char *type;
00498
00499 if (!strcasecmp(cat, "general"))
00500 continue;
00501
00502 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
00503 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
00504 filename);
00505 continue;
00506 }
00507
00508 if (!strcasecmp(type, "event_channel")) {
00509 build_event_channel(cfg, cat);
00510 } else {
00511 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'\n",
00512 filename, type);
00513 }
00514 }
00515
00516 ast_config_destroy(cfg);
00517 }
00518
00519 static void publish_event_destroy(struct publish_event *publish_event)
00520 {
00521 ast_event_unsubscribe(publish_event->sub);
00522
00523 free(publish_event);
00524 }
00525
00526 static void subscribe_event_destroy(const struct event_channel *event_channel,
00527 struct subscribe_event *subscribe_event)
00528 {
00529 SaAisErrorT ais_res;
00530
00531
00532
00533 ais_res = saEvtEventUnsubscribe(event_channel->handle, subscribe_event->id);
00534 if (ais_res != SA_AIS_OK) {
00535 ast_log(LOG_ERROR, "Error unsubscribing: %s\n", ais_err2str(ais_res));
00536 }
00537
00538 free(subscribe_event);
00539 }
00540
00541 static void event_channel_destroy(struct event_channel *event_channel)
00542 {
00543 struct publish_event *publish_event;
00544 struct subscribe_event *subscribe_event;
00545 SaAisErrorT ais_res;
00546
00547 while ((publish_event = AST_LIST_REMOVE_HEAD(&event_channel->publish_events, entry)))
00548 publish_event_destroy(publish_event);
00549 while ((subscribe_event = AST_LIST_REMOVE_HEAD(&event_channel->subscribe_events, entry)))
00550 subscribe_event_destroy(event_channel, subscribe_event);
00551
00552 ais_res = saEvtChannelClose(event_channel->handle);
00553 if (ais_res != SA_AIS_OK) {
00554 ast_log(LOG_ERROR, "Error closing event channel '%s': %s\n",
00555 event_channel->name, ais_err2str(ais_res));
00556 }
00557
00558 free(event_channel);
00559 }
00560
00561 static void destroy_event_channels(void)
00562 {
00563 struct event_channel *event_channel;
00564
00565 AST_RWLIST_WRLOCK(&event_channels);
00566 while ((event_channel = AST_RWLIST_REMOVE_HEAD(&event_channels, entry))) {
00567 event_channel_destroy(event_channel);
00568 }
00569 AST_RWLIST_UNLOCK(&event_channels);
00570 }
00571
00572 int ast_ais_evt_load_module(void)
00573 {
00574 evt_init_res = saEvtInitialize(&evt_handle, &evt_callbacks, &ais_version);
00575 if (evt_init_res != SA_AIS_OK) {
00576 ast_log(LOG_ERROR, "Could not initialize eventing service: %s\n",
00577 ais_err2str(evt_init_res));
00578 return -1;
00579 }
00580
00581 load_config();
00582
00583 ast_cli_register_multiple(ais_cli, ARRAY_LEN(ais_cli));
00584
00585 return 0;
00586 }
00587
00588 int ast_ais_evt_unload_module(void)
00589 {
00590 SaAisErrorT ais_res;
00591
00592 if (evt_init_res != SA_AIS_OK) {
00593 return 0;
00594 }
00595
00596 destroy_event_channels();
00597
00598 ais_res = saEvtFinalize(evt_handle);
00599 if (ais_res != SA_AIS_OK) {
00600 ast_log(LOG_ERROR, "Problem stopping eventing service: %s\n",
00601 ais_err2str(ais_res));
00602 return -1;
00603 }
00604
00605 return 0;
00606 }