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 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 295710 $")
00029
00030 #include "asterisk/_private.h"
00031
00032 #include "asterisk/event.h"
00033 #include "asterisk/linkedlists.h"
00034 #include "asterisk/dlinkedlists.h"
00035 #include "asterisk/lock.h"
00036 #include "asterisk/utils.h"
00037 #include "asterisk/unaligned.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/taskprocessor.h"
00040 #include "asterisk/astobj2.h"
00041 #include "asterisk/cli.h"
00042
00043 struct ast_taskprocessor *event_dispatcher;
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 struct ast_event_ie {
00054 enum ast_event_ie_type ie_type:16;
00055
00056 uint16_t ie_payload_len;
00057 unsigned char ie_payload[0];
00058 } __attribute__((packed));
00059
00060
00061
00062
00063 struct ast_event_ie_str_payload {
00064
00065 uint32_t hash;
00066
00067 char str[1];
00068 } __attribute__((packed));
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 struct ast_event {
00082
00083 enum ast_event_type type:16;
00084
00085 uint16_t event_len:16;
00086
00087 unsigned char payload[0];
00088 } __attribute__((packed));
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 struct ast_event_ref {
00101 struct ast_event *event;
00102 };
00103
00104 struct ast_event_ie_val {
00105 AST_LIST_ENTRY(ast_event_ie_val) entry;
00106 enum ast_event_ie_type ie_type;
00107 enum ast_event_ie_pltype ie_pltype;
00108 union {
00109 uint32_t uint;
00110 struct {
00111 uint32_t hash;
00112 const char *str;
00113 };
00114 void *raw;
00115 } payload;
00116 size_t raw_datalen;
00117 };
00118
00119
00120 struct ast_event_sub {
00121 enum ast_event_type type;
00122 ast_event_cb_t cb;
00123 void *userdata;
00124 uint32_t uniqueid;
00125 AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
00126 AST_RWDLLIST_ENTRY(ast_event_sub) entry;
00127 };
00128
00129 static uint32_t sub_uniqueid;
00130
00131
00132
00133 static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
00134
00135 static int ast_event_cmp(void *obj, void *arg, int flags);
00136 static int ast_event_hash_mwi(const void *obj, const int flags);
00137 static int ast_event_hash_devstate(const void *obj, const int flags);
00138 static int ast_event_hash_devstate_change(const void *obj, const int flags);
00139
00140 #ifdef LOW_MEMORY
00141 #define NUM_CACHE_BUCKETS 17
00142 #else
00143 #define NUM_CACHE_BUCKETS 563
00144 #endif
00145
00146 #define MAX_CACHE_ARGS 8
00147
00148
00149
00150
00151 static struct {
00152
00153
00154
00155
00156
00157
00158 struct ao2_container *container;
00159
00160 ao2_hash_fn *hash_fn;
00161
00162
00163
00164
00165
00166
00167
00168
00169 enum ast_event_ie_type cache_args[MAX_CACHE_ARGS];
00170 } ast_event_cache[AST_EVENT_TOTAL] = {
00171 [AST_EVENT_MWI] = {
00172 .hash_fn = ast_event_hash_mwi,
00173 .cache_args = { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_CONTEXT },
00174 },
00175 [AST_EVENT_DEVICE_STATE] = {
00176 .hash_fn = ast_event_hash_devstate,
00177 .cache_args = { AST_EVENT_IE_DEVICE, },
00178 },
00179 [AST_EVENT_DEVICE_STATE_CHANGE] = {
00180 .hash_fn = ast_event_hash_devstate_change,
00181 .cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
00182 },
00183 };
00184
00185
00186
00187
00188
00189
00190 static char * const cached_event_types[] = { "MWI", "DeviceState", "DeviceStateChange", NULL };
00191
00192
00193
00194
00195 static struct event_name {
00196 enum ast_event_type type;
00197 const char *name;
00198 } event_names[] = {
00199 { 0, "" },
00200 { AST_EVENT_CUSTOM, "Custom" },
00201 { AST_EVENT_MWI, "MWI" },
00202 { AST_EVENT_SUB, "Subscription" },
00203 { AST_EVENT_UNSUB, "Unsubscription" },
00204 { AST_EVENT_DEVICE_STATE, "DeviceState" },
00205 { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
00206 };
00207
00208
00209
00210
00211 static struct ie_map {
00212 enum ast_event_ie_type ie_type;
00213 enum ast_event_ie_pltype ie_pltype;
00214 const char *name;
00215 } ie_maps[] = {
00216 { 0, 0, "" },
00217 { AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
00218 { AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
00219 { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, "Mailbox" },
00220 { AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
00221 { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
00222 { AST_EVENT_IE_EXISTS, AST_EVENT_IE_PLTYPE_UINT, "Exists" },
00223 { AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Device" },
00224 { AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, "State" },
00225 { AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "Context" },
00226 { AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, "EntityID" },
00227 };
00228
00229 const char *ast_event_get_type_name(const struct ast_event *event)
00230 {
00231 enum ast_event_type type;
00232
00233 type = ast_event_get_type(event);
00234
00235 if (type >= AST_EVENT_TOTAL || type < 0) {
00236 ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
00237 return "";
00238 }
00239
00240 return event_names[type].name;
00241 }
00242
00243 int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
00244 {
00245 int i;
00246
00247 for (i = 0; i < ARRAY_LEN(event_names); i++) {
00248 if (strcasecmp(event_names[i].name, str))
00249 continue;
00250
00251 *event_type = event_names[i].type;
00252 return 0;
00253 }
00254
00255 return -1;
00256 }
00257
00258 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
00259 {
00260 if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
00261 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
00262 return "";
00263 }
00264
00265 if (ie_maps[ie_type].ie_type != ie_type) {
00266 ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
00267 return "";
00268 }
00269
00270 return ie_maps[ie_type].name;
00271 }
00272
00273 enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
00274 {
00275 if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
00276 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
00277 return AST_EVENT_IE_PLTYPE_UNKNOWN;
00278 }
00279
00280 if (ie_maps[ie_type].ie_type != ie_type) {
00281 ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
00282 return AST_EVENT_IE_PLTYPE_UNKNOWN;
00283 }
00284
00285 return ie_maps[ie_type].ie_pltype;
00286 }
00287
00288 int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
00289 {
00290 int i;
00291
00292 for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
00293 if (strcasecmp(ie_maps[i].name, str))
00294 continue;
00295
00296 *ie_type = ie_maps[i].ie_type;
00297 return 0;
00298 }
00299
00300 return -1;
00301 }
00302
00303 size_t ast_event_get_size(const struct ast_event *event)
00304 {
00305 size_t res;
00306
00307 res = ntohs(event->event_len);
00308
00309 return res;
00310 }
00311
00312 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
00313 {
00314 switch (ie_val->ie_pltype) {
00315 case AST_EVENT_IE_PLTYPE_STR:
00316 ast_free((char *) ie_val->payload.str);
00317 break;
00318 case AST_EVENT_IE_PLTYPE_RAW:
00319 ast_free(ie_val->payload.raw);
00320 break;
00321 case AST_EVENT_IE_PLTYPE_UINT:
00322 case AST_EVENT_IE_PLTYPE_EXISTS:
00323 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00324 break;
00325 }
00326
00327 ast_free(ie_val);
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 static int match_ie_val_to_sub(const struct ast_event_sub *sub, const struct ast_event_ie_val *ie_val)
00341 {
00342 const struct ast_event_ie_val *sub_ie_val;
00343 int res = 1;
00344
00345 AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
00346 if (sub_ie_val->ie_type == ie_val->ie_type) {
00347 break;
00348 }
00349 }
00350
00351 if (!sub_ie_val) {
00352
00353
00354 return 1;
00355 }
00356
00357 switch (ie_val->ie_pltype) {
00358 case AST_EVENT_IE_PLTYPE_UINT:
00359 res = (ie_val->payload.uint != sub_ie_val->payload.uint);
00360 break;
00361 case AST_EVENT_IE_PLTYPE_STR:
00362 res = strcmp(ie_val->payload.str, sub_ie_val->payload.str);
00363 break;
00364 case AST_EVENT_IE_PLTYPE_RAW:
00365 res = memcmp(ie_val->payload.raw,
00366 sub_ie_val->payload.raw, ie_val->raw_datalen);
00367 break;
00368 case AST_EVENT_IE_PLTYPE_EXISTS:
00369 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00370 break;
00371 }
00372
00373 return res;
00374 }
00375
00376 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00377 {
00378 va_list ap;
00379 enum ast_event_ie_type ie_type;
00380 enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00381 struct ast_event_ie_val *ie_val;
00382 struct ast_event_sub *sub;
00383 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00384 const enum ast_event_type event_types[] = { type, AST_EVENT_ALL };
00385 int i;
00386
00387 if (type >= AST_EVENT_TOTAL) {
00388 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00389 return res;
00390 }
00391
00392 va_start(ap, type);
00393 for (ie_type = va_arg(ap, enum ast_event_ie_type);
00394 ie_type != AST_EVENT_IE_END;
00395 ie_type = va_arg(ap, enum ast_event_ie_type))
00396 {
00397 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00398 memset(ie_value, 0, sizeof(*ie_value));
00399 ie_value->ie_type = ie_type;
00400 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00401 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00402 ie_value->payload.uint = va_arg(ap, uint32_t);
00403 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00404 ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00405 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00406 void *data = va_arg(ap, void *);
00407 size_t datalen = va_arg(ap, size_t);
00408 ie_value->payload.raw = alloca(datalen);
00409 memcpy(ie_value->payload.raw, data, datalen);
00410 ie_value->raw_datalen = datalen;
00411 }
00412 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00413 }
00414 va_end(ap);
00415
00416 for (i = 0; i < ARRAY_LEN(event_types); i++) {
00417 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
00418 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
00419 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00420 if (match_ie_val_to_sub(sub, ie_val)) {
00421 break;
00422 }
00423 }
00424
00425 if (!ie_val) {
00426
00427 break;
00428 }
00429 }
00430 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
00431 if (sub) {
00432 break;
00433 }
00434 }
00435
00436 return sub ? AST_EVENT_SUB_EXISTS : AST_EVENT_SUB_NONE;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 static int match_ie_val(const struct ast_event *event,
00453 const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
00454 {
00455 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
00456 uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
00457 if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
00458 return 1;
00459 return 0;
00460 }
00461
00462 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
00463 const char *str;
00464 uint32_t hash;
00465
00466 hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
00467 if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
00468 return 0;
00469 }
00470
00471 str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
00472 if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
00473 return 1;
00474 }
00475
00476 return 0;
00477 }
00478
00479 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00480 const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
00481 uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
00482
00483 return (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
00484 }
00485
00486 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
00487 if (ast_event_get_ie_raw(event, ie_val->ie_type))
00488 return 1;
00489 return 0;
00490 }
00491
00492 return 0;
00493 }
00494
00495 static int dump_cache_cb(void *obj, void *arg, int flags)
00496 {
00497 const struct ast_event_ref *event_ref = obj;
00498 const struct ast_event *event = event_ref->event;
00499 const struct ast_event_sub *event_sub = arg;
00500 struct ast_event_ie_val *ie_val = NULL;
00501
00502 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00503 if (!match_ie_val(event, ie_val, NULL)) {
00504 break;
00505 }
00506 }
00507
00508 if (!ie_val) {
00509
00510 event_sub->cb(event, event_sub->userdata);
00511 }
00512
00513 return 0;
00514 }
00515
00516
00517 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
00518 {
00519 ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
00520 dump_cache_cb, (void *) event_sub);
00521 }
00522
00523 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
00524 {
00525 struct ast_event_ie_val *ie_val;
00526 struct ast_event *event;
00527
00528 event = ast_event_new(AST_EVENT_SUB,
00529 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00530 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00531 AST_EVENT_IE_END);
00532
00533 if (!event)
00534 return NULL;
00535
00536 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00537 switch (ie_val->ie_pltype) {
00538 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00539 break;
00540 case AST_EVENT_IE_PLTYPE_EXISTS:
00541 ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00542 break;
00543 case AST_EVENT_IE_PLTYPE_UINT:
00544 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00545 break;
00546 case AST_EVENT_IE_PLTYPE_STR:
00547 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00548 break;
00549 case AST_EVENT_IE_PLTYPE_RAW:
00550 ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00551 break;
00552 }
00553 if (!event)
00554 break;
00555 }
00556
00557 return event;
00558 }
00559
00560
00561 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00562 {
00563 struct ast_event *event;
00564 struct ast_event_sub *sub;
00565 enum ast_event_type event_type = -1;
00566 struct ast_event_ie_val *ie_val;
00567
00568 if (event_sub->type != AST_EVENT_SUB)
00569 return;
00570
00571 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00572 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00573 event_type = ie_val->payload.uint;
00574 break;
00575 }
00576 }
00577
00578 if (event_type == -1)
00579 return;
00580
00581 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
00582 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00583 if (event_sub == sub)
00584 continue;
00585
00586 event = gen_sub_event(sub);
00587
00588 if (!event)
00589 continue;
00590
00591 event_sub->cb(event, event_sub->userdata);
00592
00593 ast_event_destroy(event);
00594 }
00595 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
00596 }
00597
00598 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
00599 ast_event_cb_t cb, void *userdata)
00600 {
00601 struct ast_event_sub *sub;
00602
00603 if (type < 0 || type >= AST_EVENT_TOTAL) {
00604 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00605 return NULL;
00606 }
00607
00608 if (!(sub = ast_calloc(1, sizeof(*sub))))
00609 return NULL;
00610
00611 sub->type = type;
00612 sub->cb = cb;
00613 sub->userdata = userdata;
00614 sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00615
00616 return sub;
00617 }
00618
00619 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
00620 enum ast_event_ie_type ie_type, uint32_t unsigned_int)
00621 {
00622 struct ast_event_ie_val *ie_val;
00623
00624 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00625 return -1;
00626
00627 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00628 return -1;
00629
00630 ie_val->ie_type = ie_type;
00631 ie_val->payload.uint = unsigned_int;
00632 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
00633
00634 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00635
00636 return 0;
00637 }
00638
00639 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
00640 enum ast_event_ie_type ie_type)
00641 {
00642 struct ast_event_ie_val *ie_val;
00643
00644 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00645 return -1;
00646
00647 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00648 return -1;
00649
00650 ie_val->ie_type = ie_type;
00651 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
00652
00653 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00654
00655 return 0;
00656 }
00657
00658 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
00659 enum ast_event_ie_type ie_type, const char *str)
00660 {
00661 struct ast_event_ie_val *ie_val;
00662
00663 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00664 return -1;
00665
00666 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00667 return -1;
00668
00669 ie_val->ie_type = ie_type;
00670 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
00671
00672 if (!(ie_val->payload.str = ast_strdup(str))) {
00673 ast_free(ie_val);
00674 return -1;
00675 }
00676
00677 ie_val->payload.hash = ast_str_hash(str);
00678
00679 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00680
00681 return 0;
00682 }
00683
00684 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
00685 enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
00686 {
00687 struct ast_event_ie_val *ie_val;
00688
00689 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00690 return -1;
00691
00692 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00693 return -1;
00694
00695 ie_val->ie_type = ie_type;
00696 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
00697 ie_val->raw_datalen = raw_datalen;
00698
00699 if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
00700 ast_free(ie_val);
00701 return -1;
00702 }
00703
00704 memcpy(ie_val->payload.raw, data, raw_datalen);
00705
00706 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00707
00708 return 0;
00709 }
00710
00711 int ast_event_sub_activate(struct ast_event_sub *sub)
00712 {
00713 if (ast_event_check_subscriber(AST_EVENT_SUB,
00714 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00715 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00716 struct ast_event *event;
00717
00718 event = gen_sub_event(sub);
00719
00720 if (event)
00721 ast_event_queue(event);
00722 }
00723
00724 AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00725 AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
00726 AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00727
00728 return 0;
00729 }
00730
00731 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
00732 void *userdata, ...)
00733 {
00734 va_list ap;
00735 enum ast_event_ie_type ie_type;
00736 struct ast_event_sub *sub;
00737
00738 if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
00739 return NULL;
00740
00741 va_start(ap, userdata);
00742 for (ie_type = va_arg(ap, enum ast_event_ie_type);
00743 ie_type != AST_EVENT_IE_END;
00744 ie_type = va_arg(ap, enum ast_event_ie_type))
00745 {
00746 enum ast_event_ie_pltype ie_pltype;
00747
00748 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00749
00750 switch (ie_pltype) {
00751 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00752 break;
00753 case AST_EVENT_IE_PLTYPE_UINT:
00754 {
00755 uint32_t unsigned_int = va_arg(ap, uint32_t);
00756 ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
00757 break;
00758 }
00759 case AST_EVENT_IE_PLTYPE_STR:
00760 {
00761 const char *str = va_arg(ap, const char *);
00762 ast_event_sub_append_ie_str(sub, ie_type, str);
00763 break;
00764 }
00765 case AST_EVENT_IE_PLTYPE_RAW:
00766 {
00767 void *data = va_arg(ap, void *);
00768 size_t data_len = va_arg(ap, size_t);
00769 ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
00770 break;
00771 }
00772 case AST_EVENT_IE_PLTYPE_EXISTS:
00773 ast_event_sub_append_ie_exists(sub, ie_type);
00774 break;
00775 }
00776 }
00777 va_end(ap);
00778
00779 ast_event_sub_activate(sub);
00780
00781 return sub;
00782 }
00783
00784 void ast_event_sub_destroy(struct ast_event_sub *sub)
00785 {
00786 struct ast_event_ie_val *ie_val;
00787
00788 while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
00789 ast_event_ie_val_destroy(ie_val);
00790
00791 ast_free(sub);
00792 }
00793
00794 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
00795 {
00796 struct ast_event *event;
00797
00798 AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00799 AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
00800 AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00801
00802 if (ast_event_check_subscriber(AST_EVENT_UNSUB,
00803 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00804 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00805
00806 event = ast_event_new(AST_EVENT_UNSUB,
00807 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00808 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00809 AST_EVENT_IE_END);
00810
00811 if (event)
00812 ast_event_queue(event);
00813 }
00814
00815 ast_event_sub_destroy(sub);
00816
00817 return NULL;
00818 }
00819
00820 int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00821 {
00822 int res = 0;
00823
00824 iterator->event_len = ntohs(event->event_len);
00825 iterator->event = event;
00826 if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
00827 iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00828 } else {
00829 iterator->ie = NULL;
00830 res = -1;
00831 }
00832
00833 return res;
00834 }
00835
00836 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00837 {
00838 iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00839 return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00840 }
00841
00842 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00843 {
00844 return ntohs(iterator->ie->ie_type);
00845 }
00846
00847 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00848 {
00849 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00850 }
00851
00852 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00853 {
00854 const struct ast_event_ie_str_payload *str_payload;
00855
00856 str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
00857
00858 return str_payload ? str_payload->str : NULL;
00859 }
00860
00861 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00862 {
00863 return iterator->ie->ie_payload;
00864 }
00865
00866 uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
00867 {
00868 return ntohs(iterator->ie->ie_payload_len);
00869 }
00870
00871 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00872 {
00873 return ntohs(event->type);
00874 }
00875
00876 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00877 {
00878 const uint32_t *ie_val;
00879
00880 ie_val = ast_event_get_ie_raw(event, ie_type);
00881
00882 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00883 }
00884
00885 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
00886 {
00887 const struct ast_event_ie_str_payload *str_payload;
00888
00889 str_payload = ast_event_get_ie_raw(event, ie_type);
00890
00891 return str_payload ? str_payload->hash : 0;
00892 }
00893
00894 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00895 {
00896 const struct ast_event_ie_str_payload *str_payload;
00897
00898 str_payload = ast_event_get_ie_raw(event, ie_type);
00899
00900 return str_payload ? str_payload->str : NULL;
00901 }
00902
00903 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00904 {
00905 struct ast_event_iterator iterator;
00906 int res = 0;
00907
00908 for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00909 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
00910 return ast_event_iterator_get_ie_raw(&iterator);
00911 }
00912 }
00913
00914 return NULL;
00915 }
00916
00917 uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
00918 {
00919 struct ast_event_iterator iterator;
00920 int res;
00921
00922 for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00923 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
00924 return ast_event_iterator_get_ie_raw_payload_len(&iterator);
00925 }
00926 }
00927
00928 return 0;
00929 }
00930
00931 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00932 const char *str)
00933 {
00934 struct ast_event_ie_str_payload *str_payload;
00935 size_t payload_len;
00936
00937 payload_len = sizeof(*str_payload) + strlen(str);
00938 str_payload = alloca(payload_len);
00939
00940 strcpy(str_payload->str, str);
00941 str_payload->hash = ast_str_hash(str);
00942
00943 return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
00944 }
00945
00946 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00947 uint32_t data)
00948 {
00949 data = htonl(data);
00950 return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00951 }
00952
00953 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00954 const void *data, size_t data_len)
00955 {
00956 struct ast_event_ie *ie;
00957 unsigned int extra_len;
00958 uint16_t event_len;
00959
00960 event_len = ntohs((*event)->event_len);
00961 extra_len = sizeof(*ie) + data_len;
00962
00963 if (!(*event = ast_realloc(*event, event_len + extra_len)))
00964 return -1;
00965
00966 ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00967 ie->ie_type = htons(ie_type);
00968 ie->ie_payload_len = htons(data_len);
00969 memcpy(ie->ie_payload, data, data_len);
00970
00971 (*event)->event_len = htons(event_len + extra_len);
00972
00973 return 0;
00974 }
00975
00976 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00977 {
00978 va_list ap;
00979 struct ast_event *event;
00980 enum ast_event_ie_type ie_type;
00981 struct ast_event_ie_val *ie_val;
00982 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00983
00984
00985 if (type >= AST_EVENT_TOTAL) {
00986 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00987 "type '%d'!\n", type);
00988 return NULL;
00989 }
00990
00991 va_start(ap, type);
00992 for (ie_type = va_arg(ap, enum ast_event_ie_type);
00993 ie_type != AST_EVENT_IE_END;
00994 ie_type = va_arg(ap, enum ast_event_ie_type))
00995 {
00996 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00997 memset(ie_value, 0, sizeof(*ie_value));
00998 ie_value->ie_type = ie_type;
00999 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01000 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
01001 ie_value->payload.uint = va_arg(ap, uint32_t);
01002 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
01003 ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
01004 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
01005 void *data = va_arg(ap, void *);
01006 size_t datalen = va_arg(ap, size_t);
01007 ie_value->payload.raw = alloca(datalen);
01008 memcpy(ie_value->payload.raw, data, datalen);
01009 ie_value->raw_datalen = datalen;
01010 }
01011 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
01012 }
01013 va_end(ap);
01014
01015 if (!(event = ast_calloc(1, sizeof(*event))))
01016 return NULL;
01017
01018 event->type = htons(type);
01019 event->event_len = htons(sizeof(*event));
01020
01021 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
01022 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
01023 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
01024 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
01025 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
01026 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
01027 ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
01028
01029 if (!event)
01030 break;
01031 }
01032
01033 if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
01034
01035
01036 ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
01037 }
01038
01039 return event;
01040 }
01041
01042 void ast_event_destroy(struct ast_event *event)
01043 {
01044 ast_free(event);
01045 }
01046
01047 static void ast_event_ref_destroy(void *obj)
01048 {
01049 struct ast_event_ref *event_ref = obj;
01050
01051 ast_event_destroy(event_ref->event);
01052 }
01053
01054 static struct ast_event *ast_event_dup(const struct ast_event *event)
01055 {
01056 struct ast_event *dup_event;
01057 uint16_t event_len;
01058
01059 event_len = ast_event_get_size(event);
01060
01061 if (!(dup_event = ast_calloc(1, event_len))) {
01062 return NULL;
01063 }
01064
01065 memcpy(dup_event, event, event_len);
01066
01067 return dup_event;
01068 }
01069
01070 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
01071 {
01072 va_list ap;
01073 enum ast_event_ie_type ie_type;
01074 struct ast_event *dup_event = NULL;
01075 struct ast_event_ref *cached_event_ref;
01076 struct ast_event *cache_arg_event;
01077 struct ast_event_ref tmp_event_ref = {
01078 .event = NULL,
01079 };
01080 struct ao2_container *container = NULL;
01081
01082 if (type >= AST_EVENT_TOTAL) {
01083 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01084 return NULL;
01085 }
01086
01087 if (!(container = ast_event_cache[type].container)) {
01088 ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01089 return NULL;
01090 }
01091
01092 if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01093 return NULL;
01094 }
01095
01096 va_start(ap, type);
01097 for (ie_type = va_arg(ap, enum ast_event_ie_type);
01098 ie_type != AST_EVENT_IE_END;
01099 ie_type = va_arg(ap, enum ast_event_ie_type))
01100 {
01101 enum ast_event_ie_pltype ie_pltype;
01102
01103 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01104
01105 switch (ie_pltype) {
01106 case AST_EVENT_IE_PLTYPE_UINT:
01107 ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01108 break;
01109 case AST_EVENT_IE_PLTYPE_STR:
01110 ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01111 break;
01112 case AST_EVENT_IE_PLTYPE_RAW:
01113 {
01114 void *data = va_arg(ap, void *);
01115 size_t datalen = va_arg(ap, size_t);
01116 ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01117 }
01118 case AST_EVENT_IE_PLTYPE_EXISTS:
01119 ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01120 break;
01121 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01122 break;
01123 }
01124 }
01125 va_end(ap);
01126
01127 tmp_event_ref.event = cache_arg_event;
01128
01129 cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01130
01131 ast_event_destroy(cache_arg_event);
01132 cache_arg_event = NULL;
01133
01134 if (cached_event_ref) {
01135 dup_event = ast_event_dup(cached_event_ref->event);
01136 ao2_ref(cached_event_ref, -1);
01137 cached_event_ref = NULL;
01138 }
01139
01140 return dup_event;
01141 }
01142
01143 static struct ast_event_ref *alloc_event_ref(void)
01144 {
01145 return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01146 }
01147
01148
01149
01150 static int ast_event_dup_and_cache(const struct ast_event *event)
01151 {
01152 struct ast_event *dup_event;
01153 struct ast_event_ref *event_ref;
01154
01155 if (!(dup_event = ast_event_dup(event))) {
01156 return -1;
01157 }
01158
01159 if (!(event_ref = alloc_event_ref())) {
01160 ast_event_destroy(dup_event);
01161 return -1;
01162 }
01163
01164 event_ref->event = dup_event;
01165
01166 ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
01167
01168 ao2_ref(event_ref, -1);
01169
01170 return 0;
01171 }
01172
01173 int ast_event_queue_and_cache(struct ast_event *event)
01174 {
01175 struct ao2_container *container;
01176 struct ast_event_ref tmp_event_ref = {
01177 .event = event,
01178 };
01179 int res = -1;
01180
01181 if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
01182 ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01183 goto queue_event;
01184 }
01185
01186
01187 ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01188 ast_event_cmp, &tmp_event_ref);
01189
01190 res = ast_event_dup_and_cache(event);
01191
01192 queue_event:
01193 return ast_event_queue(event) ? -1 : res;
01194 }
01195
01196 static int handle_event(void *data)
01197 {
01198 struct ast_event_ref *event_ref = data;
01199 struct ast_event_sub *sub;
01200 const enum ast_event_type event_types[] = {
01201 ntohs(event_ref->event->type),
01202 AST_EVENT_ALL
01203 };
01204 int i;
01205
01206 for (i = 0; i < ARRAY_LEN(event_types); i++) {
01207 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
01208 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
01209 struct ast_event_ie_val *ie_val;
01210 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01211 if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01212 break;
01213 }
01214 }
01215 if (ie_val) {
01216 continue;
01217 }
01218 sub->cb(event_ref->event, sub->userdata);
01219 }
01220 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
01221 }
01222
01223 ao2_ref(event_ref, -1);
01224
01225 return 0;
01226 }
01227
01228 int ast_event_queue(struct ast_event *event)
01229 {
01230 struct ast_event_ref *event_ref;
01231 uint16_t host_event_type;
01232
01233 host_event_type = ntohs(event->type);
01234
01235
01236 if (host_event_type >= AST_EVENT_TOTAL) {
01237 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01238 "type '%d'!\n", host_event_type);
01239 return -1;
01240 }
01241
01242
01243 if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01244 == AST_EVENT_SUB_NONE) {
01245 ast_event_destroy(event);
01246 return 0;
01247 }
01248
01249 if (!(event_ref = alloc_event_ref())) {
01250 return -1;
01251 }
01252
01253 event_ref->event = event;
01254
01255 return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01256 }
01257
01258 static int ast_event_hash_mwi(const void *obj, const int flags)
01259 {
01260 const struct ast_event *event = obj;
01261 const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01262 const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01263
01264 return ast_str_hash_add(context, ast_str_hash(mailbox));
01265 }
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 static int ast_event_hash_devstate(const void *obj, const int flags)
01277 {
01278 const struct ast_event *event = obj;
01279
01280 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01281 }
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01293 {
01294 const struct ast_event *event = obj;
01295
01296 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01297 }
01298
01299 static int ast_event_hash(const void *obj, const int flags)
01300 {
01301 const struct ast_event_ref *event_ref;
01302 const struct ast_event *event;
01303 ao2_hash_fn *hash_fn;
01304
01305 event_ref = obj;
01306 event = event_ref->event;
01307
01308 if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01309 return 0;
01310 }
01311
01312 return hash_fn(event, flags);
01313 }
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333 static int ast_event_cmp(void *obj, void *arg, int flags)
01334 {
01335 struct ast_event_ref *event_ref, *event_ref2;
01336 struct ast_event *event, *event2;
01337 int res = CMP_MATCH;
01338 int i;
01339 enum ast_event_ie_type *cache_args;
01340
01341 event_ref = obj;
01342 event = event_ref->event;
01343
01344 event_ref2 = arg;
01345 event2 = event_ref2->event;
01346
01347 cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01348
01349 for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01350 struct ast_event_ie_val ie_val = {
01351 .ie_pltype = ast_event_get_ie_pltype(cache_args[i]),
01352 .ie_type = cache_args[i],
01353 };
01354
01355 if (!match_ie_val(event, &ie_val, event2)) {
01356 res = 0;
01357 break;
01358 }
01359 }
01360
01361 return res;
01362 }
01363
01364 static void dump_raw_ie(struct ast_event_iterator *i, struct ast_cli_args *a)
01365 {
01366 char eid_buf[32];
01367 enum ast_event_ie_type ie_type;
01368 const char *ie_type_name;
01369
01370 ie_type = ast_event_iterator_get_ie_type(i);
01371 ie_type_name = ast_event_get_ie_type_name(ie_type);
01372
01373 switch (ie_type) {
01374 case AST_EVENT_IE_EID:
01375 ast_eid_to_str(eid_buf, sizeof(eid_buf), ast_event_iterator_get_ie_raw(i));
01376 ast_cli(a->fd, "%.30s: %s\n", ie_type_name, eid_buf);
01377 break;
01378 default:
01379 ast_cli(a->fd, "%s\n", ie_type_name);
01380 break;
01381 }
01382 }
01383
01384 static int event_dump_cli(void *obj, void *arg, int flags)
01385 {
01386 const struct ast_event_ref *event_ref = obj;
01387 const struct ast_event *event = event_ref->event;
01388 struct ast_cli_args *a = arg;
01389 struct ast_event_iterator i;
01390
01391 if (ast_event_iterator_init(&i, event)) {
01392 ast_cli(a->fd, "Failed to initialize event iterator. :-(\n");
01393 return 0;
01394 }
01395
01396 ast_cli(a->fd, "Event: %s\n", ast_event_get_type_name(event));
01397
01398 do {
01399 enum ast_event_ie_type ie_type;
01400 enum ast_event_ie_pltype ie_pltype;
01401 const char *ie_type_name;
01402
01403 ie_type = ast_event_iterator_get_ie_type(&i);
01404 ie_type_name = ast_event_get_ie_type_name(ie_type);
01405 ie_pltype = ast_event_get_ie_pltype(ie_type);
01406
01407 switch (ie_pltype) {
01408 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01409 case AST_EVENT_IE_PLTYPE_EXISTS:
01410 ast_cli(a->fd, "%s\n", ie_type_name);
01411 break;
01412 case AST_EVENT_IE_PLTYPE_STR:
01413 ast_cli(a->fd, "%.30s: %s\n", ie_type_name,
01414 ast_event_iterator_get_ie_str(&i));
01415 break;
01416 case AST_EVENT_IE_PLTYPE_UINT:
01417 ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
01418 ast_event_iterator_get_ie_uint(&i));
01419 break;
01420 case AST_EVENT_IE_PLTYPE_RAW:
01421 dump_raw_ie(&i, a);
01422 break;
01423 }
01424 } while (!ast_event_iterator_next(&i));
01425
01426 ast_cli(a->fd, "\n");
01427
01428 return 0;
01429 }
01430
01431 static char *event_dump_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01432 {
01433 enum ast_event_type event_type;
01434 enum ast_event_ie_type *cache_args;
01435 int i;
01436
01437 switch (cmd) {
01438 case CLI_INIT:
01439 e->command = "event dump cache";
01440 e->usage =
01441 "Usage: event dump cache <event type>\n"
01442 " Dump all of the cached events for the given event type.\n"
01443 " This is primarily intended for debugging.\n";
01444 return NULL;
01445 case CLI_GENERATE:
01446 if (a->pos == 3) {
01447 return ast_cli_complete(a->word, cached_event_types, a->n);
01448 }
01449 return NULL;
01450 case CLI_HANDLER:
01451 break;
01452 }
01453
01454 if (a->argc != e->args + 1) {
01455 return CLI_SHOWUSAGE;
01456 }
01457
01458 if (ast_event_str_to_event_type(a->argv[e->args], &event_type)) {
01459 ast_cli(a->fd, "Invalid cached event type: '%s'\n", a->argv[e->args]);
01460 return CLI_SHOWUSAGE;
01461 }
01462
01463 if (!ast_event_cache[event_type].container) {
01464 ast_cli(a->fd, "Event type '%s' has no cache.\n", a->argv[e->args]);
01465 return CLI_SUCCESS;
01466 }
01467
01468 ast_cli(a->fd, "Event Type: %s\n", a->argv[e->args]);
01469 ast_cli(a->fd, "Cache Unique Keys:\n");
01470 cache_args = ast_event_cache[event_type].cache_args;
01471 for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01472 ast_cli(a->fd, "--> %s\n", ast_event_get_ie_type_name(cache_args[i]));
01473 }
01474
01475 ast_cli(a->fd, "\n--- Begin Cache Dump ---\n\n");
01476 ao2_callback(ast_event_cache[event_type].container, OBJ_NODATA, event_dump_cli, a);
01477 ast_cli(a->fd, "--- End Cache Dump ---\n\n");
01478
01479 return CLI_SUCCESS;
01480 }
01481
01482 static struct ast_cli_entry event_cli[] = {
01483 AST_CLI_DEFINE(event_dump_cache, "Dump the internal event cache (for debugging)"),
01484 };
01485
01486 int ast_event_init(void)
01487 {
01488 int i;
01489
01490 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01491 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01492 }
01493
01494 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01495 if (!ast_event_cache[i].hash_fn) {
01496
01497 continue;
01498 }
01499
01500 if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01501 ast_event_hash, ast_event_cmp))) {
01502 return -1;
01503 }
01504 }
01505
01506 if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01507 return -1;
01508 }
01509
01510 ast_cli_register_multiple(event_cli, ARRAY_LEN(event_cli));
01511
01512 return 0;
01513 }