[asterisk-commits] rmudgett: branch 1.8 r321871 - in /branches/1.8: main/event.c tests/test_event.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 3 15:58:17 CDT 2011


Author: rmudgett
Date: Fri Jun  3 15:58:13 2011
New Revision: 321871

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=321871
Log:
Event subscription fixes.

Must commit the subscription fixes together with the integration
subscription tests.  The subscription fixes cause an erroneously passing
test to fail.  The new subscription tests detect errors without the
subscription fixes.

* Added missing event_names[] table entry.

* Reworked ast_event_check_subscriber()/match_sub_ie_val_to_event() to
correctly detect if a subscriber exists for the proposed event.

* Made match_ie_val() and match_sub_ie_val_to_event() check the buffer
length for RAW payload types.

* Fixed error handling memory leak in ast_event_sub_activate(),
ast_event_unsubscribe(), and ast_event_queue().

* Made ast_event_new() and ast_event_check_subscriber() better protect
themselves from an invalid payload type.

* Added container lock protection between removing old cache events and
adding the new cached event in
ast_event_queue_and_cache()/event_update_cache().

* Added new event subscription tests.

Modified:
    branches/1.8/main/event.c
    branches/1.8/tests/test_event.c

Modified: branches/1.8/main/event.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/main/event.c?view=diff&rev=321871&r1=321870&r2=321871
==============================================================================
--- branches/1.8/main/event.c (original)
+++ branches/1.8/main/event.c Fri Jun  3 15:58:13 2011
@@ -194,6 +194,7 @@
  * \brief Event Names
  */
 static const char * const event_names[AST_EVENT_TOTAL] = {
+	[AST_EVENT_ALL]                 = "All",
 	[AST_EVENT_CUSTOM]              = "Custom",
 	[AST_EVENT_MWI]                 = "MWI",
 	[AST_EVENT_SUB]                 = "Subscription",
@@ -359,53 +360,72 @@
 	ast_free(ie_val);
 }
 
+/*! \brief Subscription event check list. */
+struct ast_ev_check_list {
+	AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
+};
+
 /*!
  * \internal
- * \brief Check if an ie_val matches a subscription
- *
- * \param sub subscription to check against
- * \param ie_val IE value to check
+ * \brief Check if a subscription ie_val matches an event.
+ *
+ * \param sub_ie_val Subscripton IE value to check
+ * \param check_ie_vals event list to check against
  *
  * \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) {
+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)
+{
+	const struct ast_event_ie_val *event_ie_val;
+	int res = 0;
+
+	AST_LIST_TRAVERSE(&check_ie_vals->ie_vals, event_ie_val, entry) {
+		if (event_ie_val->ie_type == sub_ie_val->ie_type) {
+			break;
+		}
+	}
+	if (!event_ie_val) {
+		/* The did not find the event ie the subscriber cares about. */
+		return 0;
+	}
+
+	if (sub_ie_val->ie_pltype != event_ie_val->ie_pltype) {
+		if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
+			/* The subscription only cares that this ie exists. */
+			return 1;
+		}
+		/* Payload types do not match. */
+		return 0;
+	}
+
+	switch (sub_ie_val->ie_pltype) {
 	case AST_EVENT_IE_PLTYPE_UINT:
-		res = (ie_val->payload.uint != sub_ie_val->payload.uint);
+		res = (sub_ie_val->payload.uint == event_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);
+		res = (sub_ie_val->payload.uint & event_ie_val->payload.uint);
 		break;
 	case AST_EVENT_IE_PLTYPE_STR:
-		res = strcmp(ie_val->payload.str, sub_ie_val->payload.str);
+		res = !strcmp(sub_ie_val->payload.str, event_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);
+		res = (sub_ie_val->raw_datalen == event_ie_val->raw_datalen
+			&& !memcmp(sub_ie_val->payload.raw, event_ie_val->payload.raw,
+				sub_ie_val->raw_datalen));
 		break;
 	case AST_EVENT_IE_PLTYPE_EXISTS:
+		/* Should never get here since check_ie_vals cannot have this type. */
+		break;
 	case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		/*
+		 * Should never be in a subscription event ie val list and
+		 * check_ie_vals cannot have this type either.
+		 */
 		break;
 	}
 
@@ -419,7 +439,9 @@
 	enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
 	struct ast_event_ie_val *ie_val;
 	struct ast_event_sub *sub;
-	AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
+	struct ast_ev_check_list check_ie_vals = {
+		.ie_vals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
+	};
 	const enum ast_event_type event_types[] = { type, AST_EVENT_ALL };
 	int i;
 
@@ -434,19 +456,740 @@
 		ie_type = va_arg(ap, enum ast_event_ie_type))
 	{
 		struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
-		int insert = 1;
+		int insert = 0;
+
 		memset(ie_value, 0, sizeof(*ie_value));
 		ie_value->ie_type = ie_type;
 		ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
 		switch (ie_value->ie_pltype) {
 		case AST_EVENT_IE_PLTYPE_UINT:
 			ie_value->payload.uint = va_arg(ap, uint32_t);
+			insert = 1;
 			break;
 		case AST_EVENT_IE_PLTYPE_BITFLAGS:
 			ie_value->payload.uint = va_arg(ap, uint32_t);
+			insert = 1;
 			break;
 		case AST_EVENT_IE_PLTYPE_STR:
 			ie_value->payload.str = va_arg(ap, const char *);
+			insert = 1;
+			break;
+		case AST_EVENT_IE_PLTYPE_RAW:
+		{
+			void *data = va_arg(ap, void *);
+			size_t datalen = va_arg(ap, size_t);
+
+			ie_value->payload.raw = alloca(datalen);
+			memcpy(ie_value->payload.raw, data, datalen);
+			ie_value->raw_datalen = datalen;
+			insert = 1;
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		case AST_EVENT_IE_PLTYPE_EXISTS:
+			/* Unsupported payload type. */
+			break;
+		}
+
+		if (insert) {
+			AST_LIST_INSERT_TAIL(&check_ie_vals.ie_vals, ie_value, entry);
+		} else {
+			ast_log(LOG_WARNING, "Unsupported PLTYPE(%d)\n", ie_value->ie_pltype);
+		}
+	}
+	va_end(ap);
+
+	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(&sub->ie_vals, ie_val, entry) {
+				if (!match_sub_ie_val_to_event(ie_val, &check_ie_vals)) {
+					/* The current subscription ie did not match an event ie. */
+					break;
+				}
+			}
+			if (!ie_val) {
+				/* Everything matched.  A subscriber is looking for this event. */
+				break;
+			}
+		}
+		AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
+		if (sub) {
+			break;
+		}
+	}
+
+	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)
+{
+	switch (ie_val->ie_pltype) {
+	case AST_EVENT_IE_PLTYPE_UINT:
+	{
+		uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
+
+		return (val == ast_event_get_ie_uint(event, ie_val->ie_type)) ? 1 : 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_BITFLAGS:
+	{
+		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.
+		 */
+		return (flags & ast_event_get_ie_bitflags(event, ie_val->ie_type)) ? 1 : 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_STR:
+	{
+		const char *str;
+		uint32_t hash;
+
+		hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
+		if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
+			return 0;
+		}
+
+		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;
+	}
+
+	case AST_EVENT_IE_PLTYPE_RAW:
+	{
+		const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
+		uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
+
+		return (buf
+			&& ie_payload_len == ast_event_get_ie_raw_payload_len(event, ie_val->ie_type)
+			&& !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_EXISTS:
+	{
+		return ast_event_get_ie_raw(event, ie_val->ie_type) ? 1 : 0;
+	}
+
+	case AST_EVENT_IE_PLTYPE_UNKNOWN:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int dump_cache_cb(void *obj, void *arg, int flags)
+{
+	const struct ast_event_ref *event_ref = obj;
+	const struct ast_event *event = event_ref->event;
+	const struct ast_event_sub *event_sub = arg;
+	struct ast_event_ie_val *ie_val = NULL;
+
+	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+		if (!match_ie_val(event, ie_val, NULL)) {
+			break;
+		}
+	}
+
+	if (!ie_val) {
+		/* All parameters were matched on this cache entry, so dump it */
+		event_sub->cb(event, event_sub->userdata);
+	}
+
+	return 0;
+}
+
+/*! \brief Dump the event cache for the subscribed event type */
+void ast_event_dump_cache(const struct ast_event_sub *event_sub)
+{
+	ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
+			dump_cache_cb, (void *) event_sub);
+}
+
+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_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
+		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_BITFLAGS:
+			ast_event_append_ie_bitflags(&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)
+{
+	struct ast_event *event;
+	struct ast_event_sub *sub;
+	enum ast_event_type event_type = -1;
+	struct ast_event_ie_val *ie_val;
+
+	if (event_sub->type != AST_EVENT_SUB)
+		return;
+
+	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+		if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
+			event_type = ie_val->payload.uint;
+			break;
+		}
+	}
+
+	if (event_type == -1)
+		return;
+
+	AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
+	AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
+		if (event_sub == sub) {
+			continue;
+		}
+
+		event = gen_sub_event(sub);
+		if (!event) {
+			continue;
+		}
+
+		event_sub->cb(event, event_sub->userdata);
+
+		ast_event_destroy(event);
+	}
+	AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
+}
+
+struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
+	ast_event_cb_t cb, void *userdata)
+{
+	struct ast_event_sub *sub;
+
+	if (type < 0 || type >= AST_EVENT_TOTAL) {
+		ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
+		return NULL;
+	}
+
+	if (!(sub = ast_calloc(1, sizeof(*sub)))) {
+		return NULL;
+	}
+
+	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 unsigned_int)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->payload.uint = unsigned_int;
+	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_bitflags(struct ast_event_sub *sub,
+	enum ast_event_ie_type ie_type, uint32_t flags)
+{
+	struct ast_event_ie_val *ie_val;
+
+	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
+		return -1;
+	}
+
+	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+		return -1;
+	}
+
+	ie_val->ie_type = ie_type;
+	ie_val->payload.uint = flags;
+	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_BITFLAGS;
+
+	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_TOTAL) {
+		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_TOTAL) {
+		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;
+	}
+
+	ie_val->payload.hash = ast_str_hash(str);
+
+	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_TOTAL) {
+		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, sub->type,
+		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+		struct ast_event *event;
+
+		event = gen_sub_event(sub);
+		if (event && ast_event_queue(event)) {
+			ast_event_destroy(event);
+		}
+	}
+
+	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,
+	const char *description, 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;
+	}
+
+	ast_copy_string(sub->description, description, sizeof(sub->description));
+
+	va_start(ap, userdata);
+	for (ie_type = va_arg(ap, enum ast_event_ie_type);
+		ie_type != AST_EVENT_IE_END;
+		ie_type = va_arg(ap, enum ast_event_ie_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 unsigned_int = va_arg(ap, uint32_t);
+			ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
+			break;
+		}
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+		{
+			uint32_t unsigned_int = va_arg(ap, uint32_t);
+			ast_event_sub_append_ie_bitflags(sub, ie_type, unsigned_int);
+			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;
+}
+
+void ast_event_sub_destroy(struct ast_event_sub *sub)
+{
+	struct ast_event_ie_val *ie_val;
+
+	while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry))) {
+		ast_event_ie_val_destroy(ie_val);
+	}
+
+	ast_free(sub);
+}
+
+const char *ast_event_subscriber_get_description(struct ast_event_sub *sub)
+{
+	return sub ? sub->description : NULL;
+}
+
+struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
+{
+	struct ast_event *event;
+
+	AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
+	AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
+	AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
+
+	if (ast_event_check_subscriber(AST_EVENT_UNSUB,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+
+		event = ast_event_new(AST_EVENT_UNSUB,
+			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_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
+			AST_EVENT_IE_END);
+		if (event && ast_event_queue(event)) {
+			ast_event_destroy(event);
+		}
+	}
+
+	ast_event_sub_destroy(sub);
+
+	return NULL;
+}
+
+int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
+{
+	int res = 0;
+
+	iterator->event_len = ast_event_get_size(event);
+	iterator->event = event;
+	if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
+		iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
+	} else {
+		iterator->ie = NULL;
+		res = -1;
+	}
+
+	return res;
+}
+
+int ast_event_iterator_next(struct ast_event_iterator *iterator)
+{
+	iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
+	return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
+}
+
+enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
+{
+	return ntohs(iterator->ie->ie_type);
+}
+
+uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
+{
+	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
+}
+
+uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator)
+{
+	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
+}
+
+const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
+{
+	const struct ast_event_ie_str_payload *str_payload;
+
+	str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
+
+	return str_payload ? str_payload->str : NULL;
+}
+
+void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
+{
+	return iterator->ie->ie_payload;
+}
+
+uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
+{
+	return ntohs(iterator->ie->ie_payload_len);
+}
+
+enum ast_event_type ast_event_get_type(const struct ast_event *event)
+{
+	return ntohs(event->type);
+}
+
+uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const uint32_t *ie_val;
+
+	ie_val = ast_event_get_ie_raw(event, ie_type);
+
+	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+}
+
+uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const uint32_t *ie_val;
+
+	ie_val = ast_event_get_ie_raw(event, ie_type);
+
+	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+}
+
+uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const struct ast_event_ie_str_payload *str_payload;
+
+	str_payload = ast_event_get_ie_raw(event, ie_type);
+
+	return str_payload ? str_payload->hash : 0;
+}
+
+const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	const struct ast_event_ie_str_payload *str_payload;
+
+	str_payload = ast_event_get_ie_raw(event, ie_type);
+
+	return str_payload ? str_payload->str : NULL;
+}
+
+const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	struct ast_event_iterator iterator;
+	int res;
+
+	for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
+		if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
+			return ast_event_iterator_get_ie_raw(&iterator);
+		}
+	}
+
+	return NULL;
+}
+
+uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
+{
+	struct ast_event_iterator iterator;
+	int res;
+
+	for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
+		if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
+			return ast_event_iterator_get_ie_raw_payload_len(&iterator);
+		}
+	}
+
+	return 0;
+}
+
+int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
+	const char *str)
+{
+	struct ast_event_ie_str_payload *str_payload;
+	size_t payload_len;
+
+	payload_len = sizeof(*str_payload) + strlen(str);
+	str_payload = alloca(payload_len);
+
+	strcpy(str_payload->str, str);
+	str_payload->hash = ast_str_hash(str);
+
+	return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
+}
+
+int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
+	uint32_t data)
+{
+	data = htonl(data);
+	return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
+}
+
+int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
+	uint32_t flags)
+{
+	flags = htonl(flags);
+	return ast_event_append_ie_raw(event, ie_type, &flags, sizeof(flags));
+}
+
+int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
+	const void *data, size_t data_len)
+{
+	struct ast_event_ie *ie;
+	unsigned int extra_len;
+	uint16_t event_len;
+
+	event_len = ntohs((*event)->event_len);
+	extra_len = sizeof(*ie) + data_len;
+
+	if (!(*event = ast_realloc(*event, event_len + extra_len))) {
+		return -1;
+	}
+
+	ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
+	ie->ie_type = htons(ie_type);
+	ie->ie_payload_len = htons(data_len);
+	memcpy(ie->ie_payload, data, data_len);
+
+	(*event)->event_len = htons(event_len + extra_len);
+
+	return 0;
+}
+
+struct ast_event *ast_event_new(enum ast_event_type type, ...)
+{
+	va_list ap;
+	struct ast_event *event;
+	enum ast_event_ie_type ie_type;
+	struct ast_event_ie_val *ie_val;
+	int has_ie = 0;
+	AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
+
+	/* Invalid type */
+	if (type >= AST_EVENT_TOTAL) {
+		ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
+			"type '%d'!\n", type);
+		return NULL;
+	}
+
+	va_start(ap, type);
+	for (ie_type = va_arg(ap, enum ast_event_ie_type);
+		ie_type != AST_EVENT_IE_END;
+		ie_type = va_arg(ap, enum ast_event_ie_type))
+	{
+		struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
+		int insert = 0;
+
+		memset(ie_value, 0, sizeof(*ie_value));
+		ie_value->ie_type = ie_type;
+		ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+		switch (ie_value->ie_pltype) {
+		case AST_EVENT_IE_PLTYPE_UINT:
+			ie_value->payload.uint = va_arg(ap, uint32_t);
+			insert = 1;
+			break;
+		case AST_EVENT_IE_PLTYPE_BITFLAGS:
+			ie_value->payload.uint = va_arg(ap, uint32_t);
+			insert = 1;
+			break;
+		case AST_EVENT_IE_PLTYPE_STR:
+			ie_value->payload.str = va_arg(ap, const char *);
+			insert = 1;
 			break;
 		case AST_EVENT_IE_PLTYPE_RAW:
 		{
@@ -455,722 +1198,10 @@
 			ie_value->payload.raw = alloca(datalen);
 			memcpy(ie_value->payload.raw, data, datalen);
 			ie_value->raw_datalen = datalen;
+			insert = 1;
 			break;
 		}
 		case AST_EVENT_IE_PLTYPE_UNKNOWN:
-			insert = 0;
-		case AST_EVENT_IE_PLTYPE_EXISTS:
-			break;
-		}
-
-		if (insert) {
-			AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
-		}
-	}
-	va_end(ap);
-
-	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 (!ie_val) {
-				/* Everything matched. */
-				break;
-			}
-		}
-		AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
-		if (sub) {
-			break;
-		}
-	}
-
-	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)
-{
-	switch (ie_val->ie_pltype) {
-	case AST_EVENT_IE_PLTYPE_UINT:
-	{
-		uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
-
-		return (val == ast_event_get_ie_uint(event, ie_val->ie_type)) ? 1 : 0;
-	}
-
-	case AST_EVENT_IE_PLTYPE_BITFLAGS:
-	{
-		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.
-		 */
-		return (flags & ast_event_get_ie_bitflags(event, ie_val->ie_type)) ? 1 : 0;
-	}
-
-	case AST_EVENT_IE_PLTYPE_STR:
-	{
-		const char *str;
-		uint32_t hash;
-
-		hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
-		if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
-			return 0;
-		}
-
-		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;
-	}
-
-	case AST_EVENT_IE_PLTYPE_RAW:
-	{
-		const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
-		uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
-
-		return (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
-	}
-
-	case AST_EVENT_IE_PLTYPE_EXISTS:
-	{
-		return ast_event_get_ie_raw(event, ie_val->ie_type) ? 1 : 0;
-	}
-
-	case AST_EVENT_IE_PLTYPE_UNKNOWN:
-		return 0;
-	}
-
-	return 0;
-}
-
-static int dump_cache_cb(void *obj, void *arg, int flags)
-{
-	const struct ast_event_ref *event_ref = obj;
-	const struct ast_event *event = event_ref->event;
-	const struct ast_event_sub *event_sub = arg;
-	struct ast_event_ie_val *ie_val = NULL;
-
-	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
-		if (!match_ie_val(event, ie_val, NULL)) {
-			break;
-		}
-	}
-
-	if (!ie_val) {
-		/* All parameters were matched on this cache entry, so dump it */
-		event_sub->cb(event, event_sub->userdata);
-	}
-
-	return 0;
-}
-
-/*! \brief Dump the event cache for the subscribed event type */
-void ast_event_dump_cache(const struct ast_event_sub *event_sub)
-{
-	ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
-			dump_cache_cb, (void *) event_sub);
-}
-
-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_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
-		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_BITFLAGS:
-			ast_event_append_ie_bitflags(&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)
-{
-	struct ast_event *event;
-	struct ast_event_sub *sub;
-	enum ast_event_type event_type = -1;
-	struct ast_event_ie_val *ie_val;
-
-	if (event_sub->type != AST_EVENT_SUB)
-		return;
-
-	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
-		if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
-			event_type = ie_val->payload.uint;
-			break;
-		}
-	}
-
-	if (event_type == -1)
-		return;
-
-	AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
-	AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
-		if (event_sub == sub) {
-			continue;
-		}
-
-		event = gen_sub_event(sub);
-
-		if (!event) {
-			continue;
-		}
-
-		event_sub->cb(event, event_sub->userdata);
-
-		ast_event_destroy(event);
-	}
-	AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
-}
-
-struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
-	ast_event_cb_t cb, void *userdata)
-{
-	struct ast_event_sub *sub;
-
-	if (type < 0 || type >= AST_EVENT_TOTAL) {
-		ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
-		return NULL;
-	}
-
-	if (!(sub = ast_calloc(1, sizeof(*sub)))) {
-		return NULL;
-	}
-
-	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 unsigned_int)
-{
-	struct ast_event_ie_val *ie_val;
-
-	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
-		return -1;
-	}
-
-	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
-		return -1;
-	}
-
-	ie_val->ie_type = ie_type;
-	ie_val->payload.uint = unsigned_int;
-	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_bitflags(struct ast_event_sub *sub,
-	enum ast_event_ie_type ie_type, uint32_t flags)
-{
-	struct ast_event_ie_val *ie_val;
-
-	if (ie_type <= 0 || ie_type >= AST_EVENT_IE_TOTAL) {
-		return -1;
-	}
-
-	if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
-		return -1;
-	}
-
-	ie_val->ie_type = ie_type;
-	ie_val->payload.uint = flags;
-	ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_BITFLAGS;
-
-	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_TOTAL) {
-		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_TOTAL) {
-		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;
-	}
-
-	ie_val->payload.hash = ast_str_hash(str);
-
-	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_TOTAL) {
-		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, sub->type,
-		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
-		struct ast_event *event;
-
-		event = gen_sub_event(sub);
-
-		if (event) {
-			ast_event_queue(event);
-		}
-	}
-
-	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,
-	const char *description, 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;
-	}
-
-	ast_copy_string(sub->description, description, sizeof(sub->description));
-
-	va_start(ap, userdata);
-	for (ie_type = va_arg(ap, enum ast_event_ie_type);
-		ie_type != AST_EVENT_IE_END;
-		ie_type = va_arg(ap, enum ast_event_ie_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 unsigned_int = va_arg(ap, uint32_t);
-			ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
-			break;
-		}
-		case AST_EVENT_IE_PLTYPE_BITFLAGS:
-		{
-			uint32_t unsigned_int = va_arg(ap, uint32_t);
-			ast_event_sub_append_ie_bitflags(sub, ie_type, unsigned_int);
-			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;
-}
-
-void ast_event_sub_destroy(struct ast_event_sub *sub)
-{
-	struct ast_event_ie_val *ie_val;
-
-	while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry))) {
-		ast_event_ie_val_destroy(ie_val);
-	}
-
-	ast_free(sub);
-}
-
-const char *ast_event_subscriber_get_description(struct ast_event_sub *sub)
-{
-	return sub ? sub->description : NULL;
-}
-
-struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
-{
-	struct ast_event *event;
-
-	AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
-	AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
-	AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
-
-	if (ast_event_check_subscriber(AST_EVENT_UNSUB,
-		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
-		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
-
-		event = ast_event_new(AST_EVENT_UNSUB,
-			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_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, sub->description,
-			AST_EVENT_IE_END);
-
-		if (event) {
-			ast_event_queue(event);
-		}
-	}
-
-	ast_event_sub_destroy(sub);
-
-	return NULL;
-}
-
-int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
-{
-	int res = 0;
-
-	iterator->event_len = ast_event_get_size(event);
-	iterator->event = event;
-	if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
-		iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
-	} else {
-		iterator->ie = NULL;
-		res = -1;
-	}
-
-	return res;
-}
-
-int ast_event_iterator_next(struct ast_event_iterator *iterator)
-{
-	iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
-	return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
-}
-
-enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
-{
-	return ntohs(iterator->ie->ie_type);
-}
-
-uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
-{
-	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
-}
-
-uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator)
-{
-	return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
-}
-
-const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
-{
-	const struct ast_event_ie_str_payload *str_payload;
-
-	str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
-
-	return str_payload ? str_payload->str : NULL;
-}
-
-void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
-{
-	return iterator->ie->ie_payload;
-}
-
-uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
-{
-	return ntohs(iterator->ie->ie_payload_len);
-}
-
-enum ast_event_type ast_event_get_type(const struct ast_event *event)
-{
-	return ntohs(event->type);
-}
-
-uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
-{
-	const uint32_t *ie_val;
-
-	ie_val = ast_event_get_ie_raw(event, ie_type);
-
-	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
-}
-
-uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type)
-{
-	const uint32_t *ie_val;
-
-	ie_val = ast_event_get_ie_raw(event, ie_type);
-
-	return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
-}
-

[... 1100 lines stripped ...]



More information about the asterisk-commits mailing list