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