Merge some more changes from team/russell/events
[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 #include "asterisk/event.h"
32 #include "asterisk/linkedlists.h"
33 #include "asterisk/dlinkedlists.h"
34 #include "asterisk/lock.h"
35 #include "asterisk/utils.h"
36 #include "asterisk/unaligned.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/taskprocessor.h"
39
40 struct ast_taskprocessor *event_dispatcher;
41
42 /*!
43  * \brief An event information element
44  *
45  * \note The format of this structure is important.  Since these events may
46  *       be sent directly over a network, changing this structure will break
47  *       compatibility with older versions.  However, at this point, this code
48  *       has not made it into a release, so it is still fair game for change.
49  */
50 struct ast_event_ie {
51         enum ast_event_ie_type ie_type:16;
52         /*! Total length of the IE payload */
53         uint16_t ie_payload_len;
54         unsigned char ie_payload[0];
55 } __attribute__ ((packed));
56
57 /*!
58  * \brief An event
59  *
60  * An ast_event consists of an event header (this structure), and zero or
61  * more information elements defined by ast_event_ie.
62  *
63  * \note The format of this structure is important.  Since these events may
64  *       be sent directly over a network, changing this structure will break
65  *       compatibility with older versions.  However, at this point, this code
66  *       has not made it into a release, so it is still fair game for change.
67  */
68 struct ast_event {
69         /*! Event type */
70         enum ast_event_type type:16;
71         /*! Total length of the event */
72         uint16_t event_len:16;
73         /*! The data payload of the event, made up of information elements */
74         unsigned char payload[0];
75 } __attribute__ ((packed));
76
77 struct ast_event_ref {
78         struct ast_event *event;
79         AST_LIST_ENTRY(ast_event_ref) entry;
80 };
81
82 struct ast_event_ie_val {
83         AST_LIST_ENTRY(ast_event_ie_val) entry;
84         enum ast_event_ie_type ie_type;
85         enum ast_event_ie_pltype ie_pltype;
86         union {
87                 uint32_t uint;
88                 const char *str;
89                 void *raw;
90         } payload;
91         size_t raw_datalen;
92 };
93
94 /*! \brief Event subscription */
95 struct ast_event_sub {
96         enum ast_event_type type;
97         ast_event_cb_t cb;
98         void *userdata;
99         uint32_t uniqueid;
100         AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
101         AST_RWDLLIST_ENTRY(ast_event_sub) entry;
102 };
103
104 static uint32_t sub_uniqueid;
105
106 /*! \brief Event subscriptions
107  * The event subscribers are indexed by which event they are subscribed to */
108 static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
109
110 /*! \brief Cached events
111  * The event cache is indexed on the event type.  The purpose of this is 
112  * for events that express some sort of state.  So, when someone first
113  * needs to know this state, it can get the last known state from the cache. */
114 static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL];
115
116 /*!
117  * The index of each entry _must_ match the event type number!
118  */
119 static struct event_name {
120         enum ast_event_type type;
121         const char *name;
122 } event_names[] = {
123         { 0, "" },
124         { AST_EVENT_CUSTOM,              "Custom" },
125         { AST_EVENT_MWI,                 "MWI" },
126         { AST_EVENT_SUB,                 "Subscription" },
127         { AST_EVENT_UNSUB,               "Unsubscription" },
128         { AST_EVENT_DEVICE_STATE,        "DeviceState" },
129         { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
130 };
131
132 /*!
133  * The index of each entry _must_ match the event ie number!
134  */
135 static struct ie_map {
136         enum ast_event_ie_type ie_type;
137         enum ast_event_ie_pltype ie_pltype;
138         const char *name;
139 } ie_maps[] = {
140         { 0, 0, "" },
141         { AST_EVENT_IE_NEWMSGS,   AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
142         { AST_EVENT_IE_OLDMSGS,   AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
143         { AST_EVENT_IE_MAILBOX,   AST_EVENT_IE_PLTYPE_STR,  "Mailbox" },
144         { AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
145         { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
146         { AST_EVENT_IE_EXISTS,    AST_EVENT_IE_PLTYPE_UINT, "Exists" },
147         { AST_EVENT_IE_DEVICE,    AST_EVENT_IE_PLTYPE_STR,  "Device" },
148         { AST_EVENT_IE_STATE,     AST_EVENT_IE_PLTYPE_UINT, "State" },
149         { AST_EVENT_IE_CONTEXT,   AST_EVENT_IE_PLTYPE_STR,  "Context" },
150         { AST_EVENT_IE_EID,       AST_EVENT_IE_PLTYPE_RAW,  "EntityID" },
151 };
152
153 const char *ast_event_get_type_name(const struct ast_event *event)
154 {
155         enum ast_event_type type;
156
157         type = ast_event_get_type(event);
158
159         if (type >= AST_EVENT_TOTAL || type < 0) {
160                 ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
161                 return "";
162         }
163
164         return event_names[type].name;
165 }
166
167 int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
168 {
169         int i;
170
171         for (i = 0; i < ARRAY_LEN(event_names); i++) {
172                 if (strcasecmp(event_names[i].name, str))
173                         continue;
174
175                 *event_type = event_names[i].type;
176                 return 0;
177         }
178
179         return -1;
180 }
181
182 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
183 {
184         if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
185                 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
186                 return "";
187         }
188
189         return ie_maps[ie_type].name;
190 }
191
192 enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
193 {
194         if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
195                 ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
196                 return AST_EVENT_IE_PLTYPE_UNKNOWN;
197         }
198
199         return ie_maps[ie_type].ie_pltype;
200 }
201
202 int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
203 {
204         int i;
205
206         for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
207                 if (strcasecmp(ie_maps[i].name, str))
208                         continue;
209
210                 *ie_type = ie_maps[i].ie_type;
211                 return 0;
212         }
213
214         return -1;
215 }
216
217 size_t ast_event_get_size(const struct ast_event *event)
218 {
219         size_t res;
220
221         res = ntohs(event->event_len);
222
223         return res;
224 }
225
226 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
227 {
228         switch (ie_val->ie_pltype) {
229         case AST_EVENT_IE_PLTYPE_STR:
230         case AST_EVENT_IE_PLTYPE_RAW:
231                 ast_free(ie_val->payload.raw);
232                 break;
233         case AST_EVENT_IE_PLTYPE_UINT:
234         case AST_EVENT_IE_PLTYPE_EXISTS:
235         case AST_EVENT_IE_PLTYPE_UNKNOWN:
236                 break;
237         }
238
239         ast_free(ie_val);
240 }
241
242 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
243 {
244         va_list ap;
245         enum ast_event_ie_type ie_type;
246         enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
247         struct ast_event_ie_val *ie_val, *sub_ie_val;
248         struct ast_event_sub *sub;
249         AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
250
251         if (type >= AST_EVENT_TOTAL) {
252                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
253                 return res;
254         }
255
256         va_start(ap, type);
257         for (ie_type = va_arg(ap, enum ast_event_type);
258                 ie_type != AST_EVENT_IE_END;
259                 ie_type = va_arg(ap, enum ast_event_type))
260         {
261                 struct ast_event_ie_val *ie_val = alloca(sizeof(*ie_val));
262                 memset(ie_val, 0, sizeof(*ie_val));
263                 ie_val->ie_type = ie_type;
264                 ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
265                 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
266                         ie_val->payload.uint = va_arg(ap, uint32_t);
267                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
268                         ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
269                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
270                         void *data = va_arg(ap, void *);
271                         size_t datalen = va_arg(ap, size_t);
272                         ie_val->payload.raw = alloca(datalen);
273                         memcpy(ie_val->payload.raw, data, datalen);
274                         ie_val->raw_datalen = datalen;
275                 }
276                 AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
277         }
278         va_end(ap);
279
280         AST_RWDLLIST_RDLOCK(&ast_event_subs[type]);
281         AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
282                 AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
283                         AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
284                                 if (sub_ie_val->ie_type == ie_val->ie_type)
285                                         break;
286                         }
287                         if (!sub_ie_val) {
288                                 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
289                                         break;
290                                 continue;
291                         }
292                         /* The subscriber doesn't actually care what the value is */
293                         if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
294                                 continue;
295                         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
296                                 ie_val->payload.uint != sub_ie_val->payload.uint)
297                                 break;
298                         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
299                                 strcmp(ie_val->payload.str, sub_ie_val->payload.str))
300                                 break;
301                         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
302                                 memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
303                                 break;
304                 }
305                 if (!ie_val)
306                         break;
307         }
308         AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
309
310         if (sub) /* All parameters were matched */
311                 return AST_EVENT_SUB_EXISTS;
312
313         AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
314         if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
315                 res = AST_EVENT_SUB_EXISTS;
316         AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
317
318         return res;
319 }
320
321 static int match_ie_val(struct ast_event *event, struct ast_event_ie_val *ie_val, struct ast_event *event2)
322 {
323         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
324                 uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
325                 if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
326                         return 1;
327                 return 0;
328         }
329
330         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
331                 const char *str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
332                 if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type)))
333                         return 1;
334                 return 0;
335         }
336
337         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
338                 const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
339                 if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
340                         return 1;
341                 return 0;
342         }
343
344         if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
345                 if (ast_event_get_ie_raw(event, ie_val->ie_type))
346                         return 1;
347                 return 0;
348         }
349
350         return 0;
351 }
352
353 /*! \brief Dump the event cache for the subscribed event type */
354 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
355 {
356         struct ast_event_ref *event_ref;
357         enum ast_event_type type = event_sub->type;
358
359         AST_RWLIST_RDLOCK(&ast_event_cache[type]);
360         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
361                 struct ast_event_ie_val *ie_val;
362                 AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
363                         if (!match_ie_val(event_ref->event, ie_val, NULL))
364                                 break;
365                 }
366                 if (!ie_val) {
367                         /* All parameters were matched on this cache entry, so dump it */
368                         event_sub->cb(event_ref->event, event_sub->userdata);
369                 }
370         }
371         AST_RWLIST_TRAVERSE_SAFE_END
372         AST_RWLIST_UNLOCK(&ast_event_cache[type]);
373 }
374
375 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
376 {
377         struct ast_event_ie_val *ie_val;
378         struct ast_event *event;
379
380         event = ast_event_new(AST_EVENT_SUB,
381                 AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
382                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
383                 AST_EVENT_IE_END);
384
385         if (!event)
386                 return NULL;
387
388         AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
389                 switch (ie_val->ie_pltype) {
390                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
391                         break;
392                 case AST_EVENT_IE_PLTYPE_EXISTS:
393                         ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
394                         break;
395                 case AST_EVENT_IE_PLTYPE_UINT:
396                         ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
397                         break;
398                 case AST_EVENT_IE_PLTYPE_STR:
399                         ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
400                         break;
401                 case AST_EVENT_IE_PLTYPE_RAW:
402                         ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
403                         break;
404                 }
405                 if (!event)
406                         break;
407         }
408
409         return event;
410 }
411
412 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
413 void ast_event_report_subs(const struct ast_event_sub *event_sub)
414 {
415         struct ast_event *event;
416         struct ast_event_sub *sub;
417         enum ast_event_type event_type = -1;
418         struct ast_event_ie_val *ie_val;
419
420         if (event_sub->type != AST_EVENT_SUB)
421                 return;
422
423         AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
424                 if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
425                         event_type = ie_val->payload.uint;
426                         break;
427                 }
428         }
429
430         if (event_type == -1)
431                 return;
432
433         AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
434         AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
435                 if (event_sub == sub)
436                         continue;
437
438                 event = gen_sub_event(sub);
439
440                 if (!event)
441                         continue;
442
443                 event_sub->cb(event, event_sub->userdata);
444
445                 ast_event_destroy(event);
446         }
447         AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
448 }
449
450 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, 
451         ast_event_cb_t cb, void *userdata)
452 {
453         struct ast_event_sub *sub;
454
455         if (type < 0 || type >= AST_EVENT_TOTAL) {
456                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
457                 return NULL;
458         }
459
460         if (!(sub = ast_calloc(1, sizeof(*sub))))
461                 return NULL;
462
463         sub->type = type;
464         sub->cb = cb;
465         sub->userdata = userdata;
466         sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
467
468         return sub;
469 }
470
471 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
472         enum ast_event_ie_type ie_type, uint32_t uint)
473 {
474         struct ast_event_ie_val *ie_val;
475
476         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
477                 return -1;
478
479         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
480                 return -1;
481
482         ie_val->ie_type = ie_type;
483         ie_val->payload.uint = uint;
484         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
485
486         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
487
488         return 0;
489 }
490
491 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
492         enum ast_event_ie_type ie_type)
493 {
494         struct ast_event_ie_val *ie_val;
495
496         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
497                 return -1;
498
499         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
500                 return -1;
501
502         ie_val->ie_type = ie_type;
503         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
504
505         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
506
507         return 0;
508 }
509
510 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,      
511         enum ast_event_ie_type ie_type, const char *str)
512 {
513         struct ast_event_ie_val *ie_val;
514
515         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
516                 return -1;
517
518         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
519                 return -1;
520
521         ie_val->ie_type = ie_type;
522         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
523
524         if (!(ie_val->payload.str = ast_strdup(str))) {
525                 ast_free(ie_val);
526                 return -1;
527         }
528
529         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
530
531         return 0;
532 }
533
534 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,      
535         enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
536 {
537         struct ast_event_ie_val *ie_val;
538
539         if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
540                 return -1;
541
542         if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
543                 return -1;
544
545         ie_val->ie_type = ie_type;
546         ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
547         ie_val->raw_datalen = raw_datalen;
548
549         if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
550                 ast_free(ie_val);
551                 return -1;
552         }
553
554         memcpy(ie_val->payload.raw, data, raw_datalen);
555
556         AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
557
558         return 0;
559 }
560
561 int ast_event_sub_activate(struct ast_event_sub *sub)
562 {
563         if (ast_event_check_subscriber(AST_EVENT_SUB,
564                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
565                 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
566                 struct ast_event *event;
567
568                 event = gen_sub_event(sub);
569
570                 if (event)
571                         ast_event_queue(event);
572         }
573
574         AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
575         AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
576         AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
577
578         return 0;
579 }
580
581 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
582         void *userdata, ...)
583 {
584         va_list ap;
585         enum ast_event_ie_type ie_type;
586         struct ast_event_sub *sub;
587
588         if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
589                 return NULL;
590
591         va_start(ap, userdata);
592         for (ie_type = va_arg(ap, enum ast_event_type);
593                 ie_type != AST_EVENT_IE_END;
594                 ie_type = va_arg(ap, enum ast_event_type))
595         {
596                 enum ast_event_ie_pltype ie_pltype;
597
598                 ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
599
600                 switch (ie_pltype) {
601                 case AST_EVENT_IE_PLTYPE_UNKNOWN:
602                         break;
603                 case AST_EVENT_IE_PLTYPE_UINT:
604                 {
605                         uint32_t uint = va_arg(ap, uint32_t);
606                         ast_event_sub_append_ie_uint(sub, ie_type, uint);
607                         break;
608                 }
609                 case AST_EVENT_IE_PLTYPE_STR:
610                 {
611                         const char *str = va_arg(ap, const char *);
612                         ast_event_sub_append_ie_str(sub, ie_type, str);
613                         break;
614                 }
615                 case AST_EVENT_IE_PLTYPE_RAW:
616                 {
617                         void *data = va_arg(ap, void *);
618                         size_t data_len = va_arg(ap, size_t);
619                         ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
620                         break;
621                 }
622                 case AST_EVENT_IE_PLTYPE_EXISTS:
623                         ast_event_sub_append_ie_exists(sub, ie_type);
624                         break;
625                 }
626         }
627         va_end(ap);
628
629         ast_event_sub_activate(sub);
630
631         return sub;
632 }
633
634 void ast_event_sub_destroy(struct ast_event_sub *sub)
635 {
636         struct ast_event_ie_val *ie_val;
637
638         while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
639                 ast_event_ie_val_destroy(ie_val);
640
641         ast_free(sub);
642 }
643
644 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
645 {
646         struct ast_event *event;
647
648         AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
649         AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
650         AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
651
652         if (ast_event_check_subscriber(AST_EVENT_UNSUB,
653                 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
654                 AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
655                 
656                 event = ast_event_new(AST_EVENT_UNSUB,
657                         AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
658                         AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
659                         AST_EVENT_IE_END);
660
661                 if (event)
662                         ast_event_queue(event);
663         }
664
665         ast_event_sub_destroy(sub);
666
667         return NULL;
668 }
669
670 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
671 {
672         iterator->event_len = ntohs(event->event_len);
673         iterator->event = event;
674         iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
675         return;
676 }
677
678 int ast_event_iterator_next(struct ast_event_iterator *iterator)
679 {
680         iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
681         return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
682 }
683
684 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
685 {
686         return ntohs(iterator->ie->ie_type);
687 }
688
689 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
690 {
691         return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
692 }
693
694 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
695 {
696         return (const char*)iterator->ie->ie_payload;
697 }
698
699 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
700 {
701         return iterator->ie->ie_payload;
702 }
703
704 enum ast_event_type ast_event_get_type(const struct ast_event *event)
705 {
706         return ntohs(event->type);
707 }
708
709 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
710 {
711         const uint32_t *ie_val;
712
713         ie_val = ast_event_get_ie_raw(event, ie_type);
714
715         return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
716 }
717
718 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
719 {
720         return ast_event_get_ie_raw(event, ie_type);
721 }
722
723 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
724 {
725         struct ast_event_iterator iterator;
726         int res = 0;
727
728         for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
729                 if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
730                         return ast_event_iterator_get_ie_raw(&iterator);
731         }
732
733         return NULL;
734 }
735
736 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
737         const char *str)
738 {
739         return ast_event_append_ie_raw(event, ie_type, str, strlen(str) + 1);
740 }
741
742 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
743         uint32_t data)
744 {
745         data = htonl(data);
746         return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
747 }
748
749 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
750         const void *data, size_t data_len)
751 {
752         struct ast_event_ie *ie;
753         unsigned int extra_len;
754         uint16_t event_len;
755
756         event_len = ntohs((*event)->event_len);
757         extra_len = sizeof(*ie) + data_len;
758
759         if (!(*event = ast_realloc(*event, event_len + extra_len)))
760                 return -1;
761
762         ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
763         ie->ie_type = htons(ie_type);
764         ie->ie_payload_len = htons(data_len);
765         memcpy(ie->ie_payload, data, data_len);
766
767         (*event)->event_len = htons(event_len + extra_len);
768
769         return 0;
770 }
771
772 struct ast_event *ast_event_new(enum ast_event_type type, ...)
773 {
774         va_list ap;
775         struct ast_event *event;
776         enum ast_event_type ie_type;
777         struct ast_event_ie_val *ie_val;
778         AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
779
780         /* Invalid type */
781         if (type >= AST_EVENT_TOTAL) {
782                 ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
783                         "type '%d'!\n", type);
784                 return NULL;
785         }
786
787         va_start(ap, type);
788         for (ie_type = va_arg(ap, enum ast_event_type);
789                 ie_type != AST_EVENT_IE_END;
790                 ie_type = va_arg(ap, enum ast_event_type))
791         {
792                 struct ast_event_ie_val *ie_val = alloca(sizeof(*ie_val));
793                 memset(ie_val, 0, sizeof(*ie_val));
794                 ie_val->ie_type = ie_type;
795                 ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
796                 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
797                         ie_val->payload.uint = va_arg(ap, uint32_t);
798                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
799                         ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
800                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
801                         void *data = va_arg(ap, void *);
802                         size_t datalen = va_arg(ap, size_t);
803                         ie_val->payload.raw = alloca(datalen);
804                         memcpy(ie_val->payload.raw, data, datalen);
805                         ie_val->raw_datalen = datalen;
806                 }
807                 AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
808         }
809         va_end(ap);
810
811         if (!(event = ast_calloc(1, sizeof(*event))))
812                 return NULL;
813
814         event->type = htons(type);
815         event->event_len = htons(sizeof(*event));
816
817         AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
818                 if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
819                         ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
820                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
821                         ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
822                 else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
823                         ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
824
825                 if (!event)
826                         break;
827         }
828
829         if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
830                 /* If the event is originating on this server, add the server's
831                  * entity ID to the event. */
832                 ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &g_eid, sizeof(g_eid));
833         }
834
835         return event;
836 }
837
838 void ast_event_destroy(struct ast_event *event)
839 {
840         ast_free(event);
841 }
842
843 static void ast_event_ref_destroy(struct ast_event_ref *event_ref)
844 {
845         ast_event_destroy(event_ref->event);
846         ast_free(event_ref);
847 }
848
849 static struct ast_event *ast_event_dup(const struct ast_event *event)
850 {
851         struct ast_event *dup_event;
852         uint16_t event_len;
853
854         event_len = ast_event_get_size(event);
855
856         if (!(dup_event = ast_calloc(1, event_len)))
857                 return NULL;
858         
859         memcpy(dup_event, event, event_len);
860
861         return dup_event;
862 }
863
864 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
865 {
866         va_list ap;
867         enum ast_event_ie_type ie_type;
868         struct ast_event *dup_event = NULL;
869         struct ast_event_ref *event_ref;
870         struct ast_event_ie_val *cache_arg;
871         AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val);
872
873         if (type >= AST_EVENT_TOTAL) {
874                 ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
875                 return NULL;
876         }
877
878         va_start(ap, type);
879         for (ie_type = va_arg(ap, enum ast_event_type);
880                 ie_type != AST_EVENT_IE_END;
881                 ie_type = va_arg(ap, enum ast_event_type))
882         {
883                 cache_arg = alloca(sizeof(*cache_arg));
884                 memset(cache_arg, 0, sizeof(*cache_arg));
885                 cache_arg->ie_type = ie_type;
886                 cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
887                 if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
888                         cache_arg->payload.uint = va_arg(ap, uint32_t);
889                 else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
890                         cache_arg->payload.str = ast_strdupa(va_arg(ap, const char *));
891                 else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
892                         void *data = va_arg(ap, void *);
893                         size_t datalen = va_arg(ap, size_t);
894                         cache_arg->payload.raw = alloca(datalen);
895                         memcpy(cache_arg->payload.raw, data, datalen);
896                         cache_arg->raw_datalen = datalen;
897                 }
898                 AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
899         }
900         va_end(ap);
901
902         if (AST_LIST_EMPTY(&cache_args)) {
903                 ast_log(LOG_ERROR, "Events can not be retrieved from the cache without "
904                         "specifying at least one IE type!\n");
905                 return NULL;
906         }
907
908         AST_RWLIST_RDLOCK(&ast_event_cache[type]);
909         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
910                 AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
911                         if (!match_ie_val(event_ref->event, cache_arg, NULL))
912                                 break;  
913                 }
914                 if (!cache_arg) {
915                         /* All parameters were matched on this cache entry, so return it */
916                         dup_event = ast_event_dup(event_ref->event);
917                         break;
918                 }
919         }
920         AST_RWLIST_TRAVERSE_SAFE_END
921         AST_RWLIST_UNLOCK(&ast_event_cache[type]);
922
923         return dup_event;
924 }
925
926 /*! \brief Duplicate an event and add it to the cache
927  * \note This assumes this index in to the cache is locked */
928 static int ast_event_dup_and_cache(const struct ast_event *event)
929 {
930         struct ast_event *dup_event;
931         struct ast_event_ref *event_ref;
932
933         if (!(dup_event = ast_event_dup(event)))
934                 return -1;
935         if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
936                 return -1;
937         
938         event_ref->event = dup_event;
939
940         AST_LIST_INSERT_TAIL(&ast_event_cache[ntohs(event->type)], event_ref, entry);
941
942         return 0;
943 }
944
945 int ast_event_queue_and_cache(struct ast_event *event, ...)
946 {
947         va_list ap;
948         enum ast_event_type ie_type;
949         uint16_t host_event_type;
950         struct ast_event_ref *event_ref;
951         int res;
952         struct ast_event_ie_val *cache_arg;
953         AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val);
954
955         host_event_type = ntohs(event->type);
956
957         /* Invalid type */
958         if (host_event_type >= AST_EVENT_TOTAL) {
959                 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
960                         "type '%d'!\n", host_event_type);
961                 return -1;
962         }
963
964         va_start(ap, event);
965         for (ie_type = va_arg(ap, enum ast_event_type);
966                 ie_type != AST_EVENT_IE_END;
967                 ie_type = va_arg(ap, enum ast_event_type))
968         {
969                 cache_arg = alloca(sizeof(*cache_arg));
970                 memset(cache_arg, 0, sizeof(*cache_arg));
971                 cache_arg->ie_type = ie_type;
972                 cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
973                 if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
974                         cache_arg->raw_datalen = va_arg(ap, size_t);
975                 AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
976         }
977         va_end(ap);
978
979         if (AST_LIST_EMPTY(&cache_args)) {
980                 ast_log(LOG_ERROR, "Events can not be cached without specifying at "
981                         "least one IE type!\n");
982                 return ast_event_queue(event);
983         }
984  
985         AST_RWLIST_WRLOCK(&ast_event_cache[host_event_type]);
986         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[host_event_type], event_ref, entry) {
987                 AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
988                         if (!match_ie_val(event_ref->event, cache_arg, event))
989                                 break;  
990                 }
991                 if (!cache_arg) {
992                         /* All parameters were matched on this cache entry, so remove it */
993                         AST_LIST_REMOVE_CURRENT(entry);
994                         ast_event_ref_destroy(event_ref);
995                 }
996         }
997         AST_RWLIST_TRAVERSE_SAFE_END;
998         res = ast_event_dup_and_cache(event);
999         AST_RWLIST_UNLOCK(&ast_event_cache[host_event_type]);
1000
1001         return (ast_event_queue(event) || res) ? -1 : 0;
1002 }
1003
1004 static int handle_event(void *data)
1005 {
1006         struct ast_event_ref *event_ref = data;
1007         struct ast_event_sub *sub;
1008         uint16_t host_event_type;
1009
1010         host_event_type = ntohs(event_ref->event->type);
1011
1012         /* Subscribers to this specific event first */
1013         AST_RWDLLIST_RDLOCK(&ast_event_subs[host_event_type]);
1014         AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
1015                 struct ast_event_ie_val *ie_val;
1016                 AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
1017                         if (!match_ie_val(event_ref->event, ie_val, NULL))
1018                                 break;
1019                 }
1020                 if (ie_val)
1021                         continue;
1022                 sub->cb(event_ref->event, sub->userdata);
1023         }
1024         AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]);
1025
1026         /* Now to subscribers to all event types */
1027         AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
1028         AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry)
1029                 sub->cb(event_ref->event, sub->userdata);
1030         AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
1031
1032         ast_event_ref_destroy(event_ref);
1033
1034         return 0;
1035 }
1036
1037 int ast_event_queue(struct ast_event *event)
1038 {
1039         struct ast_event_ref *event_ref;
1040         uint16_t host_event_type;
1041
1042         host_event_type = ntohs(event->type);
1043
1044         /* Invalid type */
1045         if (host_event_type >= AST_EVENT_TOTAL) {
1046                 ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
1047                         "type '%d'!\n", host_event_type);
1048                 return -1;
1049         }
1050
1051         /* If nobody has subscribed to this event type, throw it away now */
1052         if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END) 
1053                 == AST_EVENT_SUB_NONE) {
1054                 ast_event_destroy(event);
1055                 return 0;
1056         }
1057
1058         if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
1059                 return -1;
1060
1061         event_ref->event = event;
1062
1063         return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
1064 }
1065
1066 void ast_event_init(void)
1067 {
1068         int i;
1069
1070         for (i = 0; i < AST_EVENT_TOTAL; i++)
1071                 AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
1072
1073         for (i = 0; i < AST_EVENT_TOTAL; i++)
1074                 AST_RWLIST_HEAD_INIT(&ast_event_cache[i]);
1075
1076         event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0);
1077 }