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: 258672 $")
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 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00813 {
00814 iterator->event_len = ntohs(event->event_len);
00815 iterator->event = event;
00816 iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00817 return;
00818 }
00819
00820 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00821 {
00822 iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00823 return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00824 }
00825
00826 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00827 {
00828 return ntohs(iterator->ie->ie_type);
00829 }
00830
00831 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00832 {
00833 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00834 }
00835
00836 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00837 {
00838 const struct ast_event_ie_str_payload *str_payload;
00839
00840 str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
00841
00842 return str_payload ? str_payload->str : NULL;
00843 }
00844
00845 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00846 {
00847 return iterator->ie->ie_payload;
00848 }
00849
00850 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00851 {
00852 return ntohs(event->type);
00853 }
00854
00855 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00856 {
00857 const uint32_t *ie_val;
00858
00859 ie_val = ast_event_get_ie_raw(event, ie_type);
00860
00861 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00862 }
00863
00864 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
00865 {
00866 const struct ast_event_ie_str_payload *str_payload;
00867
00868 str_payload = ast_event_get_ie_raw(event, ie_type);
00869
00870 return str_payload ? str_payload->hash : 0;
00871 }
00872
00873 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00874 {
00875 const struct ast_event_ie_str_payload *str_payload;
00876
00877 str_payload = ast_event_get_ie_raw(event, ie_type);
00878
00879 return str_payload ? str_payload->str : NULL;
00880 }
00881
00882 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00883 {
00884 struct ast_event_iterator iterator;
00885 int res = 0;
00886
00887 for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00888 if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
00889 return ast_event_iterator_get_ie_raw(&iterator);
00890 }
00891
00892 return NULL;
00893 }
00894
00895 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00896 const char *str)
00897 {
00898 struct ast_event_ie_str_payload *str_payload;
00899 size_t payload_len;
00900
00901 payload_len = sizeof(*str_payload) + strlen(str);
00902 str_payload = alloca(payload_len);
00903
00904 strcpy(str_payload->str, str);
00905 str_payload->hash = ast_str_hash(str);
00906
00907 return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
00908 }
00909
00910 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00911 uint32_t data)
00912 {
00913 data = htonl(data);
00914 return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00915 }
00916
00917 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00918 const void *data, size_t data_len)
00919 {
00920 struct ast_event_ie *ie;
00921 unsigned int extra_len;
00922 uint16_t event_len;
00923
00924 event_len = ntohs((*event)->event_len);
00925 extra_len = sizeof(*ie) + data_len;
00926
00927 if (!(*event = ast_realloc(*event, event_len + extra_len)))
00928 return -1;
00929
00930 ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00931 ie->ie_type = htons(ie_type);
00932 ie->ie_payload_len = htons(data_len);
00933 memcpy(ie->ie_payload, data, data_len);
00934
00935 (*event)->event_len = htons(event_len + extra_len);
00936
00937 return 0;
00938 }
00939
00940 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00941 {
00942 va_list ap;
00943 struct ast_event *event;
00944 enum ast_event_ie_type ie_type;
00945 struct ast_event_ie_val *ie_val;
00946 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00947
00948
00949 if (type >= AST_EVENT_TOTAL) {
00950 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00951 "type '%d'!\n", type);
00952 return NULL;
00953 }
00954
00955 va_start(ap, type);
00956 for (ie_type = va_arg(ap, enum ast_event_ie_type);
00957 ie_type != AST_EVENT_IE_END;
00958 ie_type = va_arg(ap, enum ast_event_ie_type))
00959 {
00960 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00961 memset(ie_value, 0, sizeof(*ie_value));
00962 ie_value->ie_type = ie_type;
00963 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00964 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00965 ie_value->payload.uint = va_arg(ap, uint32_t);
00966 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00967 ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00968 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00969 void *data = va_arg(ap, void *);
00970 size_t datalen = va_arg(ap, size_t);
00971 ie_value->payload.raw = alloca(datalen);
00972 memcpy(ie_value->payload.raw, data, datalen);
00973 ie_value->raw_datalen = datalen;
00974 }
00975 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00976 }
00977 va_end(ap);
00978
00979 if (!(event = ast_calloc(1, sizeof(*event))))
00980 return NULL;
00981
00982 event->type = htons(type);
00983 event->event_len = htons(sizeof(*event));
00984
00985 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00986 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00987 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00988 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00989 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00990 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
00991 ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00992
00993 if (!event)
00994 break;
00995 }
00996
00997 if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
00998
00999
01000 ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
01001 }
01002
01003 return event;
01004 }
01005
01006 void ast_event_destroy(struct ast_event *event)
01007 {
01008 ast_free(event);
01009 }
01010
01011 static void ast_event_ref_destroy(void *obj)
01012 {
01013 struct ast_event_ref *event_ref = obj;
01014
01015 ast_event_destroy(event_ref->event);
01016 }
01017
01018 static struct ast_event *ast_event_dup(const struct ast_event *event)
01019 {
01020 struct ast_event *dup_event;
01021 uint16_t event_len;
01022
01023 event_len = ast_event_get_size(event);
01024
01025 if (!(dup_event = ast_calloc(1, event_len))) {
01026 return NULL;
01027 }
01028
01029 memcpy(dup_event, event, event_len);
01030
01031 return dup_event;
01032 }
01033
01034 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
01035 {
01036 va_list ap;
01037 enum ast_event_ie_type ie_type;
01038 struct ast_event *dup_event = NULL;
01039 struct ast_event_ref *cached_event_ref;
01040 struct ast_event *cache_arg_event;
01041 struct ast_event_ref tmp_event_ref = {
01042 .event = NULL,
01043 };
01044 struct ao2_container *container = NULL;
01045
01046 if (type >= AST_EVENT_TOTAL) {
01047 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01048 return NULL;
01049 }
01050
01051 if (!(container = ast_event_cache[type].container)) {
01052 ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01053 return NULL;
01054 }
01055
01056 if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01057 return NULL;
01058 }
01059
01060 va_start(ap, type);
01061 for (ie_type = va_arg(ap, enum ast_event_ie_type);
01062 ie_type != AST_EVENT_IE_END;
01063 ie_type = va_arg(ap, enum ast_event_ie_type))
01064 {
01065 enum ast_event_ie_pltype ie_pltype;
01066
01067 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01068
01069 switch (ie_pltype) {
01070 case AST_EVENT_IE_PLTYPE_UINT:
01071 ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01072 break;
01073 case AST_EVENT_IE_PLTYPE_STR:
01074 ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01075 break;
01076 case AST_EVENT_IE_PLTYPE_RAW:
01077 {
01078 void *data = va_arg(ap, void *);
01079 size_t datalen = va_arg(ap, size_t);
01080 ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01081 }
01082 case AST_EVENT_IE_PLTYPE_EXISTS:
01083 ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01084 break;
01085 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01086 break;
01087 }
01088 }
01089 va_end(ap);
01090
01091 tmp_event_ref.event = cache_arg_event;
01092
01093 cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01094
01095 ast_event_destroy(cache_arg_event);
01096 cache_arg_event = NULL;
01097
01098 if (cached_event_ref) {
01099 dup_event = ast_event_dup(cached_event_ref->event);
01100 ao2_ref(cached_event_ref, -1);
01101 cached_event_ref = NULL;
01102 }
01103
01104 return dup_event;
01105 }
01106
01107 static struct ast_event_ref *alloc_event_ref(void)
01108 {
01109 return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01110 }
01111
01112
01113
01114 static int ast_event_dup_and_cache(const struct ast_event *event)
01115 {
01116 struct ast_event *dup_event;
01117 struct ast_event_ref *event_ref;
01118
01119 if (!(dup_event = ast_event_dup(event))) {
01120 return -1;
01121 }
01122
01123 if (!(event_ref = alloc_event_ref())) {
01124 ast_event_destroy(dup_event);
01125 return -1;
01126 }
01127
01128 event_ref->event = dup_event;
01129
01130 ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
01131
01132 ao2_ref(event_ref, -1);
01133
01134 return 0;
01135 }
01136
01137 int ast_event_queue_and_cache(struct ast_event *event)
01138 {
01139 struct ao2_container *container;
01140 struct ast_event_ref tmp_event_ref = {
01141 .event = event,
01142 };
01143 int res = -1;
01144
01145 if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
01146 ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01147 goto queue_event;
01148 }
01149
01150
01151 ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01152 ast_event_cmp, &tmp_event_ref);
01153
01154 res = ast_event_dup_and_cache(event);
01155
01156 queue_event:
01157 return ast_event_queue(event) ? -1 : res;
01158 }
01159
01160 static int handle_event(void *data)
01161 {
01162 struct ast_event_ref *event_ref = data;
01163 struct ast_event_sub *sub;
01164 const enum ast_event_type event_types[] = {
01165 ntohs(event_ref->event->type),
01166 AST_EVENT_ALL
01167 };
01168 int i;
01169
01170 for (i = 0; i < ARRAY_LEN(event_types); i++) {
01171 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
01172 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
01173 struct ast_event_ie_val *ie_val;
01174 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01175 if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01176 break;
01177 }
01178 }
01179 if (ie_val) {
01180 continue;
01181 }
01182 sub->cb(event_ref->event, sub->userdata);
01183 }
01184 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
01185 }
01186
01187 ao2_ref(event_ref, -1);
01188
01189 return 0;
01190 }
01191
01192 int ast_event_queue(struct ast_event *event)
01193 {
01194 struct ast_event_ref *event_ref;
01195 uint16_t host_event_type;
01196
01197 host_event_type = ntohs(event->type);
01198
01199
01200 if (host_event_type >= AST_EVENT_TOTAL) {
01201 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01202 "type '%d'!\n", host_event_type);
01203 return -1;
01204 }
01205
01206
01207 if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01208 == AST_EVENT_SUB_NONE) {
01209 ast_event_destroy(event);
01210 return 0;
01211 }
01212
01213 if (!(event_ref = alloc_event_ref())) {
01214 return -1;
01215 }
01216
01217 event_ref->event = event;
01218
01219 return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01220 }
01221
01222 static int ast_event_hash_mwi(const void *obj, const int flags)
01223 {
01224 const struct ast_event *event = obj;
01225 const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01226 const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01227
01228 return ast_str_hash_add(context, ast_str_hash(mailbox));
01229 }
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240 static int ast_event_hash_devstate(const void *obj, const int flags)
01241 {
01242 const struct ast_event *event = obj;
01243
01244 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01245 }
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01257 {
01258 const struct ast_event *event = obj;
01259
01260 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01261 }
01262
01263 static int ast_event_hash(const void *obj, const int flags)
01264 {
01265 const struct ast_event_ref *event_ref;
01266 const struct ast_event *event;
01267 ao2_hash_fn *hash_fn;
01268
01269 event_ref = obj;
01270 event = event_ref->event;
01271
01272 if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01273 return 0;
01274 }
01275
01276 return hash_fn(event, flags);
01277 }
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297 static int ast_event_cmp(void *obj, void *arg, int flags)
01298 {
01299 struct ast_event_ref *event_ref, *event_ref2;
01300 struct ast_event *event, *event2;
01301 int res = CMP_MATCH;
01302 int i;
01303 enum ast_event_ie_type *cache_args;
01304
01305 event_ref = obj;
01306 event = event_ref->event;
01307
01308 event_ref2 = arg;
01309 event2 = event_ref2->event;
01310
01311 cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01312
01313 for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01314 struct ast_event_ie_val ie_val = {
01315 .ie_pltype = ast_event_get_ie_pltype(cache_args[i]),
01316 .ie_type = cache_args[i],
01317 };
01318
01319 if (!match_ie_val(event, &ie_val, event2)) {
01320 res = 0;
01321 break;
01322 }
01323 }
01324
01325 return res;
01326 }
01327
01328 int ast_event_init(void)
01329 {
01330 int i;
01331
01332 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01333 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01334 }
01335
01336 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01337 if (!ast_event_cache[i].hash_fn) {
01338
01339 continue;
01340 }
01341
01342 if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01343 ast_event_hash, ast_event_cmp))) {
01344 return -1;
01345 }
01346 }
01347
01348 if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01349 return -1;
01350 }
01351
01352 return 0;
01353 }