diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-04-22 21:06:53 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-04-22 21:06:53 +0000 |
commit | 9c4e095194143632fa08aa9301d1d7f2e03a400c (patch) | |
tree | 81248e5756094401a6fee21329af4056f2b72562 /main/event.c | |
parent | c81c6b967b6e1a5060d2b93016e1d9e83e703b6d (diff) |
Add ast_event subscription unit test and fix some ast_event API bugs.
This patch introduces another test in test_event.c that exercises most of the
subscription related ast_event API calls. I made some minor additions to the
existing event allocation test to increase API coverage by the test code.
Finally, I made a list in a comment of API calls not yet touched by the test
module as a to-do list for future test development.
During the development of this test code, I discovered a number of bugs in
the event API.
1) subscriptions to AST_EVENT_ALL were not handled appropriately in a couple
of different places. The API allows a subscription to all event types,
but with IE parameters, just as if it was a subscription to a specific
event type. However, the parameters were being ignored. This affected
ast_event_check_subscriber() and event distribution to subscribers.
2) Some of the logic in ast_event_check_subscriber() for checking subscriptions
against query parameters was wrong.
Review: https://reviewboard.asterisk.org/r/617/
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@258632 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/event.c')
-rw-r--r-- | main/event.c | 180 |
1 files changed, 100 insertions, 80 deletions
diff --git a/main/event.c b/main/event.c index 366834ea6..51a3a45ab 100644 --- a/main/event.c +++ b/main/event.c @@ -350,14 +350,69 @@ static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val) ast_free(ie_val); } +/*! + * \internal + * \brief Check if an ie_val matches a subscription + * + * \param sub subscription to check against + * \param ie_val IE value to check + * + * \retval 0 not matched + * \retval non-zero matched + */ +static int match_ie_val_to_sub(const struct ast_event_sub *sub, const struct ast_event_ie_val *ie_val) +{ + const struct ast_event_ie_val *sub_ie_val; + int res = 1; + + AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) { + if (sub_ie_val->ie_type == ie_val->ie_type) { + break; + } + } + + if (!sub_ie_val) { + /* This subscriber doesn't care about this IE, so consider + * it matched. */ + return 1; + } + + switch (ie_val->ie_pltype) { + case AST_EVENT_IE_PLTYPE_UINT: + res = (ie_val->payload.uint != sub_ie_val->payload.uint); + break; + case AST_EVENT_IE_PLTYPE_BITFLAGS: + /* + * If the subscriber has requested *any* of the bitflags we are providing, + * then it's a match. + */ + res = !(ie_val->payload.uint & sub_ie_val->payload.uint); + break; + case AST_EVENT_IE_PLTYPE_STR: + res = strcmp(ie_val->payload.str, sub_ie_val->payload.str); + break; + case AST_EVENT_IE_PLTYPE_RAW: + res = memcmp(ie_val->payload.raw, + sub_ie_val->payload.raw, ie_val->raw_datalen); + break; + case AST_EVENT_IE_PLTYPE_EXISTS: + case AST_EVENT_IE_PLTYPE_UNKNOWN: + break; + } + + return res; +} + enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...) { va_list ap; enum ast_event_ie_type ie_type; enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE; - struct ast_event_ie_val *ie_val, *sub_ie_val; + struct ast_event_ie_val *ie_val; struct ast_event_sub *sub; AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val); + const enum ast_event_type event_types[] = { type, AST_EVENT_ALL }; + int i; if (type >= AST_EVENT_TOTAL) { ast_log(LOG_ERROR, "%u is an invalid type!\n", type); @@ -405,74 +460,42 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ } va_end(ap); - AST_RWDLLIST_RDLOCK(&ast_event_subs[type]); - AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) { - AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) { - int break_out = 0; - - AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) { - if (sub_ie_val->ie_type == ie_val->ie_type) { + for (i = 0; i < ARRAY_LEN(event_types); i++) { + AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]); + AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) { + AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) { + if (match_ie_val_to_sub(sub, ie_val)) { break; } } - if (!sub_ie_val) { - /* This subscriber doesn't care about this IE, so consider - * it matched. */ - continue; - } - - switch (ie_val->ie_pltype) { - case AST_EVENT_IE_PLTYPE_UINT: - break_out = (ie_val->payload.uint != sub_ie_val->payload.uint); - break; - case AST_EVENT_IE_PLTYPE_BITFLAGS: - /* if the subscriber has requested *any* of the bitflags we are providing, - * then it's a match - */ - break_out = (ie_val->payload.uint & sub_ie_val->payload.uint); - break; - case AST_EVENT_IE_PLTYPE_STR: - break_out = strcmp(ie_val->payload.str, sub_ie_val->payload.str); - break; - case AST_EVENT_IE_PLTYPE_RAW: - break_out = memcmp(ie_val->payload.raw, - sub_ie_val->payload.raw, ie_val->raw_datalen); - break; - case AST_EVENT_IE_PLTYPE_EXISTS: - /* The subscriber doesn't actually care what the value is */ - break_out = 1; - break; - case AST_EVENT_IE_PLTYPE_UNKNOWN: - break; - } - - if (break_out) { + if (!ie_val) { + /* Everything matched. */ break; } } - - if (!ie_val) { - /* Everything matched */ + AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]); + if (sub) { break; } } - AST_RWDLLIST_UNLOCK(&ast_event_subs[type]); - - if (sub) { - /* All parameters were matched */ - return AST_EVENT_SUB_EXISTS; - } - AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]); - if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL])) { - res = AST_EVENT_SUB_EXISTS; - } - AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]); - - return res; + return sub ? AST_EVENT_SUB_EXISTS : AST_EVENT_SUB_NONE; } +/*! + * \internal + * \brief Check if an ie_val matches an event + * + * \param event event to check against + * \param ie_val IE value to check + * \param event2 optional event, if specified, the value to compare against will be pulled + * from this event instead of from the ie_val structure. In this case, only the IE + * type and payload type will be pulled from ie_val. + * + * \retval 0 not matched + * \retval non-zero matched + */ static int match_ie_val(const struct ast_event *event, const struct ast_event_ie_val *ie_val, const struct ast_event *event2) { @@ -488,8 +511,9 @@ static int match_ie_val(const struct ast_event *event, { uint32_t flags = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint; - /* if the subscriber has requested *any* of the bitflags that this event provides, - * then it's a match + /* + * If the subscriber has requested *any* of the bitflags that this event provides, + * then it's a match. */ return (flags & ast_event_get_ie_bitflags(event, ie_val->ie_type)) ? 1 : 0; } @@ -1332,32 +1356,28 @@ static int handle_event(void *data) { struct ast_event_ref *event_ref = data; struct ast_event_sub *sub; - uint16_t host_event_type; - - host_event_type = ntohs(event_ref->event->type); + const enum ast_event_type event_types[] = { + ntohs(event_ref->event->type), + AST_EVENT_ALL + }; + int i; - /* Subscribers to this specific event first */ - AST_RWDLLIST_RDLOCK(&ast_event_subs[host_event_type]); - AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) { - struct ast_event_ie_val *ie_val; - AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { - if (!match_ie_val(event_ref->event, ie_val, NULL)) { - break; + for (i = 0; i < ARRAY_LEN(event_types); i++) { + AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]); + AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) { + struct ast_event_ie_val *ie_val; + AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { + if (!match_ie_val(event_ref->event, ie_val, NULL)) { + break; + } } + if (ie_val) { + continue; + } + sub->cb(event_ref->event, sub->userdata); } - if (ie_val) { - continue; - } - sub->cb(event_ref->event, sub->userdata); - } - AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]); - - /* Now to subscribers to all event types */ - AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]); - AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry) { - sub->cb(event_ref->event, sub->userdata); + AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]); } - AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]); ao2_ref(event_ref, -1); |