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: 159855 $")
00029
00030 #include "asterisk/_private.h"
00031 #include "asterisk/event.h"
00032 #include "asterisk/linkedlists.h"
00033 #include "asterisk/lock.h"
00034 #include "asterisk/utils.h"
00035 #include "asterisk/unaligned.h"
00036
00037
00038 #define NUM_EVENT_THREADS 1
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 struct ast_event_ie {
00049 enum ast_event_ie_type ie_type:16;
00050
00051 uint16_t ie_payload_len;
00052 unsigned char ie_payload[0];
00053 } __attribute__((packed));
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 struct ast_event {
00067
00068 enum ast_event_type type:16;
00069
00070 uint16_t event_len:16;
00071
00072 unsigned char payload[0];
00073 } __attribute__((packed));
00074
00075 struct ast_event_ref {
00076 struct ast_event *event;
00077 AST_LIST_ENTRY(ast_event_ref) entry;
00078 };
00079
00080 struct ast_event_iterator {
00081 uint16_t event_len;
00082 const struct ast_event *event;
00083 struct ast_event_ie *ie;
00084 };
00085
00086
00087 static struct {
00088 ast_cond_t cond;
00089 ast_mutex_t lock;
00090 AST_LIST_HEAD_NOLOCK(, ast_event_ref) event_q;
00091 } event_thread = {
00092 .lock = AST_MUTEX_INIT_VALUE,
00093 };
00094
00095 struct ast_event_ie_val {
00096 AST_LIST_ENTRY(ast_event_ie_val) entry;
00097 enum ast_event_ie_type ie_type;
00098 enum ast_event_ie_pltype ie_pltype;
00099 union {
00100 uint32_t uint;
00101 const char *str;
00102 } payload;
00103 };
00104
00105
00106 struct ast_event_sub {
00107 enum ast_event_type type;
00108 ast_event_cb_t cb;
00109 void *userdata;
00110 uint32_t uniqueid;
00111 AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
00112 AST_RWLIST_ENTRY(ast_event_sub) entry;
00113 };
00114
00115 static uint32_t sub_uniqueid;
00116
00117
00118
00119 static AST_RWLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
00120
00121
00122
00123
00124
00125 static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL];
00126
00127 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
00128 {
00129 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00130 ast_free((void *) ie_val->payload.str);
00131
00132 ast_free(ie_val);
00133 }
00134
00135 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00136 {
00137 va_list ap;
00138 enum ast_event_ie_type ie_type;
00139 enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00140 struct ast_event_ie_val *ie_val, *sub_ie_val;
00141 struct ast_event_sub *sub;
00142 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00143
00144 if (type >= AST_EVENT_TOTAL) {
00145 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00146 return res;
00147 }
00148
00149 va_start(ap, type);
00150 for (ie_type = va_arg(ap, enum ast_event_type);
00151 ie_type != AST_EVENT_IE_END;
00152 ie_type = va_arg(ap, enum ast_event_type))
00153 {
00154 struct ast_event_ie_val *ie_val = alloca(sizeof(*ie_val));
00155 memset(ie_val, 0, sizeof(*ie_val));
00156 ie_val->ie_type = ie_type;
00157 ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00158 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00159 ie_val->payload.uint = va_arg(ap, uint32_t);
00160 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00161 ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
00162 AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
00163 }
00164 va_end(ap);
00165
00166 AST_RWLIST_RDLOCK(&ast_event_subs[type]);
00167 AST_RWLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
00168 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00169 AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
00170 if (sub_ie_val->ie_type == ie_val->ie_type)
00171 break;
00172 }
00173 if (!sub_ie_val) {
00174 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00175 break;
00176 continue;
00177 }
00178
00179 if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00180 continue;
00181 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00182 ie_val->payload.uint != sub_ie_val->payload.uint)
00183 break;
00184 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00185 strcmp(ie_val->payload.str, sub_ie_val->payload.str))
00186 break;
00187 }
00188 if (!ie_val)
00189 break;
00190 }
00191 AST_RWLIST_UNLOCK(&ast_event_subs[type]);
00192
00193 if (sub)
00194 return AST_EVENT_SUB_EXISTS;
00195
00196 AST_RWLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
00197 if (!AST_LIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
00198 res = AST_EVENT_SUB_EXISTS;
00199 AST_RWLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
00200
00201 return res;
00202 }
00203
00204
00205 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00206 {
00207 struct ast_event *event;
00208 struct ast_event_sub *sub;
00209 enum ast_event_type event_type = -1;
00210 struct ast_event_ie_val *ie_val;
00211
00212 if (event_sub->type != AST_EVENT_SUB)
00213 return;
00214
00215 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00216 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00217 event_type = ie_val->payload.uint;
00218 break;
00219 }
00220 }
00221
00222 if (event_type == -1)
00223 return;
00224
00225 AST_RWLIST_RDLOCK(&ast_event_subs[event_type]);
00226 AST_RWLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00227 if (event_sub == sub)
00228 continue;
00229
00230 event = ast_event_new(AST_EVENT_SUB,
00231 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00232 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00233 AST_EVENT_IE_END);
00234
00235 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00236 switch (ie_val->ie_pltype) {
00237 case AST_EVENT_IE_PLTYPE_EXISTS:
00238 ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00239 break;
00240 case AST_EVENT_IE_PLTYPE_UINT:
00241 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00242 break;
00243 case AST_EVENT_IE_PLTYPE_STR:
00244 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00245 break;
00246 }
00247 if (!event)
00248 break;
00249 }
00250
00251 if (!event)
00252 continue;
00253
00254 event_sub->cb(event, event_sub->userdata);
00255
00256 ast_event_destroy(event);
00257 }
00258 AST_RWLIST_UNLOCK(&ast_event_subs[event_type]);
00259 }
00260
00261 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
00262 void *userdata, ...)
00263 {
00264 va_list ap;
00265 enum ast_event_ie_type ie_type;
00266 struct ast_event_sub *sub;
00267 struct ast_event *event;
00268
00269 if (type >= AST_EVENT_TOTAL) {
00270 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00271 return NULL;
00272 }
00273
00274 if (!(sub = ast_calloc(1, sizeof(*sub))))
00275 return NULL;
00276
00277 va_start(ap, userdata);
00278 for (ie_type = va_arg(ap, enum ast_event_type);
00279 ie_type != AST_EVENT_IE_END;
00280 ie_type = va_arg(ap, enum ast_event_type))
00281 {
00282 struct ast_event_ie_val *ie_val;
00283 if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00284 continue;
00285 ie_val->ie_type = ie_type;
00286 ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00287 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00288 ie_val->payload.uint = va_arg(ap, uint32_t);
00289 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
00290 if (!(ie_val->payload.str = ast_strdup(va_arg(ap, const char *)))) {
00291 ast_free(ie_val);
00292 continue;
00293 }
00294 }
00295 AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00296 }
00297 va_end(ap);
00298
00299 sub->type = type;
00300 sub->cb = cb;
00301 sub->userdata = userdata;
00302 sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00303
00304 if (ast_event_check_subscriber(AST_EVENT_SUB,
00305 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, type,
00306 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00307 struct ast_event_ie_val *ie_val;
00308
00309 event = ast_event_new(AST_EVENT_SUB,
00310 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00311 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00312 AST_EVENT_IE_END);
00313
00314 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00315 switch (ie_val->ie_pltype) {
00316 case AST_EVENT_IE_PLTYPE_EXISTS:
00317 ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00318 break;
00319 case AST_EVENT_IE_PLTYPE_UINT:
00320 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00321 break;
00322 case AST_EVENT_IE_PLTYPE_STR:
00323 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00324 break;
00325 }
00326 if (!event)
00327 break;
00328 }
00329
00330 if (event)
00331 ast_event_queue(event);
00332 }
00333
00334 AST_RWLIST_WRLOCK(&ast_event_subs[type]);
00335 AST_RWLIST_INSERT_TAIL(&ast_event_subs[type], sub, entry);
00336 AST_RWLIST_UNLOCK(&ast_event_subs[type]);
00337
00338 return sub;
00339 }
00340
00341 static void ast_event_sub_destroy(struct ast_event_sub *sub)
00342 {
00343 struct ast_event_ie_val *ie_val;
00344
00345 while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
00346 ast_event_ie_val_destroy(ie_val);
00347
00348 ast_free(sub);
00349 }
00350
00351 void ast_event_unsubscribe(struct ast_event_sub *sub)
00352 {
00353 struct ast_event *event;
00354
00355 AST_RWLIST_WRLOCK(&ast_event_subs[sub->type]);
00356 AST_LIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
00357 AST_RWLIST_UNLOCK(&ast_event_subs[sub->type]);
00358
00359 if (ast_event_check_subscriber(AST_EVENT_UNSUB,
00360 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00361 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00362
00363 event = ast_event_new(AST_EVENT_UNSUB,
00364 AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00365 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00366 AST_EVENT_IE_END);
00367
00368 if (event)
00369 ast_event_queue(event);
00370 }
00371
00372 ast_event_sub_destroy(sub);
00373 }
00374
00375 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00376 {
00377 iterator->event_len = ntohs(event->event_len);
00378 iterator->event = event;
00379 iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00380 return;
00381 }
00382
00383 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00384 {
00385 iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00386 return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00387 }
00388
00389 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00390 {
00391 return ntohs(iterator->ie->ie_type);
00392 }
00393
00394 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00395 {
00396 return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00397 }
00398
00399 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00400 {
00401 return (const char*)iterator->ie->ie_payload;
00402 }
00403
00404 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00405 {
00406 return iterator->ie->ie_payload;
00407 }
00408
00409 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00410 {
00411 return ntohs(event->type);
00412 }
00413
00414 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00415 {
00416 const uint32_t *ie_val;
00417
00418 ie_val = ast_event_get_ie_raw(event, ie_type);
00419
00420 return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00421 }
00422
00423 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00424 {
00425 return ast_event_get_ie_raw(event, ie_type);
00426 }
00427
00428 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00429 {
00430 struct ast_event_iterator iterator;
00431 int res = 0;
00432
00433 for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00434 if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
00435 return ast_event_iterator_get_ie_raw(&iterator);
00436 }
00437
00438 return NULL;
00439 }
00440
00441 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00442 const char *str)
00443 {
00444 return ast_event_append_ie_raw(event, ie_type, str, strlen(str) + 1);
00445 }
00446
00447 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00448 uint32_t data)
00449 {
00450 data = htonl(data);
00451 return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00452 }
00453
00454 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00455 const void *data, size_t data_len)
00456 {
00457 struct ast_event_ie *ie;
00458 unsigned int extra_len;
00459 uint16_t event_len;
00460
00461 event_len = ntohs((*event)->event_len);
00462 extra_len = sizeof(*ie) + data_len;
00463
00464 if (!(*event = ast_realloc(*event, event_len + extra_len)))
00465 return -1;
00466
00467 ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00468 ie->ie_type = htons(ie_type);
00469 ie->ie_payload_len = htons(data_len);
00470 memcpy(ie->ie_payload, data, data_len);
00471
00472 (*event)->event_len = htons(event_len + extra_len);
00473
00474 return 0;
00475 }
00476
00477 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00478 {
00479 va_list ap;
00480 struct ast_event *event;
00481 enum ast_event_type ie_type;
00482 struct ast_event_ie_val *ie_val;
00483 AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00484
00485
00486 if (type >= AST_EVENT_TOTAL) {
00487 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00488 "type '%d'!\n", type);
00489 return NULL;
00490 }
00491
00492 va_start(ap, type);
00493 for (ie_type = va_arg(ap, enum ast_event_type);
00494 ie_type != AST_EVENT_IE_END;
00495 ie_type = va_arg(ap, enum ast_event_type))
00496 {
00497 struct ast_event_ie_val *ie_val = alloca(sizeof(*ie_val));
00498 memset(ie_val, 0, sizeof(*ie_val));
00499 ie_val->ie_type = ie_type;
00500 ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00501 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00502 ie_val->payload.uint = va_arg(ap, uint32_t);
00503 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00504 ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
00505 AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
00506 }
00507 va_end(ap);
00508
00509 if (!(event = ast_calloc(1, sizeof(*event))))
00510 return NULL;
00511
00512 event->type = htons(type);
00513 event->event_len = htons(sizeof(*event));
00514
00515 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00516 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00517 ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00518 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00519 ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00520
00521 if (!event)
00522 break;
00523 }
00524
00525 return event;
00526 }
00527
00528 void ast_event_destroy(struct ast_event *event)
00529 {
00530 ast_free(event);
00531 }
00532
00533 static void ast_event_ref_destroy(struct ast_event_ref *event_ref)
00534 {
00535 ast_event_destroy(event_ref->event);
00536 ast_free(event_ref);
00537 }
00538
00539 static struct ast_event *ast_event_dup(const struct ast_event *event)
00540 {
00541 struct ast_event *dup_event;
00542 uint16_t event_len;
00543
00544 event_len = ntohs(event->event_len);
00545
00546 if (!(dup_event = ast_calloc(1, event_len)))
00547 return NULL;
00548
00549 memcpy(dup_event, event, event_len);
00550
00551 return dup_event;
00552 }
00553
00554 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
00555 {
00556 va_list ap;
00557 enum ast_event_ie_type ie_type;
00558 struct ast_event *dup_event = NULL;
00559 struct ast_event_ref *event_ref;
00560 struct cache_arg {
00561 AST_LIST_ENTRY(cache_arg) entry;
00562 enum ast_event_ie_type ie_type;
00563 enum ast_event_ie_pltype ie_pltype;
00564 union {
00565 uint32_t uint;
00566 const char *str;
00567 } payload;
00568 } *cache_arg;
00569 AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg);
00570
00571 if (type >= AST_EVENT_TOTAL) {
00572 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00573 return NULL;
00574 }
00575
00576 va_start(ap, type);
00577 for (ie_type = va_arg(ap, enum ast_event_type);
00578 ie_type != AST_EVENT_IE_END;
00579 ie_type = va_arg(ap, enum ast_event_type))
00580 {
00581 cache_arg = alloca(sizeof(*cache_arg));
00582 memset(cache_arg, 0, sizeof(*cache_arg));
00583 cache_arg->ie_type = ie_type;
00584 cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00585 if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00586 cache_arg->payload.uint = va_arg(ap, uint32_t);
00587 else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00588 cache_arg->payload.str = ast_strdupa(va_arg(ap, const char *));
00589 AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
00590 }
00591 va_end(ap);
00592
00593 if (AST_LIST_EMPTY(&cache_args)) {
00594 ast_log(LOG_ERROR, "Events can not be retrieved from the cache without "
00595 "specifying at least one IE type!\n");
00596 return NULL;
00597 }
00598
00599 AST_RWLIST_RDLOCK(&ast_event_cache[type]);
00600 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
00601 AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
00602 if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00603 (cache_arg->payload.uint ==
00604 ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) ||
00605
00606 (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00607 (!strcmp(cache_arg->payload.str,
00608 ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) ||
00609
00610 (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
00611 ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) )
00612 {
00613 break;
00614 }
00615 }
00616 if (!cache_arg) {
00617
00618 dup_event = ast_event_dup(event_ref->event);
00619 break;
00620 }
00621 }
00622 AST_RWLIST_TRAVERSE_SAFE_END
00623 AST_RWLIST_UNLOCK(&ast_event_cache[type]);
00624
00625 return dup_event;
00626 }
00627
00628
00629
00630 static int ast_event_dup_and_cache(const struct ast_event *event)
00631 {
00632 struct ast_event *dup_event;
00633 struct ast_event_ref *event_ref;
00634
00635 if (!(dup_event = ast_event_dup(event)))
00636 return -1;
00637 if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
00638 return -1;
00639
00640 event_ref->event = dup_event;
00641
00642 AST_LIST_INSERT_TAIL(&ast_event_cache[ntohs(event->type)], event_ref, entry);
00643
00644 return 0;
00645 }
00646
00647 int ast_event_queue_and_cache(struct ast_event *event, ...)
00648 {
00649 va_list ap;
00650 enum ast_event_type ie_type;
00651 uint16_t host_event_type;
00652 struct ast_event_ref *event_ref;
00653 int res;
00654 struct cache_arg {
00655 AST_LIST_ENTRY(cache_arg) entry;
00656 enum ast_event_ie_type ie_type;
00657 enum ast_event_ie_pltype ie_pltype;
00658 } *cache_arg;
00659 AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg);
00660
00661 host_event_type = ntohs(event->type);
00662
00663
00664 if (host_event_type >= AST_EVENT_TOTAL) {
00665 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
00666 "type '%d'!\n", host_event_type);
00667 return -1;
00668 }
00669
00670 va_start(ap, event);
00671 for (ie_type = va_arg(ap, enum ast_event_type);
00672 ie_type != AST_EVENT_IE_END;
00673 ie_type = va_arg(ap, enum ast_event_type))
00674 {
00675 cache_arg = alloca(sizeof(*cache_arg));
00676 memset(cache_arg, 0, sizeof(*cache_arg));
00677 cache_arg->ie_type = ie_type;
00678 cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00679 AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
00680 }
00681 va_end(ap);
00682
00683 if (AST_LIST_EMPTY(&cache_args)) {
00684 ast_log(LOG_ERROR, "Events can not be cached without specifying at "
00685 "least one IE type!\n");
00686 return ast_event_queue(event);
00687 }
00688
00689 AST_RWLIST_WRLOCK(&ast_event_cache[host_event_type]);
00690 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[host_event_type], event_ref, entry) {
00691 AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
00692 if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00693 (ast_event_get_ie_uint(event, cache_arg->ie_type) ==
00694 ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) ||
00695
00696 (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00697 (!strcmp(ast_event_get_ie_str(event, cache_arg->ie_type),
00698 ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) ||
00699
00700 (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
00701 ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) )
00702 {
00703 break;
00704 }
00705 }
00706 if (!cache_arg) {
00707
00708 AST_LIST_REMOVE_CURRENT(entry);
00709 ast_event_ref_destroy(event_ref);
00710 }
00711 }
00712 AST_RWLIST_TRAVERSE_SAFE_END;
00713 res = ast_event_dup_and_cache(event);
00714 AST_RWLIST_UNLOCK(&ast_event_cache[host_event_type]);
00715
00716 return (ast_event_queue(event) || res) ? -1 : 0;
00717 }
00718
00719 int ast_event_queue(struct ast_event *event)
00720 {
00721 struct ast_event_ref *event_ref;
00722 uint16_t host_event_type;
00723
00724 host_event_type = ntohs(event->type);
00725
00726
00727 if (host_event_type >= AST_EVENT_TOTAL) {
00728 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
00729 "type '%d'!\n", host_event_type);
00730 return -1;
00731 }
00732
00733
00734 if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
00735 == AST_EVENT_SUB_NONE) {
00736 ast_event_destroy(event);
00737 return 0;
00738 }
00739
00740 if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
00741 return -1;
00742
00743 event_ref->event = event;
00744
00745 ast_mutex_lock(&event_thread.lock);
00746 AST_LIST_INSERT_TAIL(&event_thread.event_q, event_ref, entry);
00747 ast_cond_signal(&event_thread.cond);
00748 ast_mutex_unlock(&event_thread.lock);
00749
00750 return 0;
00751 }
00752
00753 static void *ast_event_dispatcher(void *unused)
00754 {
00755 for (;;) {
00756 struct ast_event_ref *event_ref;
00757 struct ast_event_sub *sub;
00758 uint16_t host_event_type;
00759
00760 ast_mutex_lock(&event_thread.lock);
00761 while (!(event_ref = AST_LIST_REMOVE_HEAD(&event_thread.event_q, entry)))
00762 ast_cond_wait(&event_thread.cond, &event_thread.lock);
00763 ast_mutex_unlock(&event_thread.lock);
00764
00765 host_event_type = ntohs(event_ref->event->type);
00766
00767
00768 AST_RWLIST_RDLOCK(&ast_event_subs[host_event_type]);
00769 AST_RWLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
00770 struct ast_event_ie_val *ie_val;
00771 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00772 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
00773 ast_event_get_ie_raw(event_ref->event, ie_val->ie_type)) {
00774 continue;
00775 } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00776 ast_event_get_ie_uint(event_ref->event, ie_val->ie_type)
00777 == ie_val->payload.uint) {
00778 continue;
00779 } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00780 !strcmp(ast_event_get_ie_str(event_ref->event, ie_val->ie_type),
00781 ie_val->payload.str)) {
00782 continue;
00783 }
00784 break;
00785 }
00786 if (ie_val)
00787 continue;
00788 sub->cb(event_ref->event, sub->userdata);
00789 }
00790 AST_RWLIST_UNLOCK(&ast_event_subs[host_event_type]);
00791
00792
00793 AST_RWLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
00794 AST_RWLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry)
00795 sub->cb(event_ref->event, sub->userdata);
00796 AST_RWLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
00797
00798 ast_event_ref_destroy(event_ref);
00799 }
00800
00801 return NULL;
00802 }
00803
00804 void ast_event_init(void)
00805 {
00806 int i;
00807
00808 for (i = 0; i < AST_EVENT_TOTAL; i++)
00809 AST_RWLIST_HEAD_INIT(&ast_event_subs[i]);
00810
00811 for (i = 0; i < AST_EVENT_TOTAL; i++)
00812 AST_RWLIST_HEAD_INIT(&ast_event_cache[i]);
00813
00814 ast_cond_init(&event_thread.cond, NULL);
00815
00816 for (i = 0; i < NUM_EVENT_THREADS; i++) {
00817 pthread_t dont_care;
00818 ast_pthread_create_background(&dont_care, NULL, ast_event_dispatcher, NULL);
00819 }
00820 }