00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374197 $")
00033
00034 #include "asterisk/_private.h"
00035
00036 #include "asterisk/event.h"
00037 #include "asterisk/linkedlists.h"
00038 #include "asterisk/dlinkedlists.h"
00039 #include "asterisk/lock.h"
00040 #include "asterisk/utils.h"
00041 #include "asterisk/unaligned.h"
00042 #include "asterisk/utils.h"
00043 #include "asterisk/taskprocessor.h"
00044 #include "asterisk/astobj2.h"
00045 #include "asterisk/cli.h"
00046
00047 static struct ast_taskprocessor *event_dispatcher;
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 struct ast_event_ie {
00058 enum ast_event_ie_type ie_type:16;
00059
00060 uint16_t ie_payload_len;
00061 unsigned char ie_payload[0];
00062 } __attribute__((packed));
00063
00064
00065
00066
00067 struct ast_event_ie_str_payload {
00068
00069 uint32_t hash;
00070
00071 char str[1];
00072 } __attribute__((packed));
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 struct ast_event {
00086
00087 enum ast_event_type type:16;
00088
00089 uint16_t event_len:16;
00090
00091 unsigned char payload[0];
00092 } __attribute__((packed));
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 struct ast_event_ref {
00105 struct ast_event *event;
00106 unsigned int cache;
00107 };
00108
00109 struct ast_event_ie_val {
00110 AST_LIST_ENTRY(ast_event_ie_val) entry;
00111 enum ast_event_ie_type ie_type;
00112 enum ast_event_ie_pltype ie_pltype;
00113 union {
00114 uint32_t uint;
00115 struct {
00116 uint32_t hash;
00117 const char *str;
00118 };
00119 void *raw;
00120 } payload;
00121 size_t raw_datalen;
00122 };
00123
00124
00125 struct ast_event_sub {
00126 enum ast_event_type type;
00127 ast_event_cb_t cb;
00128 char description[64];
00129 void *userdata;
00130 uint32_t uniqueid;
00131 AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
00132 AST_RWDLLIST_ENTRY(ast_event_sub) entry;
00133 };
00134
00135 static uint32_t sub_uniqueid;
00136
00137
00138
00139 static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
00140
00141 static int ast_event_cmp(void *obj, void *arg, int flags);
00142 static int ast_event_hash_mwi(const void *obj, const int flags);
00143 static int ast_event_hash_devstate(const void *obj, const int flags);
00144 static int ast_event_hash_devstate_change(const void *obj, const int flags);
00145 static int ast_event_hash_presence_state_change(const void *obj, const int flags);
00146
00147 #ifdef LOW_MEMORY
00148 #define NUM_CACHE_BUCKETS 17
00149 #else
00150 #define NUM_CACHE_BUCKETS 563
00151 #endif
00152
00153 #define MAX_CACHE_ARGS 8
00154
00155
00156
00157
00158 static struct {
00159
00160
00161
00162
00163
00164
00165 struct ao2_container *container;
00166
00167 ao2_hash_fn *hash_fn;
00168
00169
00170
00171
00172
00173
00174
00175
00176 enum ast_event_ie_type cache_args[MAX_CACHE_ARGS];
00177 } ast_event_cache[AST_EVENT_TOTAL] = {
00178 [AST_EVENT_MWI] = {
00179 .hash_fn = ast_event_hash_mwi,
00180 .cache_args = { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_CONTEXT },
00181 },
00182 [AST_EVENT_DEVICE_STATE] = {
00183 .hash_fn = ast_event_hash_devstate,
00184 .cache_args = { AST_EVENT_IE_DEVICE, },
00185 },
00186 [AST_EVENT_DEVICE_STATE_CHANGE] = {
00187 .hash_fn = ast_event_hash_devstate_change,
00188 .cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
00189 },
00190 [AST_EVENT_PRESENCE_STATE] = {
00191 .hash_fn = ast_event_hash_presence_state_change,
00192 .cache_args = { AST_EVENT_IE_PRESENCE_STATE, },
00193 },
00194
00195 };
00196
00197
00198
00199
00200
00201
00202 static const char * const cached_event_types[] = { "MWI", "DeviceState", "DeviceStateChange", NULL };
00203
00204
00205
00206
00207 static const char * const event_names[AST_EVENT_TOTAL] = {
00208 [AST_EVENT_ALL] = "All",
00209 [AST_EVENT_CUSTOM] = "Custom",
00210 [AST_EVENT_MWI] = "MWI",
00211 [AST_EVENT_SUB] = "Subscription",
00212 [AST_EVENT_UNSUB] = "Unsubscription",
00213 [AST_EVENT_DEVICE_STATE] = "DeviceState",
00214 [AST_EVENT_DEVICE_STATE_CHANGE] = "DeviceStateChange",
00215 [AST_EVENT_CEL] = "CEL",
00216 [AST_EVENT_SECURITY] = "Security",
00217 [AST_EVENT_NETWORK_CHANGE] = "NetworkChange",
00218 };
00219
00220
00221
00222
00223 static const struct ie_map {
00224 enum ast_event_ie_pltype ie_pltype;
00225 const char *name;
00226 } ie_maps[AST_EVENT_IE_TOTAL] = {
00227 [AST_EVENT_IE_NEWMSGS] = { AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
00228 [AST_EVENT_IE_OLDMSGS] = { AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
00229 [AST_EVENT_IE_MAILBOX] = { AST_EVENT_IE_PLTYPE_STR, "Mailbox" },
00230 [AST_EVENT_IE_UNIQUEID] = { AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
00231 [AST_EVENT_IE_EVENTTYPE] = { AST_EVENT_IE_PLTYPE_UINT, "EventType" },
00232 [AST_EVENT_IE_EXISTS] = { AST_EVENT_IE_PLTYPE_UINT, "Exists" },
00233 [AST_EVENT_IE_DEVICE] = { AST_EVENT_IE_PLTYPE_STR, "Device" },
00234 [AST_EVENT_IE_STATE] = { AST_EVENT_IE_PLTYPE_UINT, "State" },
00235 [AST_EVENT_IE_CONTEXT] = { AST_EVENT_IE_PLTYPE_STR, "Context" },
00236 [AST_EVENT_IE_EID] = { AST_EVENT_IE_PLTYPE_RAW, "EntityID" },
00237 [AST_EVENT_IE_CEL_EVENT_TYPE] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventType" },
00238 [AST_EVENT_IE_CEL_EVENT_TIME] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTime" },
00239 [AST_EVENT_IE_CEL_EVENT_TIME_USEC] = { AST_EVENT_IE_PLTYPE_UINT, "CELEventTimeUSec" },
00240 [AST_EVENT_IE_CEL_USEREVENT_NAME] = { AST_EVENT_IE_PLTYPE_UINT, "CELUserEventName" },
00241 [AST_EVENT_IE_CEL_CIDNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDName" },
00242 [AST_EVENT_IE_CEL_CIDNUM] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDNum" },
00243 [AST_EVENT_IE_CEL_EXTEN] = { AST_EVENT_IE_PLTYPE_STR, "CELExten" },
00244 [AST_EVENT_IE_CEL_CONTEXT] = { AST_EVENT_IE_PLTYPE_STR, "CELContext" },
00245 [AST_EVENT_IE_CEL_CHANNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELChanName" },
00246 [AST_EVENT_IE_CEL_APPNAME] = { AST_EVENT_IE_PLTYPE_STR, "CELAppName" },
00247 [AST_EVENT_IE_CEL_APPDATA] = { AST_EVENT_IE_PLTYPE_STR, "CELAppData" },
00248 [AST_EVENT_IE_CEL_AMAFLAGS] = { AST_EVENT_IE_PLTYPE_STR, "CELAMAFlags" },
00249 [AST_EVENT_IE_CEL_ACCTCODE] = { AST_EVENT_IE_PLTYPE_UINT, "CELAcctCode" },
00250 [AST_EVENT_IE_CEL_UNIQUEID] = { AST_EVENT_IE_PLTYPE_STR, "CELUniqueID" },
00251 [AST_EVENT_IE_CEL_USERFIELD] = { AST_EVENT_IE_PLTYPE_STR, "CELUserField" },
00252 [AST_EVENT_IE_CEL_CIDANI] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDani" },
00253 [AST_EVENT_IE_CEL_CIDRDNIS] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDrdnis" },
00254 [AST_EVENT_IE_CEL_CIDDNID] = { AST_EVENT_IE_PLTYPE_STR, "CELCIDdnid" },
00255 [AST_EVENT_IE_CEL_PEER] = { AST_EVENT_IE_PLTYPE_STR, "CELPeer" },
00256 [AST_EVENT_IE_CEL_LINKEDID] = { AST_EVENT_IE_PLTYPE_STR, "CELLinkedID" },
00257 [AST_EVENT_IE_CEL_PEERACCT] = { AST_EVENT_IE_PLTYPE_STR, "CELPeerAcct" },
00258 [AST_EVENT_IE_CEL_EXTRA] = { AST_EVENT_IE_PLTYPE_STR, "CELExtra" },
00259 [AST_EVENT_IE_SECURITY_EVENT] = { AST_EVENT_IE_PLTYPE_STR, "SecurityEvent" },
00260 [AST_EVENT_IE_EVENT_VERSION] = { AST_EVENT_IE_PLTYPE_UINT, "EventVersion" },
00261 [AST_EVENT_IE_SERVICE] = { AST_EVENT_IE_PLTYPE_STR, "Service" },
00262 [AST_EVENT_IE_MODULE] = { AST_EVENT_IE_PLTYPE_STR, "Module" },
00263 [AST_EVENT_IE_ACCOUNT_ID] = { AST_EVENT_IE_PLTYPE_STR, "AccountID" },
00264 [AST_EVENT_IE_SESSION_ID] = { AST_EVENT_IE_PLTYPE_STR, "SessionID" },
00265 [AST_EVENT_IE_SESSION_TV] = { AST_EVENT_IE_PLTYPE_STR, "SessionTV" },
00266 [AST_EVENT_IE_ACL_NAME] = { AST_EVENT_IE_PLTYPE_STR, "ACLName" },
00267 [AST_EVENT_IE_LOCAL_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "LocalAddress" },
00268 [AST_EVENT_IE_REMOTE_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "RemoteAddress" },
00269 [AST_EVENT_IE_EVENT_TV] = { AST_EVENT_IE_PLTYPE_STR, "EventTV" },
00270 [AST_EVENT_IE_REQUEST_TYPE] = { AST_EVENT_IE_PLTYPE_STR, "RequestType" },
00271 [AST_EVENT_IE_REQUEST_PARAMS] = { AST_EVENT_IE_PLTYPE_STR, "RequestParams" },
00272 [AST_EVENT_IE_AUTH_METHOD] = { AST_EVENT_IE_PLTYPE_STR, "AuthMethod" },
00273 [AST_EVENT_IE_SEVERITY] = { AST_EVENT_IE_PLTYPE_STR, "Severity" },
00274 [AST_EVENT_IE_EXPECTED_ADDR] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedAddress" },
00275 [AST_EVENT_IE_CHALLENGE] = { AST_EVENT_IE_PLTYPE_STR, "Challenge" },
00276 [AST_EVENT_IE_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "Response" },
00277 [AST_EVENT_IE_EXPECTED_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedResponse" },
00278 [AST_EVENT_IE_RECEIVED_CHALLENGE] = { AST_EVENT_IE_PLTYPE_STR, "ReceivedChallenge" },
00279 [AST_EVENT_IE_RECEIVED_HASH] = { AST_EVENT_IE_PLTYPE_STR, "ReceivedHash" },
00280 [AST_EVENT_IE_USING_PASSWORD] = { AST_EVENT_IE_PLTYPE_UINT, "UsingPassword" },
00281 [AST_EVENT_IE_ATTEMPTED_TRANSPORT] = { AST_EVENT_IE_PLTYPE_STR, "AttemptedTransport" },
00282
00283 };
00284
00285 const char *ast_event_get_type_name(const struct ast_event *event)
00286 {
00287 enum ast_event_type type;
00288
00289 type = ast_event_get_type(event);
00290
00291 if (type < 0 || type >= ARRAY_LEN(event_names)) {
00292 ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
00293 return "";
00294 }
00295
00296 return event_names[type];
00297 }
00298
00299 int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
00300 {
00301 int i;
00302
00303 for (i = 0; i < ARRAY_LEN(event_names); i++) {
00304 if (ast_strlen_zero(event_names[i]) || strcasecmp(event_names[i], str)) {
00305 continue;
00306 }
00307
00308 *event_type = i;
00309 return 0;
00310 }
00311
00312 return -1;
00313 }
00314
00315 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
00316 {
00317 if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
00318 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
00319 return "";
00320 }
00321
00322 return ie_maps[ie_type].name;
00323 }
00324
00325 enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
00326 {
00327 if (ie_type <= 0 || ie_type >= ARRAY_LEN(ie_maps)) {
00328 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
00329 return AST_EVENT_IE_PLTYPE_UNKNOWN;
00330 }
00331
00332 return ie_maps[ie_type].ie_pltype;
00333 }
00334
00335 int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
00336 {
00337 int i;
00338
00339 for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
00340 if (strcasecmp(ie_maps[i].name, str)) {
00341 continue;
00342 }
00343
00344 *ie_type = i;
00345 return 0;
00346 }
00347
00348 return -1;
00349 }
00350
00351 size_t ast_event_get_size(const struct ast_event *event)
00352 {
00353 size_t res;
00354
00355 res = ntohs(event->event_len);
00356
00357 return res;
00358 }
00359
00360 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
00361 {
00362 switch (ie_val->ie_pltype) {
00363 case AST_EVENT_IE_PLTYPE_STR:
00364 ast_free((char *) ie_val->payload.str);
00365 break;
00366 case AST_EVENT_IE_PLTYPE_RAW:
00367 ast_free(ie_val->payload.raw);
00368 break;
00369 case AST_EVENT_IE_PLTYPE_UINT:
00370 case AST_EVENT_IE_PLTYPE_BITFLAGS:
00371 case AST_EVENT_IE_PLTYPE_EXISTS:
00372 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00373 break;
00374 }
00375
00376 ast_free(ie_val);
00377 }
00378
00379
00380 struct ast_ev_check_list {
00381 AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
00382 };
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 static int match_sub_ie_val_to_event(const struct ast_event_ie_val *sub_ie_val, const struct ast_ev_check_list *check_ie_vals)
00395 {
00396 const struct ast_event_ie_val *event_ie_val;
00397 int res = 0;
00398
00399 AST_LIST_TRAVERSE(&check_ie_vals->ie_vals, event_ie_val, entry) {
00400 if (sub_ie_val->ie_type == event_ie_val->ie_type) {
00401 break;
00402 }
00403 }
00404 if (!event_ie_val) {
00405
00406 return 0;
00407 }
00408
00409 if (sub_ie_val->ie_pltype != event_ie_val->ie_pltype) {
00410 if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
00411
00412 return 1;
00413 }
00414
00415 return 0;
00416 }
00417
00418 switch (sub_ie_val->ie_pltype) {
00419 case AST_EVENT_IE_PLTYPE_UINT:
00420 res = (sub_ie_val->payload.uint == event_ie_val->payload.uint);
00421 break;
00422 case AST_EVENT_IE_PLTYPE_BITFLAGS:
00423
00424
00425
00426
00427 res = (sub_ie_val->payload.uint & event_ie_val->payload.uint);
00428 break;
00429 case AST_EVENT_IE_PLTYPE_STR:
00430 {
00431 const char *substr = sub_ie_val->payload.str;
00432 const char *estr = event_ie_val->payload.str;
00433 if (sub_ie_val->ie_type == AST_EVENT_IE_DEVICE) {
00434 substr = ast_tech_to_upper(ast_strdupa(substr));
00435 estr = ast_tech_to_upper(ast_strdupa(estr));
00436 }
00437 res = !strcmp(substr, estr);
00438 break;
00439 }
00440 case AST_EVENT_IE_PLTYPE_RAW:
00441 res = (sub_ie_val->raw_datalen == event_ie_val->raw_datalen
00442 && !memcmp(sub_ie_val->payload.raw, event_ie_val->payload.raw,
00443 sub_ie_val->raw_datalen));
00444 break;
00445 case AST_EVENT_IE_PLTYPE_EXISTS:
00446
00447 break;
00448 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00449
00450
00451
00452
00453 break;
00454 }
00455
00456 return res;
00457 }
00458
00459 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00460 {
00461 va_list ap;
00462 enum ast_event_ie_type ie_type;
00463 enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00464 struct ast_event_ie_val *ie_val;
00465 struct ast_event_sub *sub;
00466 struct ast_ev_check_list check_ie_vals = {
00467 .ie_vals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
00468 };
00469 const enum ast_event_type event_types[] = { type, AST_EVENT_ALL };
00470 int i;
00471 int want_specific_event;
00472
00473 if (type >= AST_EVENT_TOTAL) {
00474 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00475 return res;
00476 }
00477
00478 want_specific_event = 0;
00479 va_start(ap, type);
00480 for (ie_type = va_arg(ap, enum ast_event_ie_type);
00481 ie_type != AST_EVENT_IE_END;
00482 ie_type = va_arg(ap, enum ast_event_ie_type))
00483 {
00484 struct ast_event_ie_val *ie_value = ast_alloca(sizeof(*ie_value));
00485 int insert = 0;
00486
00487 memset(ie_value, 0, sizeof(*ie_value));
00488 ie_value->ie_type = ie_type;
00489 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00490 switch (ie_value->ie_pltype) {
00491 case AST_EVENT_IE_PLTYPE_UINT:
00492 ie_value->payload.uint = va_arg(ap, uint32_t);
00493 insert = 1;
00494 break;
00495 case AST_EVENT_IE_PLTYPE_BITFLAGS:
00496 ie_value->payload.uint = va_arg(ap, uint32_t);
00497 insert = 1;
00498 break;
00499 case AST_EVENT_IE_PLTYPE_STR:
00500 ie_value->payload.str = va_arg(ap, const char *);
00501 insert = 1;
00502 break;
00503 case AST_EVENT_IE_PLTYPE_RAW:
00504 {
00505 void *data = va_arg(ap, void *);
00506 size_t datalen = va_arg(ap, size_t);
00507
00508 ie_value->payload.raw = ast_alloca(datalen);
00509 memcpy(ie_value->payload.raw, data, datalen);
00510 ie_value->raw_datalen = datalen;
00511 insert = 1;
00512 break;
00513 }
00514 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00515 case AST_EVENT_IE_PLTYPE_EXISTS:
00516
00517 break;
00518 }
00519
00520 if (insert) {
00521 want_specific_event = 1;
00522 AST_LIST_INSERT_TAIL(&check_ie_vals.ie_vals, ie_value, entry);
00523 } else {
00524 ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
00525 }
00526 }
00527 va_end(ap);
00528
00529 for (i = 0; i < ARRAY_LEN(event_types); i++) {
00530 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
00531 if (want_specific_event) {
00532 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
00533 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00534 if (!match_sub_ie_val_to_event(ie_val, &check_ie_vals)) {
00535
00536 break;
00537 }
00538 }
00539 if (!ie_val) {
00540
00541 break;
00542 }
00543 }
00544 } else {
00545
00546 sub = AST_RWLIST_FIRST(&ast_event_subs[event_types[i]]);
00547 }
00548 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
00549 if (sub) {
00550 break;
00551 }
00552 }
00553
00554 return sub ? AST_EVENT_SUB_EXISTS : AST_EVENT_SUB_NONE;
00555 }
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 static int match_ie_val(const struct ast_event *event,
00571 const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
00572 {
00573 switch (ie_val->ie_pltype) {
00574 case AST_EVENT_IE_PLTYPE_UINT:
00575 {
00576 uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
00577
00578 return (val == ast_event_get_ie_uint(event, ie_val->ie_type)) ? 1 : 0;
00579 }
00580
00581 case AST_EVENT_IE_PLTYPE_BITFLAGS:
00582 {
00583 uint32_t flags = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
00584
00585
00586
00587
00588
00589 return (flags & ast_event_get_ie_bitflags(event, ie_val->ie_type)) ? 1 : 0;
00590 }
00591
00592 case AST_EVENT_IE_PLTYPE_STR:
00593 {
00594 const char *str;
00595 uint32_t hash;
00596
00597 hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
00598 if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
00599 return 0;
00600 }
00601
00602 str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
00603 if (str) {
00604 const char *e1str, *e2str;
00605 e1str = ast_event_get_ie_str(event, ie_val->ie_type);
00606 e2str = str;
00607
00608 if (ie_val->ie_type == AST_EVENT_IE_DEVICE) {
00609 e1str = ast_tech_to_upper(ast_strdupa(e1str));
00610 e2str = ast_tech_to_upper(ast_strdupa(e2str));
00611 }
00612
00613 if (!strcmp(e1str, e2str)) {
00614 return 1;
00615 }
00616 }
00617
00618 return 0;
00619 }
00620
00621 case AST_EVENT_IE_PLTYPE_RAW:
00622 {
00623 const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
00624 uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
00625
00626 return (buf
00627 && ie_payload_len == ast_event_get_ie_raw_payload_len(event, ie_val->ie_type)
00628 && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
00629 }
00630
00631 case AST_EVENT_IE_PLTYPE_EXISTS:
00632 {
00633 return ast_event_get_ie_raw(event, ie_val->ie_type) ? 1 : 0;
00634 }
00635
00636 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00637 return 0;
00638 }
00639
00640 return 0;
00641 }
00642
00643 static int dump_cache_cb(void *obj, void *arg, int flags)
00644 {
00645 const struct ast_event_ref *event_ref = obj;
00646 const struct ast_event *event = event_ref->event;
00647 const struct ast_event_sub *event_sub = arg;
00648 struct ast_event_ie_val *ie_val = NULL;
00649
00650 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00651 if (!match_ie_val(event, ie_val, NULL)) {
00652 break;
00653 }
00654 }
00655
00656 if (!ie_val) {
00657
00658 event_sub->cb(event, event_sub->userdata);
00659 }
00660
00661 return 0;
00662 }
00663
00664
00665 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
00666 {
00667 if (!ast_event_cache[event_sub->type].container) {
00668 return;
00669 }
00670
00671 ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
00672 dump_cache_cb, (void *) event_sub);
00673 }
00674
00675 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
00676 {
00677 struct ast_event_ie_val *ie_val;
00678 struct ast_event *event;
00679
00680 event = ast_event_new(AST_EVENT_SUB,
00681 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00682 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00683 AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
00684 AST_EVENT_IE_END);
00685 if (!event)
00686 return NULL;
00687
00688 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00689 switch (ie_val->ie_pltype) {
00690 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00691 break;
00692 case AST_EVENT_IE_PLTYPE_EXISTS:
00693 ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00694 break;
00695 case AST_EVENT_IE_PLTYPE_UINT:
00696 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00697 break;
00698 case AST_EVENT_IE_PLTYPE_BITFLAGS:
00699 ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
00700 break;
00701 case AST_EVENT_IE_PLTYPE_STR:
00702 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00703 break;
00704 case AST_EVENT_IE_PLTYPE_RAW:
00705 ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00706 break;
00707 }
00708 if (!event)
00709 break;
00710 }
00711
00712 return event;
00713 }
00714
00715
00716 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00717 {
00718 struct ast_event *event;
00719 struct ast_event_sub *sub;
00720 enum ast_event_type event_type = -1;
00721 struct ast_event_ie_val *ie_val;
00722
00723 if (event_sub->type != AST_EVENT_SUB)
00724 return;
00725
00726 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00727 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00728 event_type = ie_val->payload.uint;
00729 break;
00730 }
00731 }
00732
00733 if (event_type == -1)
00734 return;
00735
00736 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
00737 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00738 if (event_sub == sub) {
00739 continue;
00740 }
00741
00742 event = gen_sub_event(sub);
00743 if (!event) {
00744 continue;
00745 }
00746
00747 event_sub->cb(event, event_sub->userdata);
00748
00749 ast_event_destroy(event);
00750 }
00751 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
00752 }
00753
00754 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
00755 ast_event_cb_t cb, void *userdata)
00756 {
00757 struct ast_event_sub *sub;
00758
00759 if (type < 0 || type >= AST_EVENT_TOTAL) {
00760 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00761 return NULL;
00762 }
00763
00764 if (!(sub = ast_calloc(1, sizeof(*sub)))) {
00765 return NULL;
00766 }
00767
00768 sub->type = type;
00769 sub->cb = cb;
00770 sub->userdata = userdata;
00771 sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00772
00773 return sub;
00774 }
00775
00776 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
00777 enum ast_event_ie_type ie_type, uint32_t unsigned_int)
00778 {
00779 struct ast_event_ie_val *ie_val;
00780
00781 if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
00782 return -1;
00783 }
00784
00785 if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
00786 return -1;
00787 }
00788
00789 ie_val->ie_type = ie_type;
00790 ie_val->payload.uint = unsigned_int;
00791 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
00792
00793 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00794
00795 return 0;
00796 }
00797
00798 int ast_event_sub_append_ie_bitflags(struct ast_event_sub *sub,
00799 enum ast_event_ie_type ie_type, uint32_t flags)
00800 {
00801 struct ast_event_ie_val *ie_val;
00802
00803 if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
00804 return -1;
00805 }
00806
00807 if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
00808 return -1;
00809 }
00810
00811 ie_val->ie_type = ie_type;
00812 ie_val->payload.uint = flags;
00813 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_BITFLAGS;
00814
00815 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00816
00817 return 0;
00818 }
00819
00820 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
00821 enum ast_event_ie_type ie_type)
00822 {
00823 struct ast_event_ie_val *ie_val;
00824
00825 if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
00826 return -1;
00827 }
00828
00829 if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
00830 return -1;
00831 }
00832
00833 ie_val->ie_type = ie_type;
00834 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
00835
00836 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00837
00838 return 0;
00839 }
00840
00841 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
00842 enum ast_event_ie_type ie_type, const char *str)
00843 {
00844 struct ast_event_ie_val *ie_val;
00845
00846 if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
00847 return -1;
00848 }
00849
00850 if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
00851 return -1;
00852 }
00853
00854 ie_val->ie_type = ie_type;
00855 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
00856
00857 if (!(ie_val->payload.str = ast_strdup(str))) {
00858 ast_free(ie_val);
00859 return -1;
00860 }
00861
00862 if (ie_type == AST_EVENT_IE_DEVICE) {
00863 char *uppertech = ast_strdupa(str);
00864 ast_tech_to_upper(uppertech);
00865 ie_val->payload.hash = ast_str_hash(uppertech);
00866 } else {
00867 ie_val->payload.hash = ast_str_hash(str);
00868 }
00869
00870 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00871
00872 return 0;
00873 }
00874
00875 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
00876 enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
00877 {
00878 struct ast_event_ie_val *ie_val;
00879
00880 if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
00881 return -1;
00882 }
00883
00884 if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
00885 return -1;
00886 }
00887
00888 ie_val->ie_type = ie_type;
00889 ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
00890 ie_val->raw_datalen = raw_datalen;
00891
00892 if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
00893 ast_free(ie_val);
00894 return -1;
00895 }
00896
00897 memcpy(ie_val->payload.raw, data, raw_datalen);
00898
00899 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00900
00901 return 0;
00902 }
00903
00904 int ast_event_sub_activate(struct ast_event_sub *sub)
00905 {
00906 if (ast_event_check_subscriber(AST_EVENT_SUB,
00907 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00908 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00909 struct ast_event *event;
00910
00911 event = gen_sub_event(sub);
00912 if (event && ast_event_queue(event)) {
00913 ast_event_destroy(event);
00914 }
00915 }
00916
00917 AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00918 AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
00919 AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00920
00921 return 0;
00922 }
00923
00924 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
00925 const char *description, void *userdata, ...)
00926 {
00927 va_list ap;
00928 enum ast_event_ie_type ie_type;
00929 struct ast_event_sub *sub;
00930
00931 if (!(sub = ast_event_subscribe_new(type, cb, userdata))) {
00932 return NULL;
00933 }
00934
00935 ast_copy_string(sub->description, description, sizeof(sub->description));
00936
00937 va_start(ap, userdata);
00938 for (ie_type = va_arg(ap, enum ast_event_ie_type);
00939 ie_type != AST_EVENT_IE_END;
00940 ie_type = va_arg(ap, enum ast_event_ie_type))
00941 {
00942 enum ast_event_ie_pltype ie_pltype;
00943
00944 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00945
00946 switch (ie_pltype) {
00947 case AST_EVENT_IE_PLTYPE_UNKNOWN:
00948 break;
00949 case AST_EVENT_IE_PLTYPE_UINT:
00950 {
00951 uint32_t unsigned_int = va_arg(ap, uint32_t);
00952 ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
00953 break;
00954 }
00955 case AST_EVENT_IE_PLTYPE_BITFLAGS:
00956 {
00957 uint32_t unsigned_int = va_arg(ap, uint32_t);
00958 ast_event_sub_append_ie_bitflags(sub, ie_type, unsigned_int);
00959 break;
00960 }
00961 case AST_EVENT_IE_PLTYPE_STR:
00962 {
00963 const char *str = va_arg(ap, const char *);
00964 ast_event_sub_append_ie_str(sub, ie_type, str);
00965 break;
00966 }
00967 case AST_EVENT_IE_PLTYPE_RAW:
00968 {
00969 void *data = va_arg(ap, void *);
00970 size_t data_len = va_arg(ap, size_t);
00971 ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
00972 break;
00973 }
00974 case AST_EVENT_IE_PLTYPE_EXISTS:
00975 ast_event_sub_append_ie_exists(sub, ie_type);
00976 break;
00977 }
00978 }
00979 va_end(ap);
00980
00981 ast_event_sub_activate(sub);
00982
00983 return sub;
00984 }
00985
00986 void ast_event_sub_destroy(struct ast_event_sub *sub)
00987 {
00988 struct ast_event_ie_val *ie_val;
00989
00990 while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry))) {
00991 ast_event_ie_val_destroy(ie_val);
00992 }
00993
00994 ast_free(sub);
00995 }
00996
00997 const char *ast_event_subscriber_get_description(struct ast_event_sub *sub)
00998 {
00999 return sub ? sub->description : NULL;
01000 }
01001
01002 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
01003 {
01004 struct ast_event *event;
01005
01006 AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
01007 AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
01008 AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
01009
01010 if (ast_event_check_subscriber(AST_EVENT_UNSUB,
01011 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
01012 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
01013
01014 event = ast_event_new(AST_EVENT_UNSUB,
01015 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
01016 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
01017 AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
01018 AST_EVENT_IE_END);
01019 if (event && ast_event_queue(event)) {
01020 ast_event_destroy(event);
01021 }
01022 }
01023
01024 ast_event_sub_destroy(sub);
01025
01026 return NULL;
01027 }
01028
01029 int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
01030 {
01031 int res = 0;
01032
01033 iterator->event_len = ast_event_get_size(event);
01034 iterator->event = event;
01035 if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
01036 iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
01037 } else {
01038 iterator->ie = NULL;
01039 res = -1;
01040 }
01041
01042 return res;
01043 }
01044
01045 int ast_event_iterator_next(struct ast_event_iterator *iterator)
01046 {
01047 iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
01048 return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
01049 }
01050
01051 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
01052 {
01053 return ntohs(iterator->ie->ie_type);
01054 }
01055
01056 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
01057 {
01058 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
01059 }
01060
01061 uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator)
01062 {
01063 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
01064 }
01065
01066 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
01067 {
01068 const struct ast_event_ie_str_payload *str_payload;
01069
01070 str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
01071
01072 return str_payload ? str_payload->str : NULL;
01073 }
01074
01075 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
01076 {
01077 return iterator->ie->ie_payload;
01078 }
01079
01080 uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
01081 {
01082 return ntohs(iterator->ie->ie_payload_len);
01083 }
01084
01085 enum ast_event_type ast_event_get_type(const struct ast_event *event)
01086 {
01087 return ntohs(event->type);
01088 }
01089
01090 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
01091 {
01092 const uint32_t *ie_val;
01093
01094 ie_val = ast_event_get_ie_raw(event, ie_type);
01095
01096 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
01097 }
01098
01099 uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type)
01100 {
01101 const uint32_t *ie_val;
01102
01103 ie_val = ast_event_get_ie_raw(event, ie_type);
01104
01105 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
01106 }
01107
01108 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
01109 {
01110 const struct ast_event_ie_str_payload *str_payload;
01111
01112 str_payload = ast_event_get_ie_raw(event, ie_type);
01113
01114 return str_payload ? str_payload->hash : 0;
01115 }
01116
01117 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
01118 {
01119 const struct ast_event_ie_str_payload *str_payload;
01120
01121 str_payload = ast_event_get_ie_raw(event, ie_type);
01122
01123 return str_payload ? str_payload->str : NULL;
01124 }
01125
01126 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
01127 {
01128 struct ast_event_iterator iterator;
01129 int res;
01130
01131 for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
01132 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
01133 return ast_event_iterator_get_ie_raw(&iterator);
01134 }
01135 }
01136
01137 return NULL;
01138 }
01139
01140 uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
01141 {
01142 struct ast_event_iterator iterator;
01143 int res;
01144
01145 for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
01146 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
01147 return ast_event_iterator_get_ie_raw_payload_len(&iterator);
01148 }
01149 }
01150
01151 return 0;
01152 }
01153
01154 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
01155 const char *str)
01156 {
01157 struct ast_event_ie_str_payload *str_payload;
01158 size_t payload_len;
01159
01160 payload_len = sizeof(*str_payload) + strlen(str);
01161 str_payload = ast_alloca(payload_len);
01162
01163 strcpy(str_payload->str, str);
01164 if (ie_type == AST_EVENT_IE_DEVICE) {
01165 char *uppertech = ast_strdupa(str);
01166 ast_tech_to_upper(uppertech);
01167 str_payload->hash = ast_str_hash(uppertech);
01168 } else {
01169 str_payload->hash = ast_str_hash(str);
01170 }
01171
01172 return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
01173 }
01174
01175 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
01176 uint32_t data)
01177 {
01178 data = htonl(data);
01179 return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
01180 }
01181
01182 int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
01183 uint32_t flags)
01184 {
01185 flags = htonl(flags);
01186 return ast_event_append_ie_raw(event, ie_type, &flags, sizeof(flags));
01187 }
01188
01189 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
01190 const void *data, size_t data_len)
01191 {
01192 struct ast_event_ie *ie;
01193 unsigned int extra_len;
01194 uint16_t event_len;
01195
01196 event_len = ntohs((*event)->event_len);
01197 extra_len = sizeof(*ie) + data_len;
01198
01199 if (!(*event = ast_realloc(*event, event_len + extra_len))) {
01200 return -1;
01201 }
01202
01203 ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
01204 ie->ie_type = htons(ie_type);
01205 ie->ie_payload_len = htons(data_len);
01206 memcpy(ie->ie_payload, data, data_len);
01207
01208 (*event)->event_len = htons(event_len + extra_len);
01209
01210 return 0;
01211 }
01212
01213 struct ast_event *ast_event_new(enum ast_event_type type, ...)
01214 {
01215 va_list ap;
01216 struct ast_event *event;
01217 enum ast_event_ie_type ie_type;
01218 struct ast_event_ie_val *ie_val;
01219 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
01220
01221
01222 if (type >= AST_EVENT_TOTAL) {
01223 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
01224 "type '%d'!\n", type);
01225 return NULL;
01226 }
01227
01228 va_start(ap, type);
01229 for (ie_type = va_arg(ap, enum ast_event_ie_type);
01230 ie_type != AST_EVENT_IE_END;
01231 ie_type = va_arg(ap, enum ast_event_ie_type))
01232 {
01233 struct ast_event_ie_val *ie_value = ast_alloca(sizeof(*ie_value));
01234 int insert = 0;
01235
01236 memset(ie_value, 0, sizeof(*ie_value));
01237 ie_value->ie_type = ie_type;
01238 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01239 switch (ie_value->ie_pltype) {
01240 case AST_EVENT_IE_PLTYPE_UINT:
01241 ie_value->payload.uint = va_arg(ap, uint32_t);
01242 insert = 1;
01243 break;
01244 case AST_EVENT_IE_PLTYPE_BITFLAGS:
01245 ie_value->payload.uint = va_arg(ap, uint32_t);
01246 insert = 1;
01247 break;
01248 case AST_EVENT_IE_PLTYPE_STR:
01249 ie_value->payload.str = va_arg(ap, const char *);
01250 insert = 1;
01251 break;
01252 case AST_EVENT_IE_PLTYPE_RAW:
01253 {
01254 void *data = va_arg(ap, void *);
01255 size_t datalen = va_arg(ap, size_t);
01256 ie_value->payload.raw = ast_alloca(datalen);
01257 memcpy(ie_value->payload.raw, data, datalen);
01258 ie_value->raw_datalen = datalen;
01259 insert = 1;
01260 break;
01261 }
01262 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01263 case AST_EVENT_IE_PLTYPE_EXISTS:
01264 break;
01265 }
01266
01267 if (insert) {
01268 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
01269 } else {
01270 ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
01271 }
01272 }
01273 va_end(ap);
01274
01275 if (!(event = ast_calloc(1, sizeof(*event)))) {
01276 return NULL;
01277 }
01278
01279 event->type = htons(type);
01280 event->event_len = htons(sizeof(*event));
01281
01282 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
01283 switch (ie_val->ie_pltype) {
01284 case AST_EVENT_IE_PLTYPE_STR:
01285 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
01286 break;
01287 case AST_EVENT_IE_PLTYPE_UINT:
01288 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
01289 break;
01290 case AST_EVENT_IE_PLTYPE_BITFLAGS:
01291 ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
01292 break;
01293 case AST_EVENT_IE_PLTYPE_RAW:
01294 ast_event_append_ie_raw(&event, ie_val->ie_type,
01295 ie_val->payload.raw, ie_val->raw_datalen);
01296 break;
01297 case AST_EVENT_IE_PLTYPE_EXISTS:
01298 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01299 break;
01300 }
01301
01302
01303 if (!event) {
01304 return NULL;
01305 }
01306 }
01307
01308 if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
01309
01310
01311 ast_event_append_eid(&event);
01312 }
01313
01314 return event;
01315 }
01316
01317 int ast_event_append_eid(struct ast_event **event)
01318 {
01319 return ast_event_append_ie_raw(event, AST_EVENT_IE_EID,
01320 &ast_eid_default, sizeof(ast_eid_default));
01321 }
01322
01323 void ast_event_destroy(struct ast_event *event)
01324 {
01325 ast_free(event);
01326 }
01327
01328 static void ast_event_ref_destroy(void *obj)
01329 {
01330 struct ast_event_ref *event_ref = obj;
01331
01332 ast_event_destroy(event_ref->event);
01333 }
01334
01335 static struct ast_event *ast_event_dup(const struct ast_event *event)
01336 {
01337 struct ast_event *dup_event;
01338 uint16_t event_len;
01339
01340 event_len = ast_event_get_size(event);
01341
01342 if (!(dup_event = ast_calloc(1, event_len))) {
01343 return NULL;
01344 }
01345
01346 memcpy(dup_event, event, event_len);
01347
01348 return dup_event;
01349 }
01350
01351 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
01352 {
01353 va_list ap;
01354 enum ast_event_ie_type ie_type;
01355 struct ast_event *dup_event = NULL;
01356 struct ast_event_ref *cached_event_ref;
01357 struct ast_event *cache_arg_event;
01358 struct ast_event_ref tmp_event_ref = {
01359 .event = NULL,
01360 };
01361 struct ao2_container *container = NULL;
01362
01363 if (type >= AST_EVENT_TOTAL) {
01364 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01365 return NULL;
01366 }
01367
01368 if (!(container = ast_event_cache[type].container)) {
01369 ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01370 return NULL;
01371 }
01372
01373 if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01374 return NULL;
01375 }
01376
01377 va_start(ap, type);
01378 for (ie_type = va_arg(ap, enum ast_event_ie_type);
01379 ie_type != AST_EVENT_IE_END;
01380 ie_type = va_arg(ap, enum ast_event_ie_type))
01381 {
01382 enum ast_event_ie_pltype ie_pltype;
01383
01384 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01385
01386 switch (ie_pltype) {
01387 case AST_EVENT_IE_PLTYPE_UINT:
01388 ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01389 break;
01390 case AST_EVENT_IE_PLTYPE_BITFLAGS:
01391 ast_event_append_ie_bitflags(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01392 break;
01393 case AST_EVENT_IE_PLTYPE_STR:
01394 ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01395 break;
01396 case AST_EVENT_IE_PLTYPE_RAW:
01397 {
01398 void *data = va_arg(ap, void *);
01399 size_t datalen = va_arg(ap, size_t);
01400 ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01401 break;
01402 }
01403 case AST_EVENT_IE_PLTYPE_EXISTS:
01404 ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01405 break;
01406 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01407 break;
01408 }
01409 }
01410 va_end(ap);
01411
01412 tmp_event_ref.event = cache_arg_event;
01413
01414 cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01415
01416 ast_event_destroy(cache_arg_event);
01417 cache_arg_event = NULL;
01418
01419 if (cached_event_ref) {
01420 dup_event = ast_event_dup(cached_event_ref->event);
01421 ao2_ref(cached_event_ref, -1);
01422 cached_event_ref = NULL;
01423 }
01424
01425 return dup_event;
01426 }
01427
01428 static struct ast_event_ref *alloc_event_ref(void)
01429 {
01430 return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01431 }
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443 static void event_update_cache(struct ao2_container *cache, struct ast_event *event)
01444 {
01445 struct ast_event_ref tmp_event_ref = {
01446 .event = event,
01447 };
01448 struct ast_event *dup_event;
01449 struct ast_event_ref *event_ref;
01450
01451
01452 ao2_lock(cache);
01453
01454
01455 ao2_callback(cache, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01456 ast_event_cmp, &tmp_event_ref);
01457
01458
01459 dup_event = ast_event_dup(event);
01460 if (dup_event) {
01461 event_ref = alloc_event_ref();
01462 if (event_ref) {
01463 event_ref->event = dup_event;
01464 ao2_link(cache, event_ref);
01465 ao2_ref(event_ref, -1);
01466 } else {
01467 ast_event_destroy(dup_event);
01468 }
01469 }
01470
01471 ao2_unlock(cache);
01472 }
01473
01474 static int handle_event(void *data)
01475 {
01476 struct ast_event_ref *event_ref = data;
01477 struct ast_event_sub *sub;
01478 const enum ast_event_type event_types[] = {
01479 ntohs(event_ref->event->type),
01480 AST_EVENT_ALL
01481 };
01482 int i;
01483
01484 if (event_ref->cache) {
01485 struct ao2_container *container;
01486 container = ast_event_cache[ast_event_get_type(event_ref->event)].container;
01487 if (!container) {
01488 ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01489 } else {
01490 event_update_cache(container, event_ref->event);
01491 }
01492 }
01493
01494 for (i = 0; i < ARRAY_LEN(event_types); i++) {
01495 AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
01496 AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
01497 struct ast_event_ie_val *ie_val;
01498
01499 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01500 if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01501
01502 break;
01503 }
01504 }
01505 if (ie_val) {
01506
01507 continue;
01508 }
01509 sub->cb(event_ref->event, sub->userdata);
01510 }
01511 AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
01512 }
01513
01514 ao2_ref(event_ref, -1);
01515
01516 return 0;
01517 }
01518
01519 static int _ast_event_queue(struct ast_event *event, unsigned int cache)
01520 {
01521 struct ast_event_ref *event_ref;
01522 uint16_t host_event_type;
01523 int res;
01524
01525 host_event_type = ntohs(event->type);
01526
01527
01528 if (host_event_type >= AST_EVENT_TOTAL) {
01529 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01530 "type '%d'!\n", host_event_type);
01531 return -1;
01532 }
01533
01534
01535 if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01536 == AST_EVENT_SUB_NONE) {
01537 ast_event_destroy(event);
01538 return 0;
01539 }
01540
01541 if (!(event_ref = alloc_event_ref())) {
01542 return -1;
01543 }
01544
01545 event_ref->event = event;
01546 event_ref->cache = cache;
01547
01548 res = ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01549 if (res) {
01550 event_ref->event = NULL;
01551 ao2_ref(event_ref, -1);
01552 }
01553 return res;
01554 }
01555
01556 int ast_event_queue(struct ast_event *event)
01557 {
01558 return _ast_event_queue(event, 0);
01559 }
01560
01561 int ast_event_queue_and_cache(struct ast_event *event)
01562 {
01563 return _ast_event_queue(event, 1);
01564 }
01565
01566 static int ast_event_hash_mwi(const void *obj, const int flags)
01567 {
01568 const struct ast_event *event = obj;
01569 const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01570 const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01571
01572 return ast_str_hash_add(context, ast_str_hash(mailbox));
01573 }
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584 static int ast_event_hash_devstate(const void *obj, const int flags)
01585 {
01586 const struct ast_event *event = obj;
01587
01588 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01589 }
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01601 {
01602 const struct ast_event *event = obj;
01603
01604 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616 static int ast_event_hash_presence_state_change(const void *obj, const int flags)
01617 {
01618 const struct ast_event *event = obj;
01619
01620 return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER));
01621 }
01622
01623 static int ast_event_hash(const void *obj, const int flags)
01624 {
01625 const struct ast_event_ref *event_ref;
01626 const struct ast_event *event;
01627 ao2_hash_fn *hash_fn;
01628
01629 event_ref = obj;
01630 event = event_ref->event;
01631
01632 if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01633 return 0;
01634 }
01635
01636 return hash_fn(event, flags);
01637 }
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657 static int ast_event_cmp(void *obj, void *arg, int flags)
01658 {
01659 struct ast_event_ref *event_ref, *event_ref2;
01660 struct ast_event *event, *event2;
01661 int res = CMP_MATCH;
01662 int i;
01663 enum ast_event_ie_type *cache_args;
01664
01665 event_ref = obj;
01666 event = event_ref->event;
01667
01668 event_ref2 = arg;
01669 event2 = event_ref2->event;
01670
01671 cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01672
01673 for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01674 struct ast_event_ie_val ie_val = {
01675 .ie_pltype = ast_event_get_ie_pltype(cache_args[i]),
01676 .ie_type = cache_args[i],
01677 };
01678
01679 if (!match_ie_val(event, &ie_val, event2)) {
01680 res = 0;
01681 break;
01682 }
01683 }
01684
01685 return res;
01686 }
01687
01688 static void dump_raw_ie(struct ast_event_iterator *i, struct ast_cli_args *a)
01689 {
01690 char eid_buf[32];
01691 enum ast_event_ie_type ie_type;
01692 const char *ie_type_name;
01693
01694 ie_type = ast_event_iterator_get_ie_type(i);
01695 ie_type_name = ast_event_get_ie_type_name(ie_type);
01696
01697 switch (ie_type) {
01698 case AST_EVENT_IE_EID:
01699 ast_eid_to_str(eid_buf, sizeof(eid_buf), ast_event_iterator_get_ie_raw(i));
01700 ast_cli(a->fd, "%.30s: %s\n", ie_type_name, eid_buf);
01701 break;
01702 default:
01703 ast_cli(a->fd, "%s\n", ie_type_name);
01704 break;
01705 }
01706 }
01707
01708 static int event_dump_cli(void *obj, void *arg, int flags)
01709 {
01710 const struct ast_event_ref *event_ref = obj;
01711 const struct ast_event *event = event_ref->event;
01712 struct ast_cli_args *a = arg;
01713 struct ast_event_iterator i;
01714
01715 if (ast_event_iterator_init(&i, event)) {
01716 ast_cli(a->fd, "Failed to initialize event iterator. :-(\n");
01717 return 0;
01718 }
01719
01720 ast_cli(a->fd, "Event: %s\n", ast_event_get_type_name(event));
01721
01722 do {
01723 enum ast_event_ie_type ie_type;
01724 enum ast_event_ie_pltype ie_pltype;
01725 const char *ie_type_name;
01726
01727 ie_type = ast_event_iterator_get_ie_type(&i);
01728 ie_type_name = ast_event_get_ie_type_name(ie_type);
01729 ie_pltype = ast_event_get_ie_pltype(ie_type);
01730
01731 switch (ie_pltype) {
01732 case AST_EVENT_IE_PLTYPE_UNKNOWN:
01733 case AST_EVENT_IE_PLTYPE_EXISTS:
01734 ast_cli(a->fd, "%s\n", ie_type_name);
01735 break;
01736 case AST_EVENT_IE_PLTYPE_STR:
01737 ast_cli(a->fd, "%.30s: %s\n", ie_type_name,
01738 ast_event_iterator_get_ie_str(&i));
01739 break;
01740 case AST_EVENT_IE_PLTYPE_UINT:
01741 ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
01742 ast_event_iterator_get_ie_uint(&i));
01743 break;
01744 case AST_EVENT_IE_PLTYPE_BITFLAGS:
01745 ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
01746 ast_event_iterator_get_ie_bitflags(&i));
01747 break;
01748 case AST_EVENT_IE_PLTYPE_RAW:
01749 dump_raw_ie(&i, a);
01750 break;
01751 }
01752 } while (!ast_event_iterator_next(&i));
01753
01754 ast_cli(a->fd, "\n");
01755
01756 return 0;
01757 }
01758
01759 static char *event_dump_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01760 {
01761 enum ast_event_type event_type;
01762 enum ast_event_ie_type *cache_args;
01763 int i;
01764
01765 switch (cmd) {
01766 case CLI_INIT:
01767 e->command = "event dump cache";
01768 e->usage =
01769 "Usage: event dump cache <event type>\n"
01770 " Dump all of the cached events for the given event type.\n"
01771 " This is primarily intended for debugging.\n";
01772 return NULL;
01773 case CLI_GENERATE:
01774 if (a->pos == 3) {
01775 return ast_cli_complete(a->word, cached_event_types, a->n);
01776 }
01777 return NULL;
01778 case CLI_HANDLER:
01779 break;
01780 }
01781
01782 if (a->argc != e->args + 1) {
01783 return CLI_SHOWUSAGE;
01784 }
01785
01786 if (ast_event_str_to_event_type(a->argv[e->args], &event_type)) {
01787 ast_cli(a->fd, "Invalid cached event type: '%s'\n", a->argv[e->args]);
01788 return CLI_SHOWUSAGE;
01789 }
01790
01791 if (!ast_event_cache[event_type].container) {
01792 ast_cli(a->fd, "Event type '%s' has no cache.\n", a->argv[e->args]);
01793 return CLI_SUCCESS;
01794 }
01795
01796 ast_cli(a->fd, "Event Type: %s\n", a->argv[e->args]);
01797 ast_cli(a->fd, "Cache Unique Keys:\n");
01798 cache_args = ast_event_cache[event_type].cache_args;
01799 for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01800 ast_cli(a->fd, "--> %s\n", ast_event_get_ie_type_name(cache_args[i]));
01801 }
01802
01803 ast_cli(a->fd, "\n--- Begin Cache Dump ---\n\n");
01804 ao2_callback(ast_event_cache[event_type].container, OBJ_NODATA, event_dump_cli, a);
01805 ast_cli(a->fd, "--- End Cache Dump ---\n\n");
01806
01807 return CLI_SUCCESS;
01808 }
01809
01810 static struct ast_cli_entry event_cli[] = {
01811 AST_CLI_DEFINE(event_dump_cache, "Dump the internal event cache (for debugging)"),
01812 };
01813
01814
01815 static void event_shutdown(void)
01816 {
01817 struct ast_event_sub *sub;
01818 int i;
01819
01820 if (event_dispatcher) {
01821 event_dispatcher = ast_taskprocessor_unreference(event_dispatcher);
01822 }
01823
01824
01825
01826
01827 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01828 AST_RWDLLIST_WRLOCK(&ast_event_subs[i]);
01829 while ((sub = AST_RWDLLIST_REMOVE_HEAD(&ast_event_subs[i], entry))) {
01830 ast_event_sub_destroy(sub);
01831 }
01832 AST_RWDLLIST_UNLOCK(&ast_event_subs[i]);
01833 AST_RWDLLIST_HEAD_DESTROY(&ast_event_subs[i]);
01834 }
01835
01836 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01837 if (!ast_event_cache[i].hash_fn) {
01838 continue;
01839 }
01840 if (ast_event_cache[i].container) {
01841 ao2_ref(ast_event_cache[i].container, -1);
01842 }
01843 }
01844 }
01845
01846 int ast_event_init(void)
01847 {
01848 int i;
01849
01850 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01851 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01852 }
01853
01854 for (i = 0; i < AST_EVENT_TOTAL; i++) {
01855 if (!ast_event_cache[i].hash_fn) {
01856
01857 continue;
01858 }
01859
01860 if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01861 ast_event_hash, ast_event_cmp))) {
01862 goto event_init_cleanup;
01863 }
01864 }
01865
01866 if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01867 goto event_init_cleanup;
01868 }
01869
01870 ast_cli_register_multiple(event_cli, ARRAY_LEN(event_cli));
01871
01872 ast_register_atexit(event_shutdown);
01873
01874 return 0;
01875
01876 event_init_cleanup:
01877 event_shutdown();
01878 return -1;
01879 }
01880
01881 size_t ast_event_minimum_length(void)
01882 {
01883 return sizeof(struct ast_event);
01884 }