Change g_eid to ast_eid_default.
[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                 memset(ie_value, 0, sizeof(*ie_value));
343                 ie_value->ie_type = ie_type;
344                 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
345                 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
346                         ie_value->payload.uint = va_arg(ap, uint32_t);
347                 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
348                         ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
349                 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
350                         void *data = va_arg(ap, void *);
351                         size_t datalen = va_arg(ap, size_t);
352                         ie_value->payload.raw = alloca(datalen);
353                         memcpy(ie_value->payload.raw, data, datalen);
354                         ie_value->raw_datalen = datalen;
355                 }
356                 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
357         }
358         va_end(ap);
359
360         AST_RWDLLIST_RDLOCK(&ast_event_subs[type]);
361         AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
362                 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
363                         AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
364                                 if (sub_ie_val->ie_type == ie_val->ie_type)
365                                         break;
366                         }
367                         if (!sub_ie_val) {
368                                 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
369                                         break;
370                                 continue;
371                         }
372                         /* The subscriber doesn't actually care what the value is */
373                         if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
374                                 continue;
375                         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
376                                 ie_val->payload.uint != sub_ie_val->payload.uint)
377                                 break;
378                         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
379                                 strcmp(ie_val->payload.str, sub_ie_val->payload.str))
380                                 break;
381                         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
382                                 memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
383                                 break;
384                 }
385                 if (!ie_val)
386                         break;
387         }
388         AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
389
390         if (sub) /* All parameters were matched */
391                 return AST_EVENT_SUB_EXISTS;
392
393         AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
394         if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
395                 res = AST_EVENT_SUB_EXISTS;
396         AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
397
398         return res;
399 }
400
401 static int match_ie_val(const struct ast_event *event,
402                 const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
403 {
404         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
405                 uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
406                 if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
407                         return 1;
408                 return 0;
409         }
410
411         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
412                 const char *str;
413                 uint32_t hash;
414
415                 hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
416                 if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
417                         return 0;
418                 }
419
420                 str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
421                 if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
422                         return 1;
423                 }
424
425                 return 0;
426         }
427
428         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
429                 const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
430                 if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
431                         return 1;
432                 return 0;
433         }
434
435         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
436                 if (ast_event_get_ie_raw(event, ie_val->ie_type))
437                         return 1;
438                 return 0;
439         }
440
441         return 0;
442 }
443
444 static int dump_cache_cb(void *obj, void *arg, int flags)
445 {
446         const struct ast_event_ref *event_ref = obj;
447         const struct ast_event *event = event_ref->event;
448         const struct ast_event_sub *event_sub = arg;
449         struct ast_event_ie_val *ie_val = NULL;
450
451         AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
452                 if (!match_ie_val(event, ie_val, NULL)) {
453                         break;
454                 }
455         }
456
457         if (!ie_val) {
458                 /* All parameters were matched on this cache entry, so dump it */
459                 event_sub->cb(event, event_sub->userdata);
460         }
461
462         return 0;
463 }
464
465 /*! \brief Dump the event cache for the subscribed event type */
466 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
467 {
468         ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
469                         dump_cache_cb, (void *) event_sub);
470 }
471
472 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
473 {
474         struct ast_event_ie_val *ie_val;
475         struct ast_event *event;
476
477         event = ast_event_new(AST_EVENT_SUB,
478                 AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
479                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
480                 AST_EVENT_IE_END);
481
482         if (!event)
483                 return NULL;
484
485         AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
486                 switch (ie_val->ie_pltype) {
487                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
488                         break;
489                 case AST_EVENT_IE_PLTYPE_EXISTS:
490                         ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
491                         break;
492                 case AST_EVENT_IE_PLTYPE_UINT:
493                         ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
494                         break;
495                 case AST_EVENT_IE_PLTYPE_STR:
496                         ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
497                         break;
498                 case AST_EVENT_IE_PLTYPE_RAW:
499                         ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
500                         break;
501                 }
502                 if (!event)
503                         break;
504         }
505
506         return event;
507 }
508
509 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
510 void ast_event_report_subs(const struct ast_event_sub *event_sub)
511 {
512         struct ast_event *event;
513         struct ast_event_sub *sub;
514         enum ast_event_type event_type = -1;
515         struct ast_event_ie_val *ie_val;
516
517         if (event_sub->type != AST_EVENT_SUB)
518                 return;
519
520         AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
521                 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
522                         event_type = ie_val->payload.uint;
523                         break;
524                 }
525         }
526
527         if (event_type == -1)
528                 return;
529
530         AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
531         AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
532                 if (event_sub == sub)
533                         continue;
534
535                 event = gen_sub_event(sub);
536
537                 if (!event)
538                         continue;
539
540                 event_sub->cb(event, event_sub->userdata);
541
542                 ast_event_destroy(event);
543         }
544         AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
545 }
546
547 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, 
548         ast_event_cb_t cb, void *userdata)
549 {
550         struct ast_event_sub *sub;
551
552         if (type < 0 || type >= AST_EVENT_TOTAL) {
553                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
554                 return NULL;
555         }
556
557         if (!(sub = ast_calloc(1, sizeof(*sub))))
558                 return NULL;
559
560         sub->type = type;
561         sub->cb = cb;
562         sub->userdata = userdata;
563         sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
564
565         return sub;
566 }
567
568 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
569         enum ast_event_ie_type ie_type, uint32_t unsigned_int)
570 {
571         struct ast_event_ie_val *ie_val;
572
573         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
574                 return -1;
575
576         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
577                 return -1;
578
579         ie_val->ie_type = ie_type;
580         ie_val->payload.uint = unsigned_int;
581         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
582
583         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
584
585         return 0;
586 }
587
588 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
589         enum ast_event_ie_type ie_type)
590 {
591         struct ast_event_ie_val *ie_val;
592
593         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
594                 return -1;
595
596         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
597                 return -1;
598
599         ie_val->ie_type = ie_type;
600         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
601
602         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
603
604         return 0;
605 }
606
607 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,      
608         enum ast_event_ie_type ie_type, const char *str)
609 {
610         struct ast_event_ie_val *ie_val;
611
612         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
613                 return -1;
614
615         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
616                 return -1;
617
618         ie_val->ie_type = ie_type;
619         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
620
621         if (!(ie_val->payload.str = ast_strdup(str))) {
622                 ast_free(ie_val);
623                 return -1;
624         }
625
626         ie_val->payload.hash = ast_str_hash(str);
627
628         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
629
630         return 0;
631 }
632
633 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,      
634         enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
635 {
636         struct ast_event_ie_val *ie_val;
637
638         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
639                 return -1;
640
641         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
642                 return -1;
643
644         ie_val->ie_type = ie_type;
645         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
646         ie_val->raw_datalen = raw_datalen;
647
648         if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
649                 ast_free(ie_val);
650                 return -1;
651         }
652
653         memcpy(ie_val->payload.raw, data, raw_datalen);
654
655         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
656
657         return 0;
658 }
659
660 int ast_event_sub_activate(struct ast_event_sub *sub)
661 {
662         if (ast_event_check_subscriber(AST_EVENT_SUB,
663                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
664                 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
665                 struct ast_event *event;
666
667                 event = gen_sub_event(sub);
668
669                 if (event)
670                         ast_event_queue(event);
671         }
672
673         AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
674         AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
675         AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
676
677         return 0;
678 }
679
680 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
681         void *userdata, ...)
682 {
683         va_list ap;
684         enum ast_event_ie_type ie_type;
685         struct ast_event_sub *sub;
686
687         if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
688                 return NULL;
689
690         va_start(ap, userdata);
691         for (ie_type = va_arg(ap, enum ast_event_type);
692                 ie_type != AST_EVENT_IE_END;
693                 ie_type = va_arg(ap, enum ast_event_type))
694         {
695                 enum ast_event_ie_pltype ie_pltype;
696
697                 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
698
699                 switch (ie_pltype) {
700                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
701                         break;
702                 case AST_EVENT_IE_PLTYPE_UINT:
703                 {
704                         uint32_t unsigned_int = va_arg(ap, uint32_t);
705                         ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
706                         break;
707                 }
708                 case AST_EVENT_IE_PLTYPE_STR:
709                 {
710                         const char *str = va_arg(ap, const char *);
711                         ast_event_sub_append_ie_str(sub, ie_type, str);
712                         break;
713                 }
714                 case AST_EVENT_IE_PLTYPE_RAW:
715                 {
716                         void *data = va_arg(ap, void *);
717                         size_t data_len = va_arg(ap, size_t);
718                         ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
719                         break;
720                 }
721                 case AST_EVENT_IE_PLTYPE_EXISTS:
722                         ast_event_sub_append_ie_exists(sub, ie_type);
723                         break;
724                 }
725         }
726         va_end(ap);
727
728         ast_event_sub_activate(sub);
729
730         return sub;
731 }
732
733 void ast_event_sub_destroy(struct ast_event_sub *sub)
734 {
735         struct ast_event_ie_val *ie_val;
736
737         while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
738                 ast_event_ie_val_destroy(ie_val);
739
740         ast_free(sub);
741 }
742
743 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
744 {
745         struct ast_event *event;
746
747         AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
748         AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
749         AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
750
751         if (ast_event_check_subscriber(AST_EVENT_UNSUB,
752                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
753                 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
754                 
755                 event = ast_event_new(AST_EVENT_UNSUB,
756                         AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
757                         AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
758                         AST_EVENT_IE_END);
759
760                 if (event)
761                         ast_event_queue(event);
762         }
763
764         ast_event_sub_destroy(sub);
765
766         return NULL;
767 }
768
769 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
770 {
771         iterator->event_len = ntohs(event->event_len);
772         iterator->event = event;
773         iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
774         return;
775 }
776
777 int ast_event_iterator_next(struct ast_event_iterator *iterator)
778 {
779         iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
780         return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
781 }
782
783 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
784 {
785         return ntohs(iterator->ie->ie_type);
786 }
787
788 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
789 {
790         return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
791 }
792
793 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
794 {
795         const struct ast_event_ie_str_payload *str_payload;
796
797         str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
798
799         return str_payload->str;
800 }
801
802 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
803 {
804         return iterator->ie->ie_payload;
805 }
806
807 enum ast_event_type ast_event_get_type(const struct ast_event *event)
808 {
809         return ntohs(event->type);
810 }
811
812 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
813 {
814         const uint32_t *ie_val;
815
816         ie_val = ast_event_get_ie_raw(event, ie_type);
817
818         return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
819 }
820
821 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
822 {
823         const struct ast_event_ie_str_payload *str_payload;
824
825         str_payload = ast_event_get_ie_raw(event, ie_type);
826
827         return str_payload->hash;
828 }
829
830 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
831 {
832         const struct ast_event_ie_str_payload *str_payload;
833
834         str_payload = ast_event_get_ie_raw(event, ie_type);
835
836         return str_payload->str;
837 }
838
839 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
840 {
841         struct ast_event_iterator iterator;
842         int res = 0;
843
844         for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
845                 if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
846                         return ast_event_iterator_get_ie_raw(&iterator);
847         }
848
849         return NULL;
850 }
851
852 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
853         const char *str)
854 {
855         struct ast_event_ie_str_payload *str_payload;
856         size_t payload_len;
857
858         payload_len = sizeof(*str_payload) + strlen(str);
859         str_payload = alloca(payload_len);
860
861         strcpy(str_payload->str, str);
862         str_payload->hash = ast_str_hash(str);
863
864         return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
865 }
866
867 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
868         uint32_t data)
869 {
870         data = htonl(data);
871         return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
872 }
873
874 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
875         const void *data, size_t data_len)
876 {
877         struct ast_event_ie *ie;
878         unsigned int extra_len;
879         uint16_t event_len;
880
881         event_len = ntohs((*event)->event_len);
882         extra_len = sizeof(*ie) + data_len;
883
884         if (!(*event = ast_realloc(*event, event_len + extra_len)))
885                 return -1;
886
887         ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
888         ie->ie_type = htons(ie_type);
889         ie->ie_payload_len = htons(data_len);
890         memcpy(ie->ie_payload, data, data_len);
891
892         (*event)->event_len = htons(event_len + extra_len);
893
894         return 0;
895 }
896
897 struct ast_event *ast_event_new(enum ast_event_type type, ...)
898 {
899         va_list ap;
900         struct ast_event *event;
901         enum ast_event_type ie_type;
902         struct ast_event_ie_val *ie_val;
903         AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
904
905         /* Invalid type */
906         if (type >= AST_EVENT_TOTAL) {
907                 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
908                         "type '%d'!\n", type);
909                 return NULL;
910         }
911
912         va_start(ap, type);
913         for (ie_type = va_arg(ap, enum ast_event_type);
914                 ie_type != AST_EVENT_IE_END;
915                 ie_type = va_arg(ap, enum ast_event_type))
916         {
917                 struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
918                 memset(ie_value, 0, sizeof(*ie_value));
919                 ie_value->ie_type = ie_type;
920                 ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
921                 if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
922                         ie_value->payload.uint = va_arg(ap, uint32_t);
923                 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
924                         ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
925                 else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
926                         void *data = va_arg(ap, void *);
927                         size_t datalen = va_arg(ap, size_t);
928                         ie_value->payload.raw = alloca(datalen);
929                         memcpy(ie_value->payload.raw, data, datalen);
930                         ie_value->raw_datalen = datalen;
931                 }
932                 AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
933         }
934         va_end(ap);
935
936         if (!(event = ast_calloc(1, sizeof(*event))))
937                 return NULL;
938
939         event->type = htons(type);
940         event->event_len = htons(sizeof(*event));
941
942         AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
943                 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
944                         ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
945                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
946                         ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
947                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
948                         ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
949
950                 if (!event)
951                         break;
952         }
953
954         if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
955                 /* If the event is originating on this server, add the server's
956                  * entity ID to the event. */
957                 ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
958         }
959
960         return event;
961 }
962
963 void ast_event_destroy(struct ast_event *event)
964 {
965         ast_free(event);
966 }
967
968 static void ast_event_ref_destroy(void *obj)
969 {
970         struct ast_event_ref *event_ref = obj;
971
972         ast_event_destroy(event_ref->event);
973 }
974
975 static struct ast_event *ast_event_dup(const struct ast_event *event)
976 {
977         struct ast_event *dup_event;
978         uint16_t event_len;
979
980         event_len = ast_event_get_size(event);
981
982         if (!(dup_event = ast_calloc(1, event_len))) {
983                 return NULL;
984         }
985
986         memcpy(dup_event, event, event_len);
987
988         return dup_event;
989 }
990
991 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
992 {
993         va_list ap;
994         enum ast_event_ie_type ie_type;
995         struct ast_event *dup_event = NULL;
996         struct ast_event_ref *cached_event_ref;
997         struct ast_event *cache_arg_event;
998         struct ast_event_ref tmp_event_ref = {
999                 .event = NULL,
1000         };
1001         struct ao2_container *container = NULL;
1002
1003         if (type >= AST_EVENT_TOTAL) {
1004                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
1005                 return NULL;
1006         }
1007
1008         if (!(container = ast_event_cache[type].container)) {
1009                 ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
1010                 return NULL;
1011         }
1012
1013         if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
1014                 return NULL;
1015         }
1016
1017         va_start(ap, type);
1018         for (ie_type = va_arg(ap, enum ast_event_type);
1019                 ie_type != AST_EVENT_IE_END;
1020                 ie_type = va_arg(ap, enum ast_event_type))
1021         {
1022                 enum ast_event_ie_pltype ie_pltype;
1023
1024                 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
1025
1026                 switch (ie_pltype) {
1027                 case AST_EVENT_IE_PLTYPE_UINT:
1028                         ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
1029                         break;
1030                 case AST_EVENT_IE_PLTYPE_STR:
1031                         ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
1032                         break;
1033                 case AST_EVENT_IE_PLTYPE_RAW:
1034                 {
1035                         void *data = va_arg(ap, void *);
1036                         size_t datalen = va_arg(ap, size_t);
1037                         ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
1038                 }
1039                 case AST_EVENT_IE_PLTYPE_EXISTS:
1040                         ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
1041                         break;
1042                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
1043                         break;
1044                 }
1045         }
1046         va_end(ap);
1047
1048         tmp_event_ref.event = cache_arg_event;
1049
1050         cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
1051
1052         ast_event_destroy(cache_arg_event);
1053         cache_arg_event = NULL;
1054
1055         if (cached_event_ref) {
1056                 dup_event = ast_event_dup(cached_event_ref->event);
1057                 ao2_ref(cached_event_ref, -1);
1058                 cached_event_ref = NULL;
1059         }
1060
1061         return dup_event;
1062 }
1063
1064 static struct ast_event_ref *alloc_event_ref(void)
1065 {
1066         return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
1067 }
1068
1069 /*! \brief Duplicate an event and add it to the cache
1070  * \note This assumes this index in to the cache is locked */
1071 static int attribute_unused ast_event_dup_and_cache(const struct ast_event *event)
1072 {
1073         struct ast_event *dup_event;
1074         struct ast_event_ref *event_ref;
1075
1076         if (!(dup_event = ast_event_dup(event))) {
1077                 return -1;
1078         }
1079
1080         if (!(event_ref = alloc_event_ref())) {
1081                 ast_event_destroy(dup_event);
1082                 return -1;
1083         }
1084
1085         event_ref->event = dup_event;
1086
1087         ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
1088
1089         ao2_ref(event_ref, -1);
1090
1091         return 0;
1092 }
1093
1094 int ast_event_queue_and_cache(struct ast_event *event)
1095 {
1096         struct ao2_container *container;
1097         struct ast_event_ref tmp_event_ref = {
1098                 .event = event,
1099         };
1100
1101         if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
1102                 ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
1103                 goto queue_event;
1104         }
1105
1106         /* Remove matches from the cache */
1107         ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
1108                         ast_event_cmp, &tmp_event_ref);
1109
1110 queue_event:
1111         return ast_event_queue(event);
1112 }
1113
1114 static int handle_event(void *data)
1115 {
1116         struct ast_event_ref *event_ref = data;
1117         struct ast_event_sub *sub;
1118         uint16_t host_event_type;
1119
1120         host_event_type = ntohs(event_ref->event->type);
1121
1122         /* Subscribers to this specific event first */
1123         AST_RWDLLIST_RDLOCK(&ast_event_subs[host_event_type]);
1124         AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
1125                 struct ast_event_ie_val *ie_val;
1126                 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
1127                         if (!match_ie_val(event_ref->event, ie_val, NULL)) {
1128                                 break;
1129                         }
1130                 }
1131                 if (ie_val) {
1132                         continue;
1133                 }
1134                 sub->cb(event_ref->event, sub->userdata);
1135         }
1136         AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]);
1137
1138         /* Now to subscribers to all event types */
1139         AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
1140         AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry) {
1141                 sub->cb(event_ref->event, sub->userdata);
1142         }
1143         AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
1144
1145         ao2_ref(event_ref, -1);
1146
1147         return 0;
1148 }
1149
1150 int ast_event_queue(struct ast_event *event)
1151 {
1152         struct ast_event_ref *event_ref;
1153         uint16_t host_event_type;
1154
1155         host_event_type = ntohs(event->type);
1156
1157         /* Invalid type */
1158         if (host_event_type >= AST_EVENT_TOTAL) {
1159                 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
1160                         "type '%d'!\n", host_event_type);
1161                 return -1;
1162         }
1163
1164         /* If nobody has subscribed to this event type, throw it away now */
1165         if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
1166                         == AST_EVENT_SUB_NONE) {
1167                 ast_event_destroy(event);
1168                 return 0;
1169         }
1170
1171         if (!(event_ref = alloc_event_ref())) {
1172                 return -1;
1173         }
1174
1175         event_ref->event = event;
1176
1177         return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
1178 }
1179
1180 static int ast_event_hash_mwi(const void *obj, const int flags)
1181 {
1182         const struct ast_event *event = obj;
1183         const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
1184         const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
1185
1186         return ast_str_hash_add(context, ast_str_hash(mailbox));
1187 }
1188
1189 /*!
1190  * \internal
1191  * \brief Hash function for AST_EVENT_DEVICE_STATE
1192  *
1193  * \param[in] obj an ast_event
1194  * \param[in] flags unused
1195  *
1196  * \return hash value
1197  */
1198 static int ast_event_hash_devstate(const void *obj, const int flags)
1199 {
1200         const struct ast_event *event = obj;
1201
1202         return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
1203 }
1204
1205 /*!
1206  * \internal
1207  * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
1208  *
1209  * \param[in] obj an ast_event
1210  * \param[in] flags unused
1211  *
1212  * \return hash value
1213  */
1214 static int ast_event_hash_devstate_change(const void *obj, const int flags)
1215 {
1216         const struct ast_event *event = obj;
1217
1218         return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
1219 }
1220
1221 static int ast_event_hash(const void *obj, const int flags)
1222 {
1223         const struct ast_event_ref *event_ref;
1224         const struct ast_event *event;
1225         ao2_hash_fn *hash_fn;
1226
1227         event_ref = obj;
1228         event = event_ref->event;
1229
1230         if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
1231                 return 0;
1232         }
1233
1234         return hash_fn(event, flags);
1235 }
1236
1237 /*!
1238  * \internal
1239  * \brief Compare two events
1240  *
1241  * \param[in] obj the first event, as an ast_event_ref
1242  * \param[in] arg the second event, as an ast_event_ref
1243  * \param[in] flags unused
1244  *
1245  * \pre Both events must be the same type.
1246  * \pre The event type must be declared as a cached event type in ast_event_cache
1247  *
1248  * \details This function takes two events, and determines if they are considered
1249  * equivalent.  The values of information elements specified in the cache arguments
1250  * for the event type are used to determine if the events are equivalent.
1251  *
1252  * \retval 0 No match
1253  * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
1254  */
1255 static int ast_event_cmp(void *obj, void *arg, int flags)
1256 {
1257         struct ast_event_ref *event_ref, *event_ref2;
1258         struct ast_event *event, *event2;
1259         int res = CMP_MATCH;
1260         int i;
1261         enum ast_event_ie_type *cache_args;
1262
1263         event_ref = obj;
1264         event = event_ref->event;
1265
1266         event_ref2 = arg;
1267         event2 = event_ref2->event;
1268
1269         cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
1270
1271         for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
1272                 struct ast_event_ie_val ie_val = {
1273                         .ie_type = cache_args[i],
1274                 };
1275
1276                 if (!match_ie_val(event, &ie_val, event2)) {
1277                         res = 0;
1278                         break;
1279                 }
1280         }
1281
1282         return res;
1283 }
1284
1285 int ast_event_init(void)
1286 {
1287         int i;
1288
1289         for (i = 0; i < AST_EVENT_TOTAL; i++) {
1290                 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
1291         }
1292
1293         for (i = 0; i < AST_EVENT_TOTAL; i++) {
1294                 if (!ast_event_cache[i].hash_fn) {
1295                         /* This event type is not cached. */
1296                         continue;
1297                 }
1298
1299                 if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
1300                                 ast_event_hash, ast_event_cmp))) {
1301                         return -1;
1302                 }
1303         }
1304
1305         if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
1306                 return -1;
1307         }
1308
1309         return 0;
1310 }