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: 184631 $")
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 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00323 {
00324 va_list ap;
00325 enum ast_event_ie_type ie_type;
00326 enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00327 struct ast_event_ie_val *ie_val, *sub_ie_val;
00328 struct ast_event_sub *sub;
00329 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00330
00331 if (type >= AST_EVENT_TOTAL) {
00332 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00333 return res;
00334 }
00335
00336 va_start(ap, type);
00337 for (ie_type = va_arg(ap, enum ast_event_type);
00338 ie_type != AST_EVENT_IE_END;
00339 ie_type = va_arg(ap, enum ast_event_type))
00340 {
00341 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00342 memset(ie_value, 0, sizeof(*ie_value));
00343 ie_value->ie_type = ie_type;
00344 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00345 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00346 ie_value->payload.uint = va_arg(ap, uint32_t);
00347 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00348 ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00349 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00350 void *data = va_arg(ap, void *);
00351 size_t datalen = va_arg(ap, size_t);
00352 ie_value->payload.raw = alloca(datalen);
00353 memcpy(ie_value->payload.raw, data, datalen);
00354 ie_value->raw_datalen = datalen;
00355 }
00356 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00357 }
00358 va_end(ap);
00359
00360 AST_RWDLLIST_RDLOCK(&ast_event_subs[type]);
00361 AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
00362 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00363 AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
00364 if (sub_ie_val->ie_type == ie_val->ie_type)
00365 break;
00366 }
00367 if (!sub_ie_val) {
00368 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00369 break;
00370 continue;
00371 }
00372
00373 if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00374 continue;
00375 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00376 ie_val->payload.uint != sub_ie_val->payload.uint)
00377 break;
00378 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00379 strcmp(ie_val->payload.str, sub_ie_val->payload.str))
00380 break;
00381 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
00382 memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
00383 break;
00384 }
00385 if (!ie_val)
00386 break;
00387 }
00388 AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
00389
00390 if (sub)
00391 return AST_EVENT_SUB_EXISTS;
00392
00393 AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
00394 if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
00395 res = AST_EVENT_SUB_EXISTS;
00396 AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
00397
00398 return res;
00399 }
00400
00401 static int match_ie_val(const struct ast_event *event,
00402 const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
00403 {
00404 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
00405 uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
00406 if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
00407 return 1;
00408 return 0;
00409 }
00410
00411 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
00412 const char *str;
00413 uint32_t hash;
00414
00415 hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
00416 if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
00417 return 0;
00418 }
00419
00420 str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
00421 if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
00422 return 1;
00423 }
00424
00425 return 0;
00426 }
00427
00428 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00429 const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
00430 if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
00431 return 1;
00432 return 0;
00433 }
00434
00435 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
00436 if (ast_event_get_ie_raw(event, ie_val->ie_type))
00437 return 1;
00438 return 0;
00439 }
00440
00441 return 0;
00442 }
00443
00444 static int dump_cache_cb(void *obj, void *arg, int flags)
00445 {
00446 const struct ast_event_ref *event_ref = obj;
00447 const struct ast_event *event = event_ref->event;
00448 const struct ast_event_sub *event_sub = arg;
00449 struct ast_event_ie_val *ie_val = NULL;
00450
00451 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00452 if (!match_ie_val(event, ie_val, NULL)) {
00453 break;
00454 }
00455 }
00456
00457 if (!ie_val) {
00458
00459 event_sub->cb(event, event_sub->userdata);
00460 }
00461
00462 return 0;
00463 }
00464
00465
00466 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
00467 {
00468 ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
00469 dump_cache_cb, (void *) event_sub);
00470 }
00471
00472 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
00473 {
00474 struct ast_event_ie_val *ie_val;
00475 struct ast_event *event;
00476
00477 event = ast_event_new(AST_EVENT_SUB,
00478 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00479 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00480 AST_EVENT_IE_END);
00481
00482 if (!event)
00483 return NULL;
00484
00485 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00486 switch (ie_val->ie_pltype) {
00487 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00488 break;
00489 case AST_EVENT_IE_PLTYPE_EXISTS:
00490 ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00491 break;
00492 case AST_EVENT_IE_PLTYPE_UINT:
00493 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00494 break;
00495 case AST_EVENT_IE_PLTYPE_STR:
00496 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00497 break;
00498 case AST_EVENT_IE_PLTYPE_RAW:
00499 ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00500 break;
00501 }
00502 if (!event)
00503 break;
00504 }
00505
00506 return event;
00507 }
00508
00509
00510 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00511 {
00512 struct ast_event *event;
00513 struct ast_event_sub *sub;
00514 enum ast_event_type event_type = -1;
00515 struct ast_event_ie_val *ie_val;
00516
00517 if (event_sub->type != AST_EVENT_SUB)
00518 return;
00519
00520 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00521 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00522 event_type = ie_val->payload.uint;
00523 break;
00524 }
00525 }
00526
00527 if (event_type == -1)
00528 return;
00529
00530 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
00531 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00532 if (event_sub == sub)
00533 continue;
00534
00535 event = gen_sub_event(sub);
00536
00537 if (!event)
00538 continue;
00539
00540 event_sub->cb(event, event_sub->userdata);
00541
00542 ast_event_destroy(event);
00543 }
00544 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
00545 }
00546
00547 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
00548 ast_event_cb_t cb, void *userdata)
00549 {
00550 struct ast_event_sub *sub;
00551
00552 if (type < 0 || type >= AST_EVENT_TOTAL) {
00553 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00554 return NULL;
00555 }
00556
00557 if (!(sub = ast_calloc(1, sizeof(*sub))))
00558 return NULL;
00559
00560 sub->type = type;
00561 sub->cb = cb;
00562 sub->userdata = userdata;
00563 sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00564
00565 return sub;
00566 }
00567
00568 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
00569 enum ast_event_ie_type ie_type, uint32_t unsigned_int)
00570 {
00571 struct ast_event_ie_val *ie_val;
00572
00573 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00574 return -1;
00575
00576 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00577 return -1;
00578
00579 ie_val->ie_type = ie_type;
00580 ie_val->payload.uint = unsigned_int;
00581 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
00582
00583 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00584
00585 return 0;
00586 }
00587
00588 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
00589 enum ast_event_ie_type ie_type)
00590 {
00591 struct ast_event_ie_val *ie_val;
00592
00593 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00594 return -1;
00595
00596 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00597 return -1;
00598
00599 ie_val->ie_type = ie_type;
00600 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
00601
00602 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00603
00604 return 0;
00605 }
00606
00607 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
00608 enum ast_event_ie_type ie_type, const char *str)
00609 {
00610 struct ast_event_ie_val *ie_val;
00611
00612 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00613 return -1;
00614
00615 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00616 return -1;
00617
00618 ie_val->ie_type = ie_type;
00619 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
00620
00621 if (!(ie_val->payload.str = ast_strdup(str))) {
00622 ast_free(ie_val);
00623 return -1;
00624 }
00625
00626 ie_val->payload.hash = ast_str_hash(str);
00627
00628 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00629
00630 return 0;
00631 }
00632
00633 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
00634 enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
00635 {
00636 struct ast_event_ie_val *ie_val;
00637
00638 if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00639 return -1;
00640
00641 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00642 return -1;
00643
00644 ie_val->ie_type = ie_type;
00645 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
00646 ie_val->raw_datalen = raw_datalen;
00647
00648 if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
00649 ast_free(ie_val);
00650 return -1;
00651 }
00652
00653 memcpy(ie_val->payload.raw, data, raw_datalen);
00654
00655 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00656
00657 return 0;
00658 }
00659
00660 int ast_event_sub_activate(struct ast_event_sub *sub)
00661 {
00662 if (ast_event_check_subscriber(AST_EVENT_SUB,
00663 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00664 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00665 struct ast_event *event;
00666
00667 event = gen_sub_event(sub);
00668
00669 if (event)
00670 ast_event_queue(event);
00671 }
00672
00673 AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00674 AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
00675 AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00676
00677 return 0;
00678 }
00679
00680 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
00681 void *userdata, ...)
00682 {
00683 va_list ap;
00684 enum ast_event_ie_type ie_type;
00685 struct ast_event_sub *sub;
00686
00687 if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
00688 return NULL;
00689
00690 va_start(ap, userdata);
00691 for (ie_type = va_arg(ap, enum ast_event_type);
00692 ie_type != AST_EVENT_IE_END;
00693 ie_type = va_arg(ap, enum ast_event_type))
00694 {
00695 enum ast_event_ie_pltype ie_pltype;
00696
00697 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00698
00699 switch (ie_pltype) {
00700 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00701 break;
00702 case AST_EVENT_IE_PLTYPE_UINT:
00703 {
00704 uint32_t unsigned_int = va_arg(ap, uint32_t);
00705 ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
00706 break;
00707 }
00708 case AST_EVENT_IE_PLTYPE_STR:
00709 {
00710 const char *str = va_arg(ap, const char *);
00711 ast_event_sub_append_ie_str(sub, ie_type, str);
00712 break;
00713 }
00714 case AST_EVENT_IE_PLTYPE_RAW:
00715 {
00716 void *data = va_arg(ap, void *);
00717 size_t data_len = va_arg(ap, size_t);
00718 ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
00719 break;
00720 }
00721 case AST_EVENT_IE_PLTYPE_EXISTS:
00722 ast_event_sub_append_ie_exists(sub, ie_type);
00723 break;
00724 }
00725 }
00726 va_end(ap);
00727
00728 ast_event_sub_activate(sub);
00729
00730 return sub;
00731 }
00732
00733 void ast_event_sub_destroy(struct ast_event_sub *sub)
00734 {
00735 struct ast_event_ie_val *ie_val;
00736
00737 while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
00738 ast_event_ie_val_destroy(ie_val);
00739
00740 ast_free(sub);
00741 }
00742
00743 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
00744 {
00745 struct ast_event *event;
00746
00747 AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00748 AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
00749 AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00750
00751 if (ast_event_check_subscriber(AST_EVENT_UNSUB,
00752 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00753 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00754
00755 event = ast_event_new(AST_EVENT_UNSUB,
00756 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00757 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00758 AST_EVENT_IE_END);
00759
00760 if (event)
00761 ast_event_queue(event);
00762 }
00763
00764 ast_event_sub_destroy(sub);
00765
00766 return NULL;
00767 }
00768
00769 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00770 {
00771 iterator->event_len = ntohs(event->event_len);
00772 iterator->event = event;
00773 iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00774 return;
00775 }
00776
00777 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00778 {
00779 iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00780 return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00781 }
00782
00783 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00784 {
00785 return ntohs(iterator->ie->ie_type);
00786 }
00787
00788 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00789 {
00790 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00791 }
00792
00793 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00794 {
00795 const struct ast_event_ie_str_payload *str_payload;
00796
00797 str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
00798
00799 return str_payload->str;
00800 }
00801
00802 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00803 {
00804 return iterator->ie->ie_payload;
00805 }
00806
00807 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00808 {
00809 return ntohs(event->type);
00810 }
00811
00812 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00813 {
00814 const uint32_t *ie_val;
00815
00816 ie_val = ast_event_get_ie_raw(event, ie_type);
00817
00818 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00819 }
00820
00821 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
00822 {
00823 const struct ast_event_ie_str_payload *str_payload;
00824
00825 str_payload = ast_event_get_ie_raw(event, ie_type);
00826
00827 return str_payload->hash;
00828 }
00829
00830 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00831 {
00832 const struct ast_event_ie_str_payload *str_payload;
00833
00834 str_payload = ast_event_get_ie_raw(event, ie_type);
00835
00836 return str_payload->str;
00837 }
00838
00839 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00840 {
00841 struct ast_event_iterator iterator;
00842 int res = 0;
00843
00844 for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00845 if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
00846 return ast_event_iterator_get_ie_raw(&iterator);
00847 }
00848
00849 return NULL;
00850 }
00851
00852 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00853 const char *str)
00854 {
00855 struct ast_event_ie_str_payload *str_payload;
00856 size_t payload_len;
00857
00858 payload_len = sizeof(*str_payload) + strlen(str);
00859 str_payload = alloca(payload_len);
00860
00861 strcpy(str_payload->str, str);
00862 str_payload->hash = ast_str_hash(str);
00863
00864 return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
00865 }
00866
00867 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00868 uint32_t data)
00869 {
00870 data = htonl(data);
00871 return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00872 }
00873
00874 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00875 const void *data, size_t data_len)
00876 {
00877 struct ast_event_ie *ie;
00878 unsigned int extra_len;
00879 uint16_t event_len;
00880
00881 event_len = ntohs((*event)->event_len);
00882 extra_len = sizeof(*ie) + data_len;
00883
00884 if (!(*event = ast_realloc(*event, event_len + extra_len)))
00885 return -1;
00886
00887 ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00888 ie->ie_type = htons(ie_type);
00889 ie->ie_payload_len = htons(data_len);
00890 memcpy(ie->ie_payload, data, data_len);
00891
00892 (*event)->event_len = htons(event_len + extra_len);
00893
00894 return 0;
00895 }
00896
00897 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00898 {
00899 va_list ap;
00900 struct ast_event *event;
00901 enum ast_event_type ie_type;
00902 struct ast_event_ie_val *ie_val;
00903 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00904
00905
00906 if (type >= AST_EVENT_TOTAL) {
00907 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00908 "type '%d'!\n", type);
00909 return NULL;
00910 }
00911
00912 va_start(ap, type);
00913 for (ie_type = va_arg(ap, enum ast_event_type);
00914 ie_type != AST_EVENT_IE_END;
00915 ie_type = va_arg(ap, enum ast_event_type))
00916 {
00917 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00918 memset(ie_value, 0, sizeof(*ie_value));
00919 ie_value->ie_type = ie_type;
00920 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00921 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00922 ie_value->payload.uint = va_arg(ap, uint32_t);
00923 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00924 ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00925 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00926 void *data = va_arg(ap, void *);
00927 size_t datalen = va_arg(ap, size_t);
00928 ie_value->payload.raw = alloca(datalen);
00929 memcpy(ie_value->payload.raw, data, datalen);
00930 ie_value->raw_datalen = datalen;
00931 }
00932 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00933 }
00934 va_end(ap);
00935
00936 if (!(event = ast_calloc(1, sizeof(*event))))
00937 return NULL;
00938
00939 event->type = htons(type);
00940 event->event_len = htons(sizeof(*event));
00941
00942 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00943 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00944 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00945 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00946 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00947 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
00948 ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00949
00950 if (!event)
00951 break;
00952 }
00953
00954 if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
00955
00956
00957 ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
00958 }
00959
00960 return event;
00961 }
00962
00963 void ast_event_destroy(struct ast_event *event)
00964 {
00965 ast_free(event);
00966 }
00967
00968 static void ast_event_ref_destroy(void *obj)
00969 {
00970 struct ast_event_ref *event_ref = obj;
00971
00972 ast_event_destroy(event_ref->event);
00973 }
00974
00975 static struct ast_event *ast_event_dup(const struct ast_event *event)
00976 {
00977 struct ast_event *dup_event;
00978 uint16_t event_len;
00979
00980 event_len = ast_event_get_size(event);
00981
00982 if (!(dup_event = ast_calloc(1, event_len))) {
00983 return NULL;
00984 }
00985
00986 memcpy(dup_event, event, event_len);
00987
00988 return dup_event;
00989 }
00990
00991 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
00992 {
00993 va_list ap;
00994 enum ast_event_ie_type ie_type;
00995 struct ast_event *dup_event = NULL;
00996 struct ast_event_ref *cached_event_ref;
00997 struct ast_event *cache_arg_event;
00998 struct ast_event_ref tmp_event_ref = {
00999 .event = NULL,
01000 };
01001 struct ao2_container *container = NULL;
01002
01003 if (type >= AST_EVENT_TOTAL) {
01004 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01005 return NULL;
01006 }
01007
01008 if (!(container = ast_event_cache[type].container)) {
01009 ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01010 return NULL;
01011 }
01012
01013 if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01014 return NULL;
01015 }
01016
01017 va_start(ap, type);
01018 for (ie_type = va_arg(ap, enum ast_event_type);
01019 ie_type != AST_EVENT_IE_END;
01020 ie_type = va_arg(ap, enum ast_event_type))
01021 {
01022 enum ast_event_ie_pltype ie_pltype;
01023
01024 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01025
01026 switch (ie_pltype) {
01027 case AST_EVENT_IE_PLTYPE_UINT:
01028 ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01029 break;
01030 case AST_EVENT_IE_PLTYPE_STR:
01031 ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01032 break;
01033 case AST_EVENT_IE_PLTYPE_RAW:
01034 {
01035 void *data = va_arg(ap, void *);
01036 size_t datalen = va_arg(ap, size_t);
01037 ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01038 }
01039 case AST_EVENT_IE_PLTYPE_EXISTS:
01040 ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01041 break;
01042 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01043 break;
01044 }
01045 }
01046 va_end(ap);
01047
01048 tmp_event_ref.event = cache_arg_event;
01049
01050 cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01051
01052 ast_event_destroy(cache_arg_event);
01053 cache_arg_event = NULL;
01054
01055 if (cached_event_ref) {
01056 dup_event = ast_event_dup(cached_event_ref->event);
01057 ao2_ref(cached_event_ref, -1);
01058 cached_event_ref = NULL;
01059 }
01060
01061 return dup_event;
01062 }
01063
01064 static struct ast_event_ref *alloc_event_ref(void)
01065 {
01066 return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01067 }
01068
01069
01070
01071 static int attribute_unused ast_event_dup_and_cache(const struct ast_event *event)
01072 {
01073 struct ast_event *dup_event;
01074 struct ast_event_ref *event_ref;
01075
01076 if (!(dup_event = ast_event_dup(event))) {
01077 return -1;
01078 }
01079
01080 if (!(event_ref = alloc_event_ref())) {
01081 ast_event_destroy(dup_event);
01082 return -1;
01083 }
01084
01085 event_ref->event = dup_event;
01086
01087 ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
01088
01089 ao2_ref(event_ref, -1);
01090
01091 return 0;
01092 }
01093
01094 int ast_event_queue_and_cache(struct ast_event *event)
01095 {
01096 struct ao2_container *container;
01097 struct ast_event_ref tmp_event_ref = {
01098 .event = event,
01099 };
01100
01101 if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
01102 ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01103 goto queue_event;
01104 }
01105
01106
01107 ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01108 ast_event_cmp, &tmp_event_ref);
01109
01110 queue_event:
01111 return ast_event_queue(event);
01112 }
01113
01114 static int handle_event(void *data)
01115 {
01116 struct ast_event_ref *event_ref = data;
01117 struct ast_event_sub *sub;
01118 uint16_t host_event_type;
01119
01120 host_event_type = ntohs(event_ref->event->type);
01121
01122
01123 AST_RWDLLIST_RDLOCK(&ast_event_subs[host_event_type]);
01124 AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
01125 struct ast_event_ie_val *ie_val;
01126 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01127 if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01128 break;
01129 }
01130 }
01131 if (ie_val) {
01132 continue;
01133 }
01134 sub->cb(event_ref->event, sub->userdata);
01135 }
01136 AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]);
01137
01138
01139 AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
01140 AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry) {
01141 sub->cb(event_ref->event, sub->userdata);
01142 }
01143 AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
01144
01145 ao2_ref(event_ref, -1);
01146
01147 return 0;
01148 }
01149
01150 int ast_event_queue(struct ast_event *event)
01151 {
01152 struct ast_event_ref *event_ref;
01153 uint16_t host_event_type;
01154
01155 host_event_type = ntohs(event->type);
01156
01157
01158 if (host_event_type >= AST_EVENT_TOTAL) {
01159 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01160 "type '%d'!\n", host_event_type);
01161 return -1;
01162 }
01163
01164
01165 if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01166 == AST_EVENT_SUB_NONE) {
01167 ast_event_destroy(event);
01168 return 0;
01169 }
01170
01171 if (!(event_ref = alloc_event_ref())) {
01172 return -1;
01173 }
01174
01175 event_ref->event = event;
01176
01177 return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01178 }
01179
01180 static int ast_event_hash_mwi(const void *obj, const int flags)
01181 {
01182 const struct ast_event *event = obj;
01183 const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01184 const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01185
01186 return ast_str_hash_add(context, ast_str_hash(mailbox));
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198 static int ast_event_hash_devstate(const void *obj, const int flags)
01199 {
01200 const struct ast_event *event = obj;
01201
01202 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01203 }
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01215 {
01216 const struct ast_event *event = obj;
01217
01218 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01219 }
01220
01221 static int ast_event_hash(const void *obj, const int flags)
01222 {
01223 const struct ast_event_ref *event_ref;
01224 const struct ast_event *event;
01225 ao2_hash_fn *hash_fn;
01226
01227 event_ref = obj;
01228 event = event_ref->event;
01229
01230 if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01231 return 0;
01232 }
01233
01234 return hash_fn(event, flags);
01235 }
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 static int ast_event_cmp(void *obj, void *arg, int flags)
01256 {
01257 struct ast_event_ref *event_ref, *event_ref2;
01258 struct ast_event *event, *event2;
01259 int res = CMP_MATCH;
01260 int i;
01261 enum ast_event_ie_type *cache_args;
01262
01263 event_ref = obj;
01264 event = event_ref->event;
01265
01266 event_ref2 = arg;
01267 event2 = event_ref2->event;
01268
01269 cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01270
01271 for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01272 struct ast_event_ie_val ie_val = {
01273 .ie_type = cache_args[i],
01274 };
01275
01276 if (!match_ie_val(event, &ie_val, event2)) {
01277 res = 0;
01278 break;
01279 }
01280 }
01281
01282 return res;
01283 }
01284
01285 int ast_event_init(void)
01286 {
01287 int i;
01288
01289 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01290 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01291 }
01292
01293 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01294 if (!ast_event_cache[i].hash_fn) {
01295
01296 continue;
01297 }
01298
01299 if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01300 ast_event_hash, ast_event_cmp))) {
01301 return -1;
01302 }
01303 }
01304
01305 if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01306 return -1;
01307 }
01308
01309 return 0;
01310 }