Do a bit of code cleanup.
[asterisk/asterisk.git] / main / event.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007 - 2008, Digium, Inc.
5  *
6  * Russell Bryant <russell@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Internal generic event system
22  *
23  * \author Russell Bryant <russell@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "asterisk/_private.h"
31
32 #include "asterisk/event.h"
33 #include "asterisk/linkedlists.h"
34 #include "asterisk/dlinkedlists.h"
35 #include "asterisk/lock.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/unaligned.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/taskprocessor.h"
40 #include "asterisk/astobj2.h"
41
42 struct ast_taskprocessor *event_dispatcher;
43
44 /*!
45  * \brief An event information element
46  *
47  * \note The format of this structure is important.  Since these events may
48  *       be sent directly over a network, changing this structure will break
49  *       compatibility with older versions.  However, at this point, this code
50  *       has not made it into a release, so it is still fair game for change.
51  */
52 struct ast_event_ie {
53         enum ast_event_ie_type ie_type:16;
54         /*! Total length of the IE payload */
55         uint16_t ie_payload_len;
56         unsigned char ie_payload[0];
57 } __attribute__((packed));
58
59 /*!
60  * \brief The payload for a string information element
61  */
62 struct ast_event_ie_str_payload {
63         /*! \brief A hash calculated with ast_str_hash(), to speed up comparisons */
64         uint32_t hash;
65         /*! \brief The actual string, null terminated */
66         char str[1];
67 } __attribute__((packed));
68
69 /*!
70  * \brief An event
71  *
72  * An ast_event consists of an event header (this structure), and zero or
73  * more information elements defined by ast_event_ie.
74  *
75  * \note The format of this structure is important.  Since these events may
76  *       be sent directly over a network, changing this structure will break
77  *       compatibility with older versions.  However, at this point, this code
78  *       has not made it into a release, so it is still fair game for change.
79  */
80 struct ast_event {
81         /*! Event type */
82         enum ast_event_type type:16;
83         /*! Total length of the event */
84         uint16_t event_len:16;
85         /*! The data payload of the event, made up of information elements */
86         unsigned char payload[0];
87 } __attribute__((packed));
88
89
90 /*!
91  * \brief A holder for an event
92  *
93  * \details This struct used to have more of a purpose than it does now.
94  * It is used to hold events in the event cache.  It can be completely removed
95  * if one of these two things is done:
96  *  - ast_event gets changed such that it never has to be realloc()d
97  *  - astobj2 is updated so that you can realloc() an astobj2 object
98  */
99 struct ast_event_ref {
100         struct ast_event *event;
101 };
102
103 struct ast_event_ie_val {
104         AST_LIST_ENTRY(ast_event_ie_val) entry;
105         enum ast_event_ie_type ie_type;
106         enum ast_event_ie_pltype ie_pltype;
107         union {
108                 uint32_t uint;
109                 struct {
110                         uint32_t hash;
111                         const char *str;
112                 };
113                 void *raw;
114         } payload;
115         size_t raw_datalen;
116 };
117
118 /*! \brief Event subscription */
119 struct ast_event_sub {
120         enum ast_event_type type;
121         ast_event_cb_t cb;
122         void *userdata;
123         uint32_t uniqueid;
124         AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
125         AST_RWDLLIST_ENTRY(ast_event_sub) entry;
126 };
127
128 static uint32_t sub_uniqueid;
129
130 /*! \brief Event subscriptions
131  * The event subscribers are indexed by which event they are subscribed to */
132 static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
133
134 static int ast_event_cmp(void *obj, void *arg, int flags);
135 static int ast_event_hash_mwi(const void *obj, const int flags);
136 static int ast_event_hash_devstate(const void *obj, const int flags);
137 static int ast_event_hash_devstate_change(const void *obj, const int flags);
138
139 #ifdef LOW_MEMORY
140 #define NUM_CACHE_BUCKETS 17
141 #else
142 #define NUM_CACHE_BUCKETS 563
143 #endif
144
145 #define MAX_CACHE_ARGS 8
146
147 /*!
148  * \brief Event types that are kept in the cache.
149  */
150 static struct {
151         /*! 
152          * \brief Container of cached events
153          *
154          * \details This gets allocated in ast_event_init() when Asterisk starts
155          * for the event types declared as using the cache.
156          */
157         struct ao2_container *container;
158         /*! \brief Event type specific hash function */
159         ao2_hash_fn *hash_fn;
160         /*!
161          * \brief Information Elements used for caching
162          *
163          * \details This array is the set of information elements that will be unique
164          * among all events in the cache for this event type.  When a new event gets
165          * cached, a previous event with the same values for these information elements
166          * will be replaced.
167          */
168         enum ast_event_ie_type cache_args[MAX_CACHE_ARGS];
169 } ast_event_cache[AST_EVENT_TOTAL] = {
170         [AST_EVENT_MWI] = {
171                 .hash_fn = ast_event_hash_mwi,
172                 .cache_args = { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_CONTEXT },
173         },
174         [AST_EVENT_DEVICE_STATE] = {
175                 .hash_fn = ast_event_hash_devstate,
176                 .cache_args = { AST_EVENT_IE_DEVICE, },
177         },
178         [AST_EVENT_DEVICE_STATE_CHANGE] = {
179                 .hash_fn = ast_event_hash_devstate_change,
180                 .cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
181         },
182 };
183
184 /*!
185  * The index of each entry _must_ match the event type number!
186  */
187 static struct event_name {
188         enum ast_event_type type;
189         const char *name;
190 } event_names[] = {
191         { 0, "" },
192         { AST_EVENT_CUSTOM,              "Custom" },
193         { AST_EVENT_MWI,                 "MWI" },
194         { AST_EVENT_SUB,                 "Subscription" },
195         { AST_EVENT_UNSUB,               "Unsubscription" },
196         { AST_EVENT_DEVICE_STATE,        "DeviceState" },
197         { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
198 };
199
200 /*!
201  * The index of each entry _must_ match the event ie number!
202  */
203 static struct ie_map {
204         enum ast_event_ie_type ie_type;
205         enum ast_event_ie_pltype ie_pltype;
206         const char *name;
207 } ie_maps[] = {
208         { 0, 0, "" },
209         { AST_EVENT_IE_NEWMSGS,   AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
210         { AST_EVENT_IE_OLDMSGS,   AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
211         { AST_EVENT_IE_MAILBOX,   AST_EVENT_IE_PLTYPE_STR,  "Mailbox" },
212         { AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
213         { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
214         { AST_EVENT_IE_EXISTS,    AST_EVENT_IE_PLTYPE_UINT, "Exists" },
215         { AST_EVENT_IE_DEVICE,    AST_EVENT_IE_PLTYPE_STR,  "Device" },
216         { AST_EVENT_IE_STATE,     AST_EVENT_IE_PLTYPE_UINT, "State" },
217         { AST_EVENT_IE_CONTEXT,   AST_EVENT_IE_PLTYPE_STR,  "Context" },
218         { AST_EVENT_IE_EID,       AST_EVENT_IE_PLTYPE_RAW,  "EntityID" },
219 };
220
221 const char *ast_event_get_type_name(const struct ast_event *event)
222 {
223         enum ast_event_type type;
224
225         type = ast_event_get_type(event);
226
227         if (type >= AST_EVENT_TOTAL || type < 0) {
228                 ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
229                 return "";
230         }
231
232         return event_names[type].name;
233 }
234
235 int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
236 {
237         int i;
238
239         for (i = 0; i < ARRAY_LEN(event_names); i++) {
240                 if (strcasecmp(event_names[i].name, str))
241                         continue;
242
243                 *event_type = event_names[i].type;
244                 return 0;
245         }
246
247         return -1;
248 }
249
250 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
251 {
252         if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
253                 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
254                 return "";
255         }
256
257         if (ie_maps[ie_type].ie_type != ie_type) {
258                 ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
259                 return "";
260         }
261
262         return ie_maps[ie_type].name;
263 }
264
265 enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
266 {
267         if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
268                 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
269                 return AST_EVENT_IE_PLTYPE_UNKNOWN;
270         }
271
272         if (ie_maps[ie_type].ie_type != ie_type) {
273                 ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
274                 return AST_EVENT_IE_PLTYPE_UNKNOWN;
275         }
276
277         return ie_maps[ie_type].ie_pltype;
278 }
279
280 int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
281 {
282         int i;
283
284         for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
285                 if (strcasecmp(ie_maps[i].name, str))
286                         continue;
287
288                 *ie_type = ie_maps[i].ie_type;
289                 return 0;
290         }
291
292         return -1;
293 }
294
295 size_t ast_event_get_size(const struct ast_event *event)
296 {
297         size_t res;
298
299         res = ntohs(event->event_len);
300
301         return res;
302 }
303
304 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
305 {
306         switch (ie_val->ie_pltype) {
307         case AST_EVENT_IE_PLTYPE_STR:
308                 ast_free((char *) ie_val->payload.str);
309                 break;
310         case AST_EVENT_IE_PLTYPE_RAW:
311                 ast_free(ie_val->payload.raw);
312                 break;
313         case AST_EVENT_IE_PLTYPE_UINT:
314         case AST_EVENT_IE_PLTYPE_EXISTS:
315         case AST_EVENT_IE_PLTYPE_UNKNOWN:
316                 break;
317         }
318
319         ast_free(ie_val);
320 }
321
322 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
323 {
324         va_list ap;
325         enum ast_event_ie_type ie_type;
326         enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
327         struct ast_event_ie_val *ie_val, *sub_ie_val;
328         struct ast_event_sub *sub;
329         AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
330
331         if (type >= AST_EVENT_TOTAL) {
332                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
333                 return res;
334         }
335
336         va_start(ap, type);
337         for (ie_type = va_arg(ap, enum ast_event_type);
338                 ie_type != AST_EVENT_IE_END;
339                 ie_type = va_arg(ap, enum ast_event_type))
340         {
341                 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
342                 int insert = 1;
343                 memset(ie_value, 0, sizeof(*ie_value));
344                 ie_value->ie_type = ie_type;
345                 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
346                 switch (ie_value->ie_pltype) {
347                 case AST_EVENT_IE_PLTYPE_UINT:
348                         ie_value->payload.uint = va_arg(ap, uint32_t);
349                         break;
350                 case AST_EVENT_IE_PLTYPE_STR:
351                         ie_value->payload.str = va_arg(ap, const char *);
352                         break;
353                 case AST_EVENT_IE_PLTYPE_RAW:
354                 {
355                         void *data = va_arg(ap, void *);
356                         size_t datalen = va_arg(ap, size_t);
357                         ie_value->payload.raw = alloca(datalen);
358                         memcpy(ie_value->payload.raw, data, datalen);
359                         ie_value->raw_datalen = datalen;
360                         break;
361                 }
362                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
363                         insert = 0;
364                 case AST_EVENT_IE_PLTYPE_EXISTS:
365                         break;
366                 }
367
368                 if (insert) {
369                         AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
370                 }
371         }
372         va_end(ap);
373
374         AST_RWDLLIST_RDLOCK(&ast_event_subs[type]);
375         AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
376                 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
377                         int break_out = 0;
378
379                         AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
380                                 if (sub_ie_val->ie_type == ie_val->ie_type) {
381                                         break;
382                                 }
383                         }
384
385                         if (!sub_ie_val) {
386                                 /* This subscriber doesn't care about this IE, so consider
387                                  * it matched. */
388                                 continue;
389                         }
390
391                         switch (ie_val->ie_pltype) {
392                         case AST_EVENT_IE_PLTYPE_UINT:
393                                 break_out = (ie_val->payload.uint != sub_ie_val->payload.uint);
394                                 break;
395                         case AST_EVENT_IE_PLTYPE_STR:
396                                 break_out = strcmp(ie_val->payload.str, sub_ie_val->payload.str);
397                                 break;
398                         case AST_EVENT_IE_PLTYPE_RAW:
399                                 break_out = memcmp(ie_val->payload.raw,
400                                                 sub_ie_val->payload.raw, ie_val->raw_datalen);
401                                 break;
402                         case AST_EVENT_IE_PLTYPE_EXISTS:
403                                 /* The subscriber doesn't actually care what the value is */
404                                 break_out = 1;
405                                 break;
406                         case AST_EVENT_IE_PLTYPE_UNKNOWN:
407                                 break;
408                         }
409
410                         if (break_out) {
411                                 break;
412                         }
413                 }
414
415                 if (!ie_val) {
416                         /* Everything matched */
417                         break;
418                 }
419         }
420         AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
421
422         if (sub) {
423                 /* All parameters were matched */
424                 return AST_EVENT_SUB_EXISTS;
425         }
426
427         AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
428         if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL])) {
429                 res = AST_EVENT_SUB_EXISTS;
430         }
431         AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
432
433         return res;
434 }
435
436 static int match_ie_val(const struct ast_event *event,
437                 const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
438 {
439         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
440                 uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
441                 if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
442                         return 1;
443                 return 0;
444         }
445
446         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
447                 const char *str;
448                 uint32_t hash;
449
450                 hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
451                 if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
452                         return 0;
453                 }
454
455                 str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
456                 if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
457                         return 1;
458                 }
459
460                 return 0;
461         }
462
463         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
464                 const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
465                 if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
466                         return 1;
467                 return 0;
468         }
469
470         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
471                 if (ast_event_get_ie_raw(event, ie_val->ie_type))
472                         return 1;
473                 return 0;
474         }
475
476         return 0;
477 }
478
479 static int dump_cache_cb(void *obj, void *arg, int flags)
480 {
481         const struct ast_event_ref *event_ref = obj;
482         const struct ast_event *event = event_ref->event;
483         const struct ast_event_sub *event_sub = arg;
484         struct ast_event_ie_val *ie_val = NULL;
485
486         AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
487                 if (!match_ie_val(event, ie_val, NULL)) {
488                         break;
489                 }
490         }
491
492         if (!ie_val) {
493                 /* All parameters were matched on this cache entry, so dump it */
494                 event_sub->cb(event, event_sub->userdata);
495         }
496
497         return 0;
498 }
499
500 /*! \brief Dump the event cache for the subscribed event type */
501 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
502 {
503         ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
504                         dump_cache_cb, (void *) event_sub);
505 }
506
507 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
508 {
509         struct ast_event_ie_val *ie_val;
510         struct ast_event *event;
511
512         event = ast_event_new(AST_EVENT_SUB,
513                 AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
514                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
515                 AST_EVENT_IE_END);
516
517         if (!event)
518                 return NULL;
519
520         AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
521                 switch (ie_val->ie_pltype) {
522                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
523                         break;
524                 case AST_EVENT_IE_PLTYPE_EXISTS:
525                         ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
526                         break;
527                 case AST_EVENT_IE_PLTYPE_UINT:
528                         ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
529                         break;
530                 case AST_EVENT_IE_PLTYPE_STR:
531                         ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
532                         break;
533                 case AST_EVENT_IE_PLTYPE_RAW:
534                         ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
535                         break;
536                 }
537                 if (!event)
538                         break;
539         }
540
541         return event;
542 }
543
544 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
545 void ast_event_report_subs(const struct ast_event_sub *event_sub)
546 {
547         struct ast_event *event;
548         struct ast_event_sub *sub;
549         enum ast_event_type event_type = -1;
550         struct ast_event_ie_val *ie_val;
551
552         if (event_sub->type != AST_EVENT_SUB)
553                 return;
554
555         AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
556                 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
557                         event_type = ie_val->payload.uint;
558                         break;
559                 }
560         }
561
562         if (event_type == -1)
563                 return;
564
565         AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
566         AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
567                 if (event_sub == sub) {
568                         continue;
569                 }
570
571                 event = gen_sub_event(sub);
572
573                 if (!event) {
574                         continue;
575                 }
576
577                 event_sub->cb(event, event_sub->userdata);
578
579                 ast_event_destroy(event);
580         }
581         AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
582 }
583
584 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
585         ast_event_cb_t cb, void *userdata)
586 {
587         struct ast_event_sub *sub;
588
589         if (type < 0 || type >= AST_EVENT_TOTAL) {
590                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
591                 return NULL;
592         }
593
594         if (!(sub = ast_calloc(1, sizeof(*sub)))) {
595                 return NULL;
596         }
597
598         sub->type = type;
599         sub->cb = cb;
600         sub->userdata = userdata;
601         sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
602
603         return sub;
604 }
605
606 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
607         enum ast_event_ie_type ie_type, uint32_t unsigned_int)
608 {
609         struct ast_event_ie_val *ie_val;
610
611         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
612                 return -1;
613         }
614
615         if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
616                 return -1;
617         }
618
619         ie_val->ie_type = ie_type;
620         ie_val->payload.uint = unsigned_int;
621         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
622
623         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
624
625         return 0;
626 }
627
628 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
629         enum ast_event_ie_type ie_type)
630 {
631         struct ast_event_ie_val *ie_val;
632
633         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
634                 return -1;
635         }
636
637         if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
638                 return -1;
639         }
640
641         ie_val->ie_type = ie_type;
642         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
643
644         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
645
646         return 0;
647 }
648
649 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
650         enum ast_event_ie_type ie_type, const char *str)
651 {
652         struct ast_event_ie_val *ie_val;
653
654         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
655                 return -1;
656         }
657
658         if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
659                 return -1;
660         }
661
662         ie_val->ie_type = ie_type;
663         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
664
665         if (!(ie_val->payload.str = ast_strdup(str))) {
666                 ast_free(ie_val);
667                 return -1;
668         }
669
670         ie_val->payload.hash = ast_str_hash(str);
671
672         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
673
674         return 0;
675 }
676
677 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
678         enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
679 {
680         struct ast_event_ie_val *ie_val;
681
682         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
683                 return -1;
684         }
685
686         if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
687                 return -1;
688         }
689
690         ie_val->ie_type = ie_type;
691         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
692         ie_val->raw_datalen = raw_datalen;
693
694         if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
695                 ast_free(ie_val);
696                 return -1;
697         }
698
699         memcpy(ie_val->payload.raw, data, raw_datalen);
700
701         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
702
703         return 0;
704 }
705
706 int ast_event_sub_activate(struct ast_event_sub *sub)
707 {
708         if (ast_event_check_subscriber(AST_EVENT_SUB,
709                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
710                 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
711                 struct ast_event *event;
712
713                 event = gen_sub_event(sub);
714
715                 if (event) {
716                         ast_event_queue(event);
717                 }
718         }
719
720         AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
721         AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
722         AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
723
724         return 0;
725 }
726
727 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
728         void *userdata, ...)
729 {
730         va_list ap;
731         enum ast_event_ie_type ie_type;
732         struct ast_event_sub *sub;
733
734         if (!(sub = ast_event_subscribe_new(type, cb, userdata))) {
735                 return NULL;
736         }
737
738         va_start(ap, userdata);
739         for (ie_type = va_arg(ap, enum ast_event_type);
740                 ie_type != AST_EVENT_IE_END;
741                 ie_type = va_arg(ap, enum ast_event_type))
742         {
743                 enum ast_event_ie_pltype ie_pltype;
744
745                 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
746
747                 switch (ie_pltype) {
748                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
749                         break;
750                 case AST_EVENT_IE_PLTYPE_UINT:
751                 {
752                         uint32_t unsigned_int = va_arg(ap, uint32_t);
753                         ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
754                         break;
755                 }
756                 case AST_EVENT_IE_PLTYPE_STR:
757                 {
758                         const char *str = va_arg(ap, const char *);
759                         ast_event_sub_append_ie_str(sub, ie_type, str);
760                         break;
761                 }
762                 case AST_EVENT_IE_PLTYPE_RAW:
763                 {
764                         void *data = va_arg(ap, void *);
765                         size_t data_len = va_arg(ap, size_t);
766                         ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
767                         break;
768                 }
769                 case AST_EVENT_IE_PLTYPE_EXISTS:
770                         ast_event_sub_append_ie_exists(sub, ie_type);
771                         break;
772                 }
773         }
774         va_end(ap);
775
776         ast_event_sub_activate(sub);
777
778         return sub;
779 }
780
781 void ast_event_sub_destroy(struct ast_event_sub *sub)
782 {
783         struct ast_event_ie_val *ie_val;
784
785         while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry))) {
786                 ast_event_ie_val_destroy(ie_val);
787         }
788
789         ast_free(sub);
790 }
791
792 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
793 {
794         struct ast_event *event;
795
796         AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
797         AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
798         AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
799
800         if (ast_event_check_subscriber(AST_EVENT_UNSUB,
801                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
802                 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
803
804                 event = ast_event_new(AST_EVENT_UNSUB,
805                         AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
806                         AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
807                         AST_EVENT_IE_END);
808
809                 if (event) {
810                         ast_event_queue(event);
811                 }
812         }
813
814         ast_event_sub_destroy(sub);
815
816         return NULL;
817 }
818
819 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
820 {
821         iterator->event_len = ntohs(event->event_len);
822         iterator->event = event;
823         iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
824 }
825
826 int ast_event_iterator_next(struct ast_event_iterator *iterator)
827 {
828         iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
829         return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
830 }
831
832 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
833 {
834         return ntohs(iterator->ie->ie_type);
835 }
836
837 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
838 {
839         return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
840 }
841
842 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
843 {
844         const struct ast_event_ie_str_payload *str_payload;
845
846         str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
847
848         return str_payload->str;
849 }
850
851 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
852 {
853         return iterator->ie->ie_payload;
854 }
855
856 enum ast_event_type ast_event_get_type(const struct ast_event *event)
857 {
858         return ntohs(event->type);
859 }
860
861 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
862 {
863         const uint32_t *ie_val;
864
865         ie_val = ast_event_get_ie_raw(event, ie_type);
866
867         return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
868 }
869
870 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
871 {
872         const struct ast_event_ie_str_payload *str_payload;
873
874         str_payload = ast_event_get_ie_raw(event, ie_type);
875
876         return str_payload->hash;
877 }
878
879 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
880 {
881         const struct ast_event_ie_str_payload *str_payload;
882
883         str_payload = ast_event_get_ie_raw(event, ie_type);
884
885         return str_payload->str;
886 }
887
888 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
889 {
890         struct ast_event_iterator iterator;
891         int res = 0;
892
893         for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
894                 if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
895                         return ast_event_iterator_get_ie_raw(&iterator);
896                 }
897         }
898
899         return NULL;
900 }
901
902 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
903         const char *str)
904 {
905         struct ast_event_ie_str_payload *str_payload;
906         size_t payload_len;
907
908         payload_len = sizeof(*str_payload) + strlen(str);
909         str_payload = alloca(payload_len);
910
911         strcpy(str_payload->str, str);
912         str_payload->hash = ast_str_hash(str);
913
914         return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
915 }
916
917 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
918         uint32_t data)
919 {
920         data = htonl(data);
921         return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
922 }
923
924 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
925         const void *data, size_t data_len)
926 {
927         struct ast_event_ie *ie;
928         unsigned int extra_len;
929         uint16_t event_len;
930
931         event_len = ntohs((*event)->event_len);
932         extra_len = sizeof(*ie) + data_len;
933
934         if (!(*event = ast_realloc(*event, event_len + extra_len))) {
935                 return -1;
936         }
937
938         ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
939         ie->ie_type = htons(ie_type);
940         ie->ie_payload_len = htons(data_len);
941         memcpy(ie->ie_payload, data, data_len);
942
943         (*event)->event_len = htons(event_len + extra_len);
944
945         return 0;
946 }
947
948 struct ast_event *ast_event_new(enum ast_event_type type, ...)
949 {
950         va_list ap;
951         struct ast_event *event;
952         enum ast_event_type ie_type;
953         struct ast_event_ie_val *ie_val;
954         AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
955
956         /* Invalid type */
957         if (type >= AST_EVENT_TOTAL) {
958                 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
959                         "type '%d'!\n", type);
960                 return NULL;
961         }
962
963         va_start(ap, type);
964         for (ie_type = va_arg(ap, enum ast_event_type);
965                 ie_type != AST_EVENT_IE_END;
966                 ie_type = va_arg(ap, enum ast_event_type))
967         {
968                 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
969                 int insert = 1;
970                 memset(ie_value, 0, sizeof(*ie_value));
971                 ie_value->ie_type = ie_type;
972                 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
973                 switch (ie_value->ie_pltype) {
974                 case AST_EVENT_IE_PLTYPE_UINT:
975                         ie_value->payload.uint = va_arg(ap, uint32_t);
976                         break;
977                 case AST_EVENT_IE_PLTYPE_STR:
978                         ie_value->payload.str = va_arg(ap, const char *);
979                         break;
980                 case AST_EVENT_IE_PLTYPE_RAW:
981                 {
982                         void *data = va_arg(ap, void *);
983                         size_t datalen = va_arg(ap, size_t);
984                         ie_value->payload.raw = alloca(datalen);
985                         memcpy(ie_value->payload.raw, data, datalen);
986                         ie_value->raw_datalen = datalen;
987                         break;
988                 }
989                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
990                         insert = 0;
991                         break;
992                 case AST_EVENT_IE_PLTYPE_EXISTS:
993                         break;
994                 }
995
996                 if (insert) {
997                         AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
998                 }
999         }
1000         va_end(ap);
1001
1002         if (!(event = ast_calloc(1, sizeof(*event)))) {
1003                 return NULL;
1004         }
1005
1006         event->type = htons(type);
1007         event->event_len = htons(sizeof(*event));
1008
1009         AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
1010                 switch (ie_val->ie_pltype) {
1011                 case AST_EVENT_IE_PLTYPE_STR:
1012                         ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
1013                         break;
1014                 case AST_EVENT_IE_PLTYPE_UINT:
1015                         ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
1016                         break;
1017                 case AST_EVENT_IE_PLTYPE_RAW:
1018                         ast_event_append_ie_raw(&event, ie_val->ie_type,
1019                                         ie_val->payload.raw, ie_val->raw_datalen);
1020                         break;
1021                 case AST_EVENT_IE_PLTYPE_EXISTS:
1022                         ast_log(LOG_WARNING, "PLTYPE_EXISTS unsupported in event_new\n");
1023                         break;
1024                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
1025                         ast_log(LOG_WARNING, "PLTYPE_UNKNOWN passed as an IE type "
1026                                         "for a new event\n");
1027                         break;
1028                 }
1029
1030                 if (!event) {
1031                         break;
1032                 }
1033         }
1034
1035         if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
1036                 /* If the event is originating on this server, add the server's
1037                  * entity ID to the event. */
1038                 ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
1039         }
1040
1041         return event;
1042 }
1043
1044 void ast_event_destroy(struct ast_event *event)
1045 {
1046         ast_free(event);
1047 }
1048
1049 static void ast_event_ref_destroy(void *obj)
1050 {
1051         struct ast_event_ref *event_ref = obj;
1052
1053         ast_event_destroy(event_ref->event);
1054 }
1055
1056 static struct ast_event *ast_event_dup(const struct ast_event *event)
1057 {
1058         struct ast_event *dup_event;
1059         uint16_t event_len;
1060
1061         event_len = ast_event_get_size(event);
1062
1063         if (!(dup_event = ast_calloc(1, event_len))) {
1064                 return NULL;
1065         }
1066
1067         memcpy(dup_event, event, event_len);
1068
1069         return dup_event;
1070 }
1071
1072 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
1073 {
1074         va_list ap;
1075         enum ast_event_ie_type ie_type;
1076         struct ast_event *dup_event = NULL;
1077         struct ast_event_ref *cached_event_ref;
1078         struct ast_event *cache_arg_event;
1079         struct ast_event_ref tmp_event_ref = {
1080                 .event = NULL,
1081         };
1082         struct ao2_container *container = NULL;
1083
1084         if (type >= AST_EVENT_TOTAL) {
1085                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
1086                 return NULL;
1087         }
1088
1089         if (!(container = ast_event_cache[type].container)) {
1090                 ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
1091                 return NULL;
1092         }
1093
1094         if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
1095                 return NULL;
1096         }
1097
1098         va_start(ap, type);
1099         for (ie_type = va_arg(ap, enum ast_event_type);
1100                 ie_type != AST_EVENT_IE_END;
1101                 ie_type = va_arg(ap, enum ast_event_type))
1102         {
1103                 enum ast_event_ie_pltype ie_pltype;
1104
1105                 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
1106
1107                 switch (ie_pltype) {
1108                 case AST_EVENT_IE_PLTYPE_UINT:
1109                         ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
1110                         break;
1111                 case AST_EVENT_IE_PLTYPE_STR:
1112                         ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
1113                         break;
1114                 case AST_EVENT_IE_PLTYPE_RAW:
1115                 {
1116                         void *data = va_arg(ap, void *);
1117                         size_t datalen = va_arg(ap, size_t);
1118                         ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
1119                 }
1120                 case AST_EVENT_IE_PLTYPE_EXISTS:
1121                         ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
1122                         break;
1123                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
1124                         break;
1125                 }
1126         }
1127         va_end(ap);
1128
1129         tmp_event_ref.event = cache_arg_event;
1130
1131         cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
1132
1133         ast_event_destroy(cache_arg_event);
1134         cache_arg_event = NULL;
1135
1136         if (cached_event_ref) {
1137                 dup_event = ast_event_dup(cached_event_ref->event);
1138                 ao2_ref(cached_event_ref, -1);
1139                 cached_event_ref = NULL;
1140         }
1141
1142         return dup_event;
1143 }
1144
1145 static struct ast_event_ref *alloc_event_ref(void)
1146 {
1147         return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
1148 }
1149
1150 /*! \brief Duplicate an event and add it to the cache
1151  * \note This assumes this index in to the cache is locked */
1152 static int attribute_unused ast_event_dup_and_cache(const struct ast_event *event)
1153 {
1154         struct ast_event *dup_event;
1155         struct ast_event_ref *event_ref;
1156
1157         if (!(dup_event = ast_event_dup(event))) {
1158                 return -1;
1159         }
1160
1161         if (!(event_ref = alloc_event_ref())) {
1162                 ast_event_destroy(dup_event);
1163                 return -1;
1164         }
1165
1166         event_ref->event = dup_event;
1167
1168         ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
1169
1170         ao2_ref(event_ref, -1);
1171
1172         return 0;
1173 }
1174
1175 int ast_event_queue_and_cache(struct ast_event *event)
1176 {
1177         struct ao2_container *container;
1178         struct ast_event_ref tmp_event_ref = {
1179                 .event = event,
1180         };
1181
1182         if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
1183                 ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
1184                 goto queue_event;
1185         }
1186
1187         /* Remove matches from the cache */
1188         ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
1189                         ast_event_cmp, &tmp_event_ref);
1190
1191 queue_event:
1192         return ast_event_queue(event);
1193 }
1194
1195 static int handle_event(void *data)
1196 {
1197         struct ast_event_ref *event_ref = data;
1198         struct ast_event_sub *sub;
1199         uint16_t host_event_type;
1200
1201         host_event_type = ntohs(event_ref->event->type);
1202
1203         /* Subscribers to this specific event first */
1204         AST_RWDLLIST_RDLOCK(&ast_event_subs[host_event_type]);
1205         AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
1206                 struct ast_event_ie_val *ie_val;
1207                 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
1208                         if (!match_ie_val(event_ref->event, ie_val, NULL)) {
1209                                 break;
1210                         }
1211                 }
1212                 if (ie_val) {
1213                         continue;
1214                 }
1215                 sub->cb(event_ref->event, sub->userdata);
1216         }
1217         AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]);
1218
1219         /* Now to subscribers to all event types */
1220         AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
1221         AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry) {
1222                 sub->cb(event_ref->event, sub->userdata);
1223         }
1224         AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
1225
1226         ao2_ref(event_ref, -1);
1227
1228         return 0;
1229 }
1230
1231 int ast_event_queue(struct ast_event *event)
1232 {
1233         struct ast_event_ref *event_ref;
1234         uint16_t host_event_type;
1235
1236         host_event_type = ntohs(event->type);
1237
1238         /* Invalid type */
1239         if (host_event_type >= AST_EVENT_TOTAL) {
1240                 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
1241                         "type '%d'!\n", host_event_type);
1242                 return -1;
1243         }
1244
1245         /* If nobody has subscribed to this event type, throw it away now */
1246         if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
1247                         == AST_EVENT_SUB_NONE) {
1248                 ast_event_destroy(event);
1249                 return 0;
1250         }
1251
1252         if (!(event_ref = alloc_event_ref())) {
1253                 return -1;
1254         }
1255
1256         event_ref->event = event;
1257
1258         return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
1259 }
1260
1261 static int ast_event_hash_mwi(const void *obj, const int flags)
1262 {
1263         const struct ast_event *event = obj;
1264         const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
1265         const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
1266
1267         return ast_str_hash_add(context, ast_str_hash(mailbox));
1268 }
1269
1270 /*!
1271  * \internal
1272  * \brief Hash function for AST_EVENT_DEVICE_STATE
1273  *
1274  * \param[in] obj an ast_event
1275  * \param[in] flags unused
1276  *
1277  * \return hash value
1278  */
1279 static int ast_event_hash_devstate(const void *obj, const int flags)
1280 {
1281         const struct ast_event *event = obj;
1282
1283         return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
1284 }
1285
1286 /*!
1287  * \internal
1288  * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
1289  *
1290  * \param[in] obj an ast_event
1291  * \param[in] flags unused
1292  *
1293  * \return hash value
1294  */
1295 static int ast_event_hash_devstate_change(const void *obj, const int flags)
1296 {
1297         const struct ast_event *event = obj;
1298
1299         return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
1300 }
1301
1302 static int ast_event_hash(const void *obj, const int flags)
1303 {
1304         const struct ast_event_ref *event_ref;
1305         const struct ast_event *event;
1306         ao2_hash_fn *hash_fn;
1307
1308         event_ref = obj;
1309         event = event_ref->event;
1310
1311         if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
1312                 return 0;
1313         }
1314
1315         return hash_fn(event, flags);
1316 }
1317
1318 /*!
1319  * \internal
1320  * \brief Compare two events
1321  *
1322  * \param[in] obj the first event, as an ast_event_ref
1323  * \param[in] arg the second event, as an ast_event_ref
1324  * \param[in] flags unused
1325  *
1326  * \pre Both events must be the same type.
1327  * \pre The event type must be declared as a cached event type in ast_event_cache
1328  *
1329  * \details This function takes two events, and determines if they are considered
1330  * equivalent.  The values of information elements specified in the cache arguments
1331  * for the event type are used to determine if the events are equivalent.
1332  *
1333  * \retval 0 No match
1334  * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
1335  */
1336 static int ast_event_cmp(void *obj, void *arg, int flags)
1337 {
1338         struct ast_event_ref *event_ref, *event_ref2;
1339         struct ast_event *event, *event2;
1340         int res = CMP_MATCH;
1341         int i;
1342         enum ast_event_ie_type *cache_args;
1343
1344         event_ref = obj;
1345         event = event_ref->event;
1346
1347         event_ref2 = arg;
1348         event2 = event_ref2->event;
1349
1350         cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
1351
1352         for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
1353                 struct ast_event_ie_val ie_val = {
1354                         .ie_type = cache_args[i],
1355                 };
1356
1357                 if (!match_ie_val(event, &ie_val, event2)) {
1358                         res = 0;
1359                         break;
1360                 }
1361         }
1362
1363         return res;
1364 }
1365
1366 int ast_event_init(void)
1367 {
1368         int i;
1369
1370         for (i = 0; i < AST_EVENT_TOTAL; i++) {
1371                 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
1372         }
1373
1374         for (i = 0; i < AST_EVENT_TOTAL; i++) {
1375                 if (!ast_event_cache[i].hash_fn) {
1376                         /* This event type is not cached. */
1377                         continue;
1378                 }
1379
1380                 if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
1381                                 ast_event_hash, ast_event_cmp))) {
1382                         return -1;
1383                 }
1384         }
1385
1386         if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
1387                 return -1;
1388         }
1389
1390         return 0;
1391 }