diff options
-rw-r--r-- | include/asterisk/event.h | 165 | ||||
-rw-r--r-- | include/asterisk/event_defs.h | 57 | ||||
-rw-r--r-- | main/event.c | 558 |
3 files changed, 623 insertions, 157 deletions
diff --git a/include/asterisk/event.h b/include/asterisk/event.h index 01fc833ba..45d10fc73 100644 --- a/include/asterisk/event.h +++ b/include/asterisk/event.h @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2007, Digium, Inc. + * Copyright (C) 2007 - 2008, Digium, Inc. * * Russell Bryant <russell@digium.com> * @@ -114,14 +114,110 @@ struct ast_event_sub *ast_event_subscribe(enum ast_event_type event_type, ast_event_cb_t cb, void *userdata, ...); /*! + * \brief Allocate a subscription, but do not activate it + * + * \arg type the event type to subscribe to + * \arg cb the function to call when an event matches this subscription + * \arg userdata data to pass to the provided callback + * + * This function should be used when you want to dynamically build a + * subscription. + * + * \return the allocated subscription, or NULL on failure + */ +struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, + ast_event_cb_t cb, void *userdata); + +/*! + * \brief Destroy an allocated subscription + * + * \arg sub the subscription to destroy + * + * This function should be used when a subscription is allocated with + * ast_event_subscribe_new(), but for some reason, you want to destroy it + * instead of activating it. This could be because of an error when + * reading in the configuration for the dynamically built subscription. + */ +void ast_event_sub_destroy(struct ast_event_sub *sub); + +/*! + * \brief Append a uint parameter to a subscription + * + * \arg sub the dynamic subscription allocated with ast_event_subscribe_new() + * \arg ie_type the information element type for the parameter + * \arg uint the value that must be present in the event to match this subscription + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_sub_append_ie_uint(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type, uint32_t uint); + +/*! + * \brief Append a string parameter to a subscription + * + * \arg sub the dynamic subscription allocated with ast_event_subscribe_new() + * \arg ie_type the information element type for the parameter + * \arg str the string that must be present in the event to match this subscription + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_sub_append_ie_str(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type, const char *str); + +/*! + * \brief Append a raw parameter to a subscription + * + * \arg sub the dynamic subscription allocated with ast_event_subscribe_new() + * \arg ie_type the information element type for the parameter + * \arg raw the data that must be present in the event to match this subscription + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_sub_append_ie_raw(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type, void *data, size_t raw_datalen); + +/*! + * \brief Append an 'exists' parameter to a subscription + * + * \arg sub the dynamic subscription allocated with ast_event_subscribe_new() + * \arg ie_type the information element type that must be present in the event + * for it to match this subscription. + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_sub_append_ie_exists(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type); + +/*! + * \brief Activate a dynamically built subscription + * + * \arg sub the subscription to activate that was allocated using + * ast_event_subscribe_new() + * + * Once a dynamically built subscription has had all of the parameters added + * to it, it should be activated using this function. + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_sub_activate(struct ast_event_sub *sub); + +/*! * \brief Un-subscribe from events * * \param event_sub This is the reference to the subscription returned by * ast_event_subscribe. - * - * \return Nothing + * + * This function will remove a subscription and free the associated data + * structures. + * + * \return NULL for convenience. */ -void ast_event_unsubscribe(struct ast_event_sub *event_sub); +struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *event_sub); /*! * \brief Check if subscribers exist @@ -178,6 +274,9 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type eve */ void ast_event_report_subs(const struct ast_event_sub *sub); +/*! \brief Dump the event cache for the subscriber */ +void ast_event_dump_cache(const struct ast_event_sub *event_sub); + /*! * \brief Create a new event * @@ -412,6 +511,24 @@ const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_i const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type); /*! + * \brief Get the string representation of an information element type + * + * \arg ie_type the information element type to get the string representation of + * + * \return the string representation of the information element type + */ +const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type); + +/*! + * \brief Get the payload type for a given information element type + * + * \arg ie_type the information element type to get the payload type of + * + * \return the payload type for the provided IE type + */ +enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type); + +/*! * \brief Get the type for an event * * \param event the event to get the type for @@ -422,6 +539,46 @@ const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_i enum ast_event_type ast_event_get_type(const struct ast_event *event); /*! + * \brief Get the string representation of the type of the given event + * + * \arg event the event to get the type of + * + * \return the string representation of the event type of the provided event + */ +const char *ast_event_get_type_name(const struct ast_event *event); + +/*! + * \brief Convert a string into an event type + * + * \arg str the string to convert + * \arg event_type an output parameter for the event type + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type); + +/*! + * \brief Convert a string to an IE type + * + * \arg str the string to convert + * \arg ie_type an output parameter for the IE type + * + * \retval 0 success + * \retval non-zero failure + */ +int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type); + +/*! + * \brief Get the size of an event + * + * \param event the event to get the size of + * + * \return the number of bytes contained in the event + */ +size_t ast_event_get_size(const struct ast_event *event); + +/*! * \brief Initialize an event iterator instance * * \param iterator The iterator instance to initialize diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h index b664ac14b..3f1e3bd15 100644 --- a/include/asterisk/event_defs.h +++ b/include/asterisk/event_defs.h @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2007, Digium, Inc. + * Copyright (C) 2007 - 2008, Digium, Inc. * * Russell Bryant <russell@digium.com> * @@ -29,23 +29,27 @@ * \note These values can *never* change. */ enum ast_event_type { /*! Reserved to provide the ability to subscribe to all events. A specific - event should never have a payload of 0. */ - AST_EVENT_ALL = 0x00, + * event should never have a payload of 0. */ + AST_EVENT_ALL = 0x00, /*! This event type is reserved for use by third-party modules to create - custom events without having to modify this file. - \note There are no "custom" IE types, because IEs only have to be - unique to the event itself, not necessarily across all events. */ - AST_EVENT_CUSTOM = 0x01, + * custom events without having to modify this file. + * \note There are no "custom" IE types, because IEs only have to be + * unique to the event itself, not necessarily across all events. */ + AST_EVENT_CUSTOM = 0x01, /*! Voicemail message waiting indication */ - AST_EVENT_MWI = 0x02, + AST_EVENT_MWI = 0x02, /*! Someone has subscribed to events */ - AST_EVENT_SUB = 0x03, + AST_EVENT_SUB = 0x03, /*! Someone has unsubscribed from events */ - AST_EVENT_UNSUB = 0x04, - /*! The state of a device has changed */ - AST_EVENT_DEVICE_STATE = 0x05, + AST_EVENT_UNSUB = 0x04, + /*! The aggregate state of a device across all servers configured to be + * a part of a device state cluster has changed. */ + AST_EVENT_DEVICE_STATE = 0x05, + /*! The state of a device has changed on _one_ server. This should not be used + * directly, in general. Use AST_EVENT_DEVICE_STATE instead. */ + AST_EVENT_DEVICE_STATE_CHANGE = 0x06, /*! Number of event types. This should be the last event type + 1 */ - AST_EVENT_TOTAL = 0x06, + AST_EVENT_TOTAL = 0x07, }; /*! \brief Event Information Element types */ @@ -91,13 +95,13 @@ enum ast_event_ie_type { AST_EVENT_IE_EXISTS = 0x06, /*! * \brief Device Name - * Used by AST_EVENT_DEVICE_STATE + * Used by AST_EVENT_DEVICE_STATE_CHANGE * Payload type: STR */ AST_EVENT_IE_DEVICE = 0x07, /*! * \brief Generic State IE - * Used by AST_EVENT_DEVICE_STATE + * Used by AST_EVENT_DEVICE_STATE_CHANGE * Payload type: UINT * The actual state values depend on the event which * this IE is a part of. @@ -109,18 +113,30 @@ enum ast_event_ie_type { * Payload type: str */ AST_EVENT_IE_CONTEXT = 0x09, + /*! + * \brief Entity ID + * Used by All events + * Payload type: RAW + * This IE indicates which server the event originated from + */ + AST_EVENT_IE_EID = 0x0A, }; +#define AST_EVENT_IE_MAX AST_EVENT_IE_EID + /*! * \brief Payload types for event information elements */ enum ast_event_ie_pltype { + AST_EVENT_IE_PLTYPE_UNKNOWN = -1, /*! Just check if it exists, not the value */ AST_EVENT_IE_PLTYPE_EXISTS, /*! Unsigned Integer (Can be used for signed, too ...) */ AST_EVENT_IE_PLTYPE_UINT, /*! String */ AST_EVENT_IE_PLTYPE_STR, + /*! Raw data, compared with memcmp */ + AST_EVENT_IE_PLTYPE_RAW, }; /*! @@ -140,4 +156,15 @@ struct ast_event_ie; struct ast_event_sub; struct ast_event_iterator; +/*! + * \brief supposed to be an opaque type + * + * This is only here so that it can be declared on the stack. + */ +struct ast_event_iterator { + uint16_t event_len; + const struct ast_event *event; + struct ast_event_ie *ie; +}; + #endif /* AST_EVENT_DEFS_H */ diff --git a/main/event.c b/main/event.c index 4855e43a3..2ce4464af 100644 --- a/main/event.c +++ b/main/event.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2007, Digium, Inc. + * Copyright (C) 2007 - 2008, Digium, Inc. * * Russell Bryant <russell@digium.com> * @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/utils.h" #include "asterisk/unaligned.h" +#include "asterisk/utils.h" #include "asterisk/taskprocessor.h" struct ast_taskprocessor *event_dispatcher; @@ -78,12 +79,6 @@ struct ast_event_ref { AST_LIST_ENTRY(ast_event_ref) entry; }; -struct ast_event_iterator { - uint16_t event_len; - const struct ast_event *event; - struct ast_event_ie *ie; -}; - struct ast_event_ie_val { AST_LIST_ENTRY(ast_event_ie_val) entry; enum ast_event_ie_type ie_type; @@ -91,7 +86,9 @@ struct ast_event_ie_val { union { uint32_t uint; const char *str; + void *raw; } payload; + size_t raw_datalen; }; /*! \brief Event subscription */ @@ -116,10 +113,128 @@ static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_E * needs to know this state, it can get the last known state from the cache. */ static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL]; +/*! + * The index of each entry _must_ match the event type number! + */ +static struct event_name { + enum ast_event_type type; + const char *name; +} event_names[] = { + { 0, "" }, + { AST_EVENT_CUSTOM, "Custom" }, + { AST_EVENT_MWI, "MWI" }, + { AST_EVENT_SUB, "Subscription" }, + { AST_EVENT_UNSUB, "Unsubscription" }, + { AST_EVENT_DEVICE_STATE, "DeviceState" }, + { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" }, +}; + +/*! + * The index of each entry _must_ match the event ie number! + */ +static struct ie_map { + enum ast_event_ie_type ie_type; + enum ast_event_ie_pltype ie_pltype; + const char *name; +} ie_maps[] = { + { 0, 0, "" }, + { AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, "NewMessages" }, + { AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, "OldMessages" }, + { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, "Mailbox" }, + { AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, "UniqueID" }, + { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" }, + { AST_EVENT_IE_EXISTS, AST_EVENT_IE_PLTYPE_UINT, "Exists" }, + { AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, "Device" }, + { AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, "State" }, + { AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, "Context" }, + { AST_EVENT_IE_EID, AST_EVENT_IE_PLTYPE_RAW, "EntityID" }, +}; + +const char *ast_event_get_type_name(const struct ast_event *event) +{ + enum ast_event_type type; + + type = ast_event_get_type(event); + + if (type >= AST_EVENT_TOTAL || type < 0) { + ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type); + return ""; + } + + return event_names[type].name; +} + +int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type) +{ + int i; + + for (i = 0; i < ARRAY_LEN(event_names); i++) { + if (strcasecmp(event_names[i].name, str)) + continue; + + *event_type = event_names[i].type; + return 0; + } + + return -1; +} + +const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type) +{ + if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) { + ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type); + return ""; + } + + return ie_maps[ie_type].name; +} + +enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type) +{ + if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) { + ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type); + return AST_EVENT_IE_PLTYPE_UNKNOWN; + } + + return ie_maps[ie_type].ie_pltype; +} + +int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type) +{ + int i; + + for (i = 0; i < ARRAY_LEN(ie_maps); i++) { + if (strcasecmp(ie_maps[i].name, str)) + continue; + + *ie_type = ie_maps[i].ie_type; + return 0; + } + + return -1; +} + +size_t ast_event_get_size(const struct ast_event *event) +{ + size_t res; + + res = ntohs(event->event_len); + + return res; +} + static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val) { - if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) - ast_free((void *) ie_val->payload.str); + switch (ie_val->ie_pltype) { + case AST_EVENT_IE_PLTYPE_STR: + case AST_EVENT_IE_PLTYPE_RAW: + ast_free(ie_val->payload.raw); + break; + case AST_EVENT_IE_PLTYPE_UINT: + case AST_EVENT_IE_PLTYPE_EXISTS: + case AST_EVENT_IE_PLTYPE_UNKNOWN: + break; + } ast_free(ie_val); } @@ -151,6 +266,13 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ ie_val->payload.uint = va_arg(ap, uint32_t); else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) ie_val->payload.str = ast_strdupa(va_arg(ap, const char *)); + else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) { + void *data = va_arg(ap, void *); + size_t datalen = va_arg(ap, size_t); + ie_val->payload.raw = alloca(datalen); + memcpy(ie_val->payload.raw, data, datalen); + ie_val->raw_datalen = datalen; + } AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry); } va_end(ap); @@ -176,6 +298,9 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR && strcmp(ie_val->payload.str, sub_ie_val->payload.str)) break; + if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW && + memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen)) + break; } if (!ie_val) break; @@ -193,6 +318,97 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ return res; } +static int match_ie_val(struct ast_event *event, struct ast_event_ie_val *ie_val, struct ast_event *event2) +{ + if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) { + uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint; + if (val == ast_event_get_ie_uint(event, ie_val->ie_type)) + return 1; + return 0; + } + + if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) { + const char *str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str; + if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) + return 1; + return 0; + } + + if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) { + const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw; + if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen)) + return 1; + return 0; + } + + if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) { + if (ast_event_get_ie_raw(event, ie_val->ie_type)) + return 1; + return 0; + } + + return 0; +} + +/*! \brief Dump the event cache for the subscribed event type */ +void ast_event_dump_cache(const struct ast_event_sub *event_sub) +{ + struct ast_event_ref *event_ref; + enum ast_event_type type = event_sub->type; + + AST_RWLIST_RDLOCK(&ast_event_cache[type]); + AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) { + struct ast_event_ie_val *ie_val; + AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) { + if (!match_ie_val(event_ref->event, ie_val, NULL)) + break; + } + if (!ie_val) { + /* All parameters were matched on this cache entry, so dump it */ + event_sub->cb(event_ref->event, event_sub->userdata); + } + } + AST_RWLIST_TRAVERSE_SAFE_END + AST_RWLIST_UNLOCK(&ast_event_cache[type]); +} + +static struct ast_event *gen_sub_event(struct ast_event_sub *sub) +{ + struct ast_event_ie_val *ie_val; + struct ast_event *event; + + event = ast_event_new(AST_EVENT_SUB, + AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid, + AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type, + AST_EVENT_IE_END); + + if (!event) + return NULL; + + AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { + switch (ie_val->ie_pltype) { + case AST_EVENT_IE_PLTYPE_UNKNOWN: + break; + case AST_EVENT_IE_PLTYPE_EXISTS: + ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type); + break; + case AST_EVENT_IE_PLTYPE_UINT: + ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint); + break; + case AST_EVENT_IE_PLTYPE_STR: + ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str); + break; + case AST_EVENT_IE_PLTYPE_RAW: + ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen); + break; + } + if (!event) + break; + } + + return event; +} + /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */ void ast_event_report_subs(const struct ast_event_sub *event_sub) { @@ -219,26 +435,7 @@ void ast_event_report_subs(const struct ast_event_sub *event_sub) if (event_sub == sub) continue; - event = ast_event_new(AST_EVENT_SUB, - AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid, - AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type, - AST_EVENT_IE_END); - - AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { - switch (ie_val->ie_pltype) { - case AST_EVENT_IE_PLTYPE_EXISTS: - ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type); - break; - case AST_EVENT_IE_PLTYPE_UINT: - ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint); - break; - case AST_EVENT_IE_PLTYPE_STR: - ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str); - break; - } - if (!event) - break; - } + event = gen_sub_event(sub); if (!event) continue; @@ -250,15 +447,12 @@ void ast_event_report_subs(const struct ast_event_sub *event_sub) AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]); } -struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, - void *userdata, ...) +struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, + ast_event_cb_t cb, void *userdata) { - va_list ap; - enum ast_event_ie_type ie_type; struct ast_event_sub *sub; - struct ast_event *event; - if (type >= AST_EVENT_TOTAL) { + if (type < 0 || type >= AST_EVENT_TOTAL) { ast_log(LOG_ERROR, "%u is an invalid type!\n", type); return NULL; } @@ -266,71 +460,178 @@ struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb if (!(sub = ast_calloc(1, sizeof(*sub)))) return NULL; - va_start(ap, userdata); - for (ie_type = va_arg(ap, enum ast_event_type); - ie_type != AST_EVENT_IE_END; - ie_type = va_arg(ap, enum ast_event_type)) - { - struct ast_event_ie_val *ie_val; - if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) - continue; - ie_val->ie_type = ie_type; - ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype); - if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) - ie_val->payload.uint = va_arg(ap, uint32_t); - else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) { - if (!(ie_val->payload.str = ast_strdup(va_arg(ap, const char *)))) { - ast_free(ie_val); - continue; - } - } - AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry); - } - va_end(ap); - sub->type = type; sub->cb = cb; sub->userdata = userdata; sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1); + return sub; +} + +int ast_event_sub_append_ie_uint(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type, uint32_t uint) +{ + struct ast_event_ie_val *ie_val; + + if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) + return -1; + + if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) + return -1; + + ie_val->ie_type = ie_type; + ie_val->payload.uint = uint; + ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT; + + AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry); + + return 0; +} + +int ast_event_sub_append_ie_exists(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type) +{ + struct ast_event_ie_val *ie_val; + + if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) + return -1; + + if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) + return -1; + + ie_val->ie_type = ie_type; + ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS; + + AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry); + + return 0; +} + +int ast_event_sub_append_ie_str(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type, const char *str) +{ + struct ast_event_ie_val *ie_val; + + if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) + return -1; + + if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) + return -1; + + ie_val->ie_type = ie_type; + ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR; + + if (!(ie_val->payload.str = ast_strdup(str))) { + ast_free(ie_val); + return -1; + } + + AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry); + + return 0; +} + +int ast_event_sub_append_ie_raw(struct ast_event_sub *sub, + enum ast_event_ie_type ie_type, void *data, size_t raw_datalen) +{ + struct ast_event_ie_val *ie_val; + + if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) + return -1; + + if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) + return -1; + + ie_val->ie_type = ie_type; + ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW; + ie_val->raw_datalen = raw_datalen; + + if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) { + ast_free(ie_val); + return -1; + } + + memcpy(ie_val->payload.raw, data, raw_datalen); + + AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry); + + return 0; +} + +int ast_event_sub_activate(struct ast_event_sub *sub) +{ if (ast_event_check_subscriber(AST_EVENT_SUB, - AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, type, + AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type, AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) { - struct ast_event_ie_val *ie_val; + struct ast_event *event; - event = ast_event_new(AST_EVENT_SUB, - AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid, - AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type, - AST_EVENT_IE_END); - - AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) { - switch (ie_val->ie_pltype) { - case AST_EVENT_IE_PLTYPE_EXISTS: - ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type); - break; - case AST_EVENT_IE_PLTYPE_UINT: - ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint); - break; - case AST_EVENT_IE_PLTYPE_STR: - ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str); - break; - } - if (!event) - break; - } + event = gen_sub_event(sub); if (event) ast_event_queue(event); } - AST_RWDLLIST_WRLOCK(&ast_event_subs[type]); - AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[type], sub, entry); - AST_RWDLLIST_UNLOCK(&ast_event_subs[type]); + AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]); + AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry); + AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]); + + return 0; +} + +struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, + void *userdata, ...) +{ + va_list ap; + enum ast_event_ie_type ie_type; + struct ast_event_sub *sub; + + if (!(sub = ast_event_subscribe_new(type, cb, userdata))) + return NULL; + + va_start(ap, userdata); + for (ie_type = va_arg(ap, enum ast_event_type); + ie_type != AST_EVENT_IE_END; + ie_type = va_arg(ap, enum ast_event_type)) + { + enum ast_event_ie_pltype ie_pltype; + + ie_pltype = va_arg(ap, enum ast_event_ie_pltype); + + switch (ie_pltype) { + case AST_EVENT_IE_PLTYPE_UNKNOWN: + break; + case AST_EVENT_IE_PLTYPE_UINT: + { + uint32_t uint = va_arg(ap, uint32_t); + ast_event_sub_append_ie_uint(sub, ie_type, uint); + break; + } + case AST_EVENT_IE_PLTYPE_STR: + { + const char *str = va_arg(ap, const char *); + ast_event_sub_append_ie_str(sub, ie_type, str); + break; + } + case AST_EVENT_IE_PLTYPE_RAW: + { + void *data = va_arg(ap, void *); + size_t data_len = va_arg(ap, size_t); + ast_event_sub_append_ie_raw(sub, ie_type, data, data_len); + break; + } + case AST_EVENT_IE_PLTYPE_EXISTS: + ast_event_sub_append_ie_exists(sub, ie_type); + break; + } + } + va_end(ap); + + ast_event_sub_activate(sub); return sub; } -static void ast_event_sub_destroy(struct ast_event_sub *sub) +void ast_event_sub_destroy(struct ast_event_sub *sub) { struct ast_event_ie_val *ie_val; @@ -340,7 +641,7 @@ static void ast_event_sub_destroy(struct ast_event_sub *sub) ast_free(sub); } -void ast_event_unsubscribe(struct ast_event_sub *sub) +struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub) { struct ast_event *event; @@ -362,6 +663,8 @@ void ast_event_unsubscribe(struct ast_event_sub *sub) } ast_event_sub_destroy(sub); + + return NULL; } void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event) @@ -494,6 +797,13 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...) ie_val->payload.uint = va_arg(ap, uint32_t); else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) ie_val->payload.str = ast_strdupa(va_arg(ap, const char *)); + else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) { + void *data = va_arg(ap, void *); + size_t datalen = va_arg(ap, size_t); + ie_val->payload.raw = alloca(datalen); + memcpy(ie_val->payload.raw, data, datalen); + ie_val->raw_datalen = datalen; + } AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry); } va_end(ap); @@ -509,11 +819,19 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...) ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str); else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint); + else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) + ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen); if (!event) break; } + if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) { + /* If the event is originating on this server, add the server's + * entity ID to the event. */ + ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &g_eid, sizeof(g_eid)); + } + return event; } @@ -533,7 +851,7 @@ static struct ast_event *ast_event_dup(const struct ast_event *event) struct ast_event *dup_event; uint16_t event_len; - event_len = ntohs(event->event_len); + event_len = ast_event_get_size(event); if (!(dup_event = ast_calloc(1, event_len))) return NULL; @@ -549,16 +867,8 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...) enum ast_event_ie_type ie_type; struct ast_event *dup_event = NULL; struct ast_event_ref *event_ref; - struct cache_arg { - AST_LIST_ENTRY(cache_arg) entry; - enum ast_event_ie_type ie_type; - enum ast_event_ie_pltype ie_pltype; - union { - uint32_t uint; - const char *str; - } payload; - } *cache_arg; - AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg); + struct ast_event_ie_val *cache_arg; + AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val); if (type >= AST_EVENT_TOTAL) { ast_log(LOG_ERROR, "%u is an invalid type!\n", type); @@ -578,6 +888,13 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...) cache_arg->payload.uint = va_arg(ap, uint32_t); else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR) cache_arg->payload.str = ast_strdupa(va_arg(ap, const char *)); + else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) { + void *data = va_arg(ap, void *); + size_t datalen = va_arg(ap, size_t); + cache_arg->payload.raw = alloca(datalen); + memcpy(cache_arg->payload.raw, data, datalen); + cache_arg->raw_datalen = datalen; + } AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry); } va_end(ap); @@ -591,19 +908,8 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...) AST_RWLIST_RDLOCK(&ast_event_cache[type]); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) { AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) { - if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT && - (cache_arg->payload.uint == - ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) || - - (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR && - (!strcmp(cache_arg->payload.str, - ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) || - - (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS && - ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) ) - { + if (!match_ie_val(event_ref->event, cache_arg, NULL)) break; - } } if (!cache_arg) { /* All parameters were matched on this cache entry, so return it */ @@ -643,12 +949,8 @@ int ast_event_queue_and_cache(struct ast_event *event, ...) uint16_t host_event_type; struct ast_event_ref *event_ref; int res; - struct cache_arg { - AST_LIST_ENTRY(cache_arg) entry; - enum ast_event_ie_type ie_type; - enum ast_event_ie_pltype ie_pltype; - } *cache_arg; - AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg); + struct ast_event_ie_val *cache_arg; + AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val); host_event_type = ntohs(event->type); @@ -668,6 +970,8 @@ int ast_event_queue_and_cache(struct ast_event *event, ...) memset(cache_arg, 0, sizeof(*cache_arg)); cache_arg->ie_type = ie_type; cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype); + if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) + cache_arg->raw_datalen = va_arg(ap, size_t); AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry); } va_end(ap); @@ -681,19 +985,8 @@ int ast_event_queue_and_cache(struct ast_event *event, ...) AST_RWLIST_WRLOCK(&ast_event_cache[host_event_type]); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[host_event_type], event_ref, entry) { AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) { - if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT && - (ast_event_get_ie_uint(event, cache_arg->ie_type) == - ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) || - - (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR && - (!strcmp(ast_event_get_ie_str(event, cache_arg->ie_type), - ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) || - - (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS && - ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) ) - { + if (!match_ie_val(event_ref->event, cache_arg, event)) break; - } } if (!cache_arg) { /* All parameters were matched on this cache entry, so remove it */ @@ -721,19 +1014,8 @@ static int handle_event(void *data) 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 (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS && - ast_event_get_ie_raw(event_ref->event, ie_val->ie_type)) { - continue; - } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT && - ast_event_get_ie_uint(event_ref->event, ie_val->ie_type) - == ie_val->payload.uint) { - continue; - } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR && - !strcmp(ast_event_get_ie_str(event_ref->event, ie_val->ie_type), - ie_val->payload.str)) { - continue; - } - break; + if (!match_ie_val(event_ref->event, ie_val, NULL)) + break; } if (ie_val) continue; |