Thu Apr 28 2011 17:13:33

Asterisk developer's documentation


event.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2007 - 2008, Digium, Inc.
00005  *
00006  * Russell Bryant <russell@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Internal generic event system
00022  *
00023  * \author Russell Bryant <russell@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 295710 $")
00029 
00030 #include "asterisk/_private.h"
00031 
00032 #include "asterisk/event.h"
00033 #include "asterisk/linkedlists.h"
00034 #include "asterisk/dlinkedlists.h"
00035 #include "asterisk/lock.h"
00036 #include "asterisk/utils.h"
00037 #include "asterisk/unaligned.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/taskprocessor.h"
00040 #include "asterisk/astobj2.h"
00041 #include "asterisk/cli.h"
00042 
00043 struct ast_taskprocessor *event_dispatcher;
00044 
00045 /*!
00046  * \brief An event information element
00047  *
00048  * \note The format of this structure is important.  Since these events may
00049  *       be sent directly over a network, changing this structure will break
00050  *       compatibility with older versions.  However, at this point, this code
00051  *       has not made it into a release, so it is still fair game for change.
00052  */
00053 struct ast_event_ie {
00054    enum ast_event_ie_type ie_type:16;
00055    /*! Total length of the IE payload */
00056    uint16_t ie_payload_len;
00057    unsigned char ie_payload[0];
00058 } __attribute__((packed));
00059 
00060 /*!
00061  * \brief The payload for a string information element
00062  */
00063 struct ast_event_ie_str_payload {
00064    /*! \brief A hash calculated with ast_str_hash(), to speed up comparisons */
00065    uint32_t hash;
00066    /*! \brief The actual string, null terminated */
00067    char str[1];
00068 } __attribute__((packed));
00069 
00070 /*!
00071  * \brief An event
00072  *
00073  * An ast_event consists of an event header (this structure), and zero or
00074  * more information elements defined by ast_event_ie.
00075  *
00076  * \note The format of this structure is important.  Since these events may
00077  *       be sent directly over a network, changing this structure will break
00078  *       compatibility with older versions.  However, at this point, this code
00079  *       has not made it into a release, so it is still fair game for change.
00080  */
00081 struct ast_event {
00082    /*! Event type */
00083    enum ast_event_type type:16;
00084    /*! Total length of the event */
00085    uint16_t event_len:16;
00086    /*! The data payload of the event, made up of information elements */
00087    unsigned char payload[0];
00088 } __attribute__((packed));
00089 
00090 
00091 /*!
00092  * \brief A holder for an event
00093  *
00094  * \details This struct used to have more of a purpose than it does now.
00095  * It is used to hold events in the event cache.  It can be completely removed
00096  * if one of these two things is done:
00097  *  - ast_event gets changed such that it never has to be realloc()d
00098  *  - astobj2 is updated so that you can realloc() an astobj2 object
00099  */
00100 struct ast_event_ref {
00101    struct ast_event *event;
00102 };
00103 
00104 struct ast_event_ie_val {
00105    AST_LIST_ENTRY(ast_event_ie_val) entry;
00106    enum ast_event_ie_type ie_type;
00107    enum ast_event_ie_pltype ie_pltype;
00108    union {
00109       uint32_t uint;
00110       struct {
00111          uint32_t hash;
00112          const char *str;
00113       };
00114       void *raw;
00115    } payload;
00116    size_t raw_datalen;
00117 };
00118 
00119 /*! \brief Event subscription */
00120 struct ast_event_sub {
00121    enum ast_event_type type;
00122    ast_event_cb_t cb;
00123    void *userdata;
00124    uint32_t uniqueid;
00125    AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
00126    AST_RWDLLIST_ENTRY(ast_event_sub) entry;
00127 };
00128 
00129 static uint32_t sub_uniqueid;
00130 
00131 /*! \brief Event subscriptions
00132  * The event subscribers are indexed by which event they are subscribed to */
00133 static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
00134 
00135 static int ast_event_cmp(void *obj, void *arg, int flags);
00136 static int ast_event_hash_mwi(const void *obj, const int flags);
00137 static int ast_event_hash_devstate(const void *obj, const int flags);
00138 static int ast_event_hash_devstate_change(const void *obj, const int flags);
00139 
00140 #ifdef LOW_MEMORY
00141 #define NUM_CACHE_BUCKETS 17
00142 #else
00143 #define NUM_CACHE_BUCKETS 563
00144 #endif
00145 
00146 #define MAX_CACHE_ARGS 8
00147 
00148 /*!
00149  * \brief Event types that are kept in the cache.
00150  */
00151 static struct {
00152    /*! 
00153     * \brief Container of cached events
00154     *
00155     * \details This gets allocated in ast_event_init() when Asterisk starts
00156     * for the event types declared as using the cache.
00157     */
00158    struct ao2_container *container;
00159    /*! \brief Event type specific hash function */
00160    ao2_hash_fn *hash_fn;
00161    /*!
00162     * \brief Information Elements used for caching
00163     *
00164     * \details This array is the set of information elements that will be unique
00165     * among all events in the cache for this event type.  When a new event gets
00166     * cached, a previous event with the same values for these information elements
00167     * will be replaced.
00168     */
00169    enum ast_event_ie_type cache_args[MAX_CACHE_ARGS];
00170 } ast_event_cache[AST_EVENT_TOTAL] = {
00171    [AST_EVENT_MWI] = {
00172       .hash_fn = ast_event_hash_mwi,
00173       .cache_args = { AST_EVENT_IE_MAILBOX, AST_EVENT_IE_CONTEXT },
00174    },
00175    [AST_EVENT_DEVICE_STATE] = {
00176       .hash_fn = ast_event_hash_devstate,
00177       .cache_args = { AST_EVENT_IE_DEVICE, },
00178    },
00179    [AST_EVENT_DEVICE_STATE_CHANGE] = {
00180       .hash_fn = ast_event_hash_devstate_change,
00181       .cache_args = { AST_EVENT_IE_DEVICE, AST_EVENT_IE_EID, },
00182    },
00183 };
00184 
00185 /*!
00186  * \brief Names of cached event types, for CLI tab completion
00187  *
00188  * \note These names must match what is in the event_names array.
00189  */
00190 static char * const cached_event_types[] = { "MWI", "DeviceState", "DeviceStateChange", NULL };
00191 
00192 /*!
00193  * The index of each entry _must_ match the event type number!
00194  */
00195 static struct event_name {
00196    enum ast_event_type type;
00197    const char *name;
00198 } event_names[] = {
00199    { 0, "" },
00200    { AST_EVENT_CUSTOM,              "Custom" },
00201    { AST_EVENT_MWI,                 "MWI" },
00202    { AST_EVENT_SUB,                 "Subscription" },
00203    { AST_EVENT_UNSUB,               "Unsubscription" },
00204    { AST_EVENT_DEVICE_STATE,        "DeviceState" },
00205    { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
00206 };
00207 
00208 /*!
00209  * The index of each entry _must_ match the event ie number!
00210  */
00211 static struct ie_map {
00212    enum ast_event_ie_type ie_type;
00213    enum ast_event_ie_pltype ie_pltype;
00214    const char *name;
00215 } ie_maps[] = {
00216    { 0, 0, "" },
00217    { AST_EVENT_IE_NEWMSGS,   AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
00218    { AST_EVENT_IE_OLDMSGS,   AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
00219    { AST_EVENT_IE_MAILBOX,   AST_EVENT_IE_PLTYPE_STR,  "Mailbox" },
00220    { AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
00221    { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
00222    { AST_EVENT_IE_EXISTS,    AST_EVENT_IE_PLTYPE_UINT, "Exists" },
00223    { AST_EVENT_IE_DEVICE,    AST_EVENT_IE_PLTYPE_STR,  "Device" },
00224    { AST_EVENT_IE_STATE,     AST_EVENT_IE_PLTYPE_UINT, "State" },
00225    { AST_EVENT_IE_CONTEXT,   AST_EVENT_IE_PLTYPE_STR,  "Context" },
00226    { AST_EVENT_IE_EID,       AST_EVENT_IE_PLTYPE_RAW,  "EntityID" },
00227 };
00228 
00229 const char *ast_event_get_type_name(const struct ast_event *event)
00230 {
00231    enum ast_event_type type;
00232 
00233    type = ast_event_get_type(event);
00234 
00235    if (type >= AST_EVENT_TOTAL || type < 0) {
00236       ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
00237       return "";
00238    }
00239 
00240    return event_names[type].name;
00241 }
00242 
00243 int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
00244 {
00245    int i;
00246 
00247    for (i = 0; i < ARRAY_LEN(event_names); i++) {
00248       if (strcasecmp(event_names[i].name, str))
00249          continue;
00250 
00251       *event_type = event_names[i].type;
00252       return 0;
00253    }
00254 
00255    return -1;
00256 }
00257 
00258 const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
00259 {
00260    if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
00261       ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
00262       return "";
00263    }
00264 
00265    if (ie_maps[ie_type].ie_type != ie_type) {
00266       ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
00267       return "";
00268    }
00269 
00270    return ie_maps[ie_type].name;
00271 }
00272 
00273 enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
00274 {
00275    if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
00276       ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
00277       return AST_EVENT_IE_PLTYPE_UNKNOWN;
00278    }
00279 
00280    if (ie_maps[ie_type].ie_type != ie_type) {
00281       ast_log(LOG_ERROR, "The ie type passed in does not match the ie type defined in the ie table.\n");
00282       return AST_EVENT_IE_PLTYPE_UNKNOWN;
00283    }
00284 
00285    return ie_maps[ie_type].ie_pltype;
00286 }
00287 
00288 int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
00289 {
00290    int i;
00291 
00292    for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
00293       if (strcasecmp(ie_maps[i].name, str))
00294          continue;
00295 
00296       *ie_type = ie_maps[i].ie_type;
00297       return 0;
00298    }
00299 
00300    return -1;
00301 }
00302 
00303 size_t ast_event_get_size(const struct ast_event *event)
00304 {
00305    size_t res;
00306 
00307    res = ntohs(event->event_len);
00308 
00309    return res;
00310 }
00311 
00312 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
00313 {
00314    switch (ie_val->ie_pltype) {
00315    case AST_EVENT_IE_PLTYPE_STR:
00316       ast_free((char *) ie_val->payload.str);
00317       break;
00318    case AST_EVENT_IE_PLTYPE_RAW:
00319       ast_free(ie_val->payload.raw);
00320       break;
00321    case AST_EVENT_IE_PLTYPE_UINT:
00322    case AST_EVENT_IE_PLTYPE_EXISTS:
00323    case AST_EVENT_IE_PLTYPE_UNKNOWN:
00324       break;
00325    }
00326 
00327    ast_free(ie_val);
00328 }
00329 
00330 /*!
00331  * \internal
00332  * \brief Check if an ie_val matches a subscription
00333  *
00334  * \param sub subscription to check against
00335  * \param ie_val IE value to check
00336  *
00337  * \retval 0 not matched
00338  * \retval non-zero matched
00339  */
00340 static int match_ie_val_to_sub(const struct ast_event_sub *sub, const struct ast_event_ie_val *ie_val)
00341 {
00342    const struct ast_event_ie_val *sub_ie_val;
00343    int res = 1;
00344 
00345    AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
00346       if (sub_ie_val->ie_type == ie_val->ie_type) {
00347          break;
00348       }
00349    }
00350 
00351    if (!sub_ie_val) {
00352       /* This subscriber doesn't care about this IE, so consider
00353        * it matched. */
00354       return 1;
00355    }
00356 
00357    switch (ie_val->ie_pltype) {
00358    case AST_EVENT_IE_PLTYPE_UINT:
00359       res = (ie_val->payload.uint != sub_ie_val->payload.uint);
00360       break;
00361    case AST_EVENT_IE_PLTYPE_STR:
00362       res = strcmp(ie_val->payload.str, sub_ie_val->payload.str);
00363       break;
00364    case AST_EVENT_IE_PLTYPE_RAW:
00365       res = memcmp(ie_val->payload.raw,
00366             sub_ie_val->payload.raw, ie_val->raw_datalen);
00367       break;
00368    case AST_EVENT_IE_PLTYPE_EXISTS:
00369    case AST_EVENT_IE_PLTYPE_UNKNOWN:
00370       break;
00371    }
00372 
00373    return res;
00374 }
00375 
00376 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00377 {
00378    va_list ap;
00379    enum ast_event_ie_type ie_type;
00380    enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00381    struct ast_event_ie_val *ie_val;
00382    struct ast_event_sub *sub;
00383    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00384    const enum ast_event_type event_types[] = { type, AST_EVENT_ALL };
00385    int i;
00386 
00387    if (type >= AST_EVENT_TOTAL) {
00388       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00389       return res;
00390    }
00391 
00392    va_start(ap, type);
00393    for (ie_type = va_arg(ap, enum ast_event_ie_type);
00394       ie_type != AST_EVENT_IE_END;
00395       ie_type = va_arg(ap, enum ast_event_ie_type))
00396    {
00397       struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00398       memset(ie_value, 0, sizeof(*ie_value));
00399       ie_value->ie_type = ie_type;
00400       ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00401       if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00402          ie_value->payload.uint = va_arg(ap, uint32_t);
00403       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00404          ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00405       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00406          void *data = va_arg(ap, void *);
00407          size_t datalen = va_arg(ap, size_t);
00408          ie_value->payload.raw = alloca(datalen);
00409          memcpy(ie_value->payload.raw, data, datalen);
00410          ie_value->raw_datalen = datalen;
00411       }
00412       AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00413    }
00414    va_end(ap);
00415 
00416    for (i = 0; i < ARRAY_LEN(event_types); i++) {
00417       AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
00418       AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
00419          AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00420             if (match_ie_val_to_sub(sub, ie_val)) {
00421                break;
00422             }
00423          }
00424 
00425          if (!ie_val) {
00426             /* Everything matched. */
00427             break;
00428          }
00429       }
00430       AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
00431       if (sub) {
00432          break;
00433       }
00434    }
00435 
00436    return sub ? AST_EVENT_SUB_EXISTS : AST_EVENT_SUB_NONE;
00437 }
00438 
00439 /*!
00440  * \internal
00441  * \brief Check if an ie_val matches an event
00442  *
00443  * \param event event to check against
00444  * \param ie_val IE value to check
00445  * \param event2 optional event, if specified, the value to compare against will be pulled
00446  *        from this event instead of from the ie_val structure.  In this case, only the IE
00447  *        type and payload type will be pulled from ie_val.
00448  *
00449  * \retval 0 not matched
00450  * \retval non-zero matched
00451  */
00452 static int match_ie_val(const struct ast_event *event,
00453       const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
00454 {
00455    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
00456       uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
00457       if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
00458          return 1;
00459       return 0;
00460    }
00461 
00462    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
00463       const char *str;
00464       uint32_t hash;
00465 
00466       hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
00467       if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
00468          return 0;
00469       }
00470 
00471       str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
00472       if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
00473          return 1;
00474       }
00475 
00476       return 0;
00477    }
00478 
00479    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00480       const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
00481       uint16_t ie_payload_len = event2 ? ast_event_get_ie_raw_payload_len(event2, ie_val->ie_type) : ie_val->raw_datalen;
00482 
00483       return (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_payload_len)) ? 1 : 0;
00484    }
00485 
00486    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
00487       if (ast_event_get_ie_raw(event, ie_val->ie_type))
00488          return 1;
00489       return 0;
00490    }
00491 
00492    return 0;
00493 }
00494 
00495 static int dump_cache_cb(void *obj, void *arg, int flags)
00496 {
00497    const struct ast_event_ref *event_ref = obj;
00498    const struct ast_event *event = event_ref->event;
00499    const struct ast_event_sub *event_sub = arg;
00500    struct ast_event_ie_val *ie_val = NULL;
00501 
00502    AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00503       if (!match_ie_val(event, ie_val, NULL)) {
00504          break;
00505       }
00506    }
00507 
00508    if (!ie_val) {
00509       /* All parameters were matched on this cache entry, so dump it */
00510       event_sub->cb(event, event_sub->userdata);
00511    }
00512 
00513    return 0;
00514 }
00515 
00516 /*! \brief Dump the event cache for the subscribed event type */
00517 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
00518 {
00519    ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
00520          dump_cache_cb, (void *) event_sub);
00521 }
00522 
00523 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
00524 {
00525    struct ast_event_ie_val *ie_val;
00526    struct ast_event *event;
00527 
00528    event = ast_event_new(AST_EVENT_SUB,
00529       AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00530       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00531       AST_EVENT_IE_END);
00532 
00533    if (!event)
00534       return NULL;
00535 
00536    AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00537       switch (ie_val->ie_pltype) {
00538       case AST_EVENT_IE_PLTYPE_UNKNOWN:
00539          break;
00540       case AST_EVENT_IE_PLTYPE_EXISTS:
00541          ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00542          break;
00543       case AST_EVENT_IE_PLTYPE_UINT:
00544          ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00545          break;
00546       case AST_EVENT_IE_PLTYPE_STR:
00547          ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00548          break;
00549       case AST_EVENT_IE_PLTYPE_RAW:
00550          ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00551          break;
00552       }
00553       if (!event)
00554          break;
00555    }
00556 
00557    return event;
00558 }
00559 
00560 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
00561 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00562 {
00563    struct ast_event *event;
00564    struct ast_event_sub *sub;
00565    enum ast_event_type event_type = -1;
00566    struct ast_event_ie_val *ie_val;
00567 
00568    if (event_sub->type != AST_EVENT_SUB)
00569       return;
00570 
00571    AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00572       if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00573          event_type = ie_val->payload.uint;
00574          break;
00575       }
00576    }
00577 
00578    if (event_type == -1)
00579       return;
00580 
00581    AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
00582    AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00583       if (event_sub == sub)
00584          continue;
00585 
00586       event = gen_sub_event(sub);
00587 
00588       if (!event)
00589          continue;
00590 
00591       event_sub->cb(event, event_sub->userdata);
00592 
00593       ast_event_destroy(event);
00594    }
00595    AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
00596 }
00597 
00598 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, 
00599    ast_event_cb_t cb, void *userdata)
00600 {
00601    struct ast_event_sub *sub;
00602 
00603    if (type < 0 || type >= AST_EVENT_TOTAL) {
00604       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00605       return NULL;
00606    }
00607 
00608    if (!(sub = ast_calloc(1, sizeof(*sub))))
00609       return NULL;
00610 
00611    sub->type = type;
00612    sub->cb = cb;
00613    sub->userdata = userdata;
00614    sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00615 
00616    return sub;
00617 }
00618 
00619 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
00620    enum ast_event_ie_type ie_type, uint32_t unsigned_int)
00621 {
00622    struct ast_event_ie_val *ie_val;
00623 
00624    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00625       return -1;
00626 
00627    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00628       return -1;
00629 
00630    ie_val->ie_type = ie_type;
00631    ie_val->payload.uint = unsigned_int;
00632    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
00633 
00634    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00635 
00636    return 0;
00637 }
00638 
00639 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
00640    enum ast_event_ie_type ie_type)
00641 {
00642    struct ast_event_ie_val *ie_val;
00643 
00644    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00645       return -1;
00646 
00647    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00648       return -1;
00649 
00650    ie_val->ie_type = ie_type;
00651    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
00652 
00653    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00654 
00655    return 0;
00656 }
00657 
00658 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,  
00659    enum ast_event_ie_type ie_type, const char *str)
00660 {
00661    struct ast_event_ie_val *ie_val;
00662 
00663    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00664       return -1;
00665 
00666    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00667       return -1;
00668 
00669    ie_val->ie_type = ie_type;
00670    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
00671 
00672    if (!(ie_val->payload.str = ast_strdup(str))) {
00673       ast_free(ie_val);
00674       return -1;
00675    }
00676 
00677    ie_val->payload.hash = ast_str_hash(str);
00678 
00679    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00680 
00681    return 0;
00682 }
00683 
00684 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,  
00685    enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
00686 {
00687    struct ast_event_ie_val *ie_val;
00688 
00689    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00690       return -1;
00691 
00692    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00693       return -1;
00694 
00695    ie_val->ie_type = ie_type;
00696    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
00697    ie_val->raw_datalen = raw_datalen;
00698 
00699    if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
00700       ast_free(ie_val);
00701       return -1;
00702    }
00703 
00704    memcpy(ie_val->payload.raw, data, raw_datalen);
00705 
00706    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00707 
00708    return 0;
00709 }
00710 
00711 int ast_event_sub_activate(struct ast_event_sub *sub)
00712 {
00713    if (ast_event_check_subscriber(AST_EVENT_SUB,
00714       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00715       AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00716       struct ast_event *event;
00717 
00718       event = gen_sub_event(sub);
00719 
00720       if (event)
00721          ast_event_queue(event);
00722    }
00723 
00724    AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00725    AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
00726    AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00727 
00728    return 0;
00729 }
00730 
00731 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
00732    void *userdata, ...)
00733 {
00734    va_list ap;
00735    enum ast_event_ie_type ie_type;
00736    struct ast_event_sub *sub;
00737 
00738    if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
00739       return NULL;
00740 
00741    va_start(ap, userdata);
00742    for (ie_type = va_arg(ap, enum ast_event_ie_type);
00743       ie_type != AST_EVENT_IE_END;
00744       ie_type = va_arg(ap, enum ast_event_ie_type))
00745    {
00746       enum ast_event_ie_pltype ie_pltype;
00747 
00748       ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00749 
00750       switch (ie_pltype) {
00751       case AST_EVENT_IE_PLTYPE_UNKNOWN:
00752          break;
00753       case AST_EVENT_IE_PLTYPE_UINT:
00754       {
00755          uint32_t unsigned_int = va_arg(ap, uint32_t);
00756          ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
00757          break;
00758       }
00759       case AST_EVENT_IE_PLTYPE_STR:
00760       {
00761          const char *str = va_arg(ap, const char *);
00762          ast_event_sub_append_ie_str(sub, ie_type, str);
00763          break;
00764       }
00765       case AST_EVENT_IE_PLTYPE_RAW:
00766       {
00767          void *data = va_arg(ap, void *);
00768          size_t data_len = va_arg(ap, size_t);
00769          ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
00770          break;
00771       }
00772       case AST_EVENT_IE_PLTYPE_EXISTS:
00773          ast_event_sub_append_ie_exists(sub, ie_type);
00774          break;
00775       }
00776    }
00777    va_end(ap);
00778 
00779    ast_event_sub_activate(sub);
00780 
00781    return sub;
00782 }
00783 
00784 void ast_event_sub_destroy(struct ast_event_sub *sub)
00785 {
00786    struct ast_event_ie_val *ie_val;
00787 
00788    while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
00789       ast_event_ie_val_destroy(ie_val);
00790 
00791    ast_free(sub);
00792 }
00793 
00794 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
00795 {
00796    struct ast_event *event;
00797 
00798    AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00799    AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
00800    AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00801 
00802    if (ast_event_check_subscriber(AST_EVENT_UNSUB,
00803       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00804       AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00805       
00806       event = ast_event_new(AST_EVENT_UNSUB,
00807          AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00808          AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00809          AST_EVENT_IE_END);
00810 
00811       if (event)
00812          ast_event_queue(event);
00813    }
00814 
00815    ast_event_sub_destroy(sub);
00816 
00817    return NULL;
00818 }
00819 
00820 int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00821 {
00822    int res = 0;
00823 
00824    iterator->event_len = ntohs(event->event_len);
00825    iterator->event = event;
00826    if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
00827       iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00828    } else {
00829       iterator->ie = NULL;
00830       res = -1;
00831    }
00832 
00833    return res;
00834 }
00835 
00836 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00837 {
00838    iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00839    return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00840 }
00841 
00842 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00843 {
00844    return ntohs(iterator->ie->ie_type);
00845 }
00846 
00847 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00848 {
00849    return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00850 }
00851 
00852 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00853 {
00854    const struct ast_event_ie_str_payload *str_payload;
00855 
00856    str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
00857 
00858    return str_payload ? str_payload->str : NULL;
00859 }
00860 
00861 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00862 {
00863    return iterator->ie->ie_payload;
00864 }
00865 
00866 uint16_t ast_event_iterator_get_ie_raw_payload_len(struct ast_event_iterator *iterator)
00867 {
00868    return ntohs(iterator->ie->ie_payload_len);
00869 }
00870 
00871 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00872 {
00873    return ntohs(event->type);
00874 }
00875 
00876 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00877 {
00878    const uint32_t *ie_val;
00879 
00880    ie_val = ast_event_get_ie_raw(event, ie_type);
00881 
00882    return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00883 }
00884 
00885 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
00886 {
00887    const struct ast_event_ie_str_payload *str_payload;
00888 
00889    str_payload = ast_event_get_ie_raw(event, ie_type);
00890 
00891    return str_payload ? str_payload->hash : 0;
00892 }
00893 
00894 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00895 {
00896    const struct ast_event_ie_str_payload *str_payload;
00897 
00898    str_payload = ast_event_get_ie_raw(event, ie_type);
00899 
00900    return str_payload ? str_payload->str : NULL;
00901 }
00902 
00903 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00904 {
00905    struct ast_event_iterator iterator;
00906    int res = 0;
00907 
00908    for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00909       if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
00910          return ast_event_iterator_get_ie_raw(&iterator);
00911       }
00912    }
00913 
00914    return NULL;
00915 }
00916 
00917 uint16_t ast_event_get_ie_raw_payload_len(const struct ast_event *event, enum ast_event_ie_type ie_type)
00918 {
00919    struct ast_event_iterator iterator;
00920    int res;
00921 
00922    for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00923       if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
00924          return ast_event_iterator_get_ie_raw_payload_len(&iterator);
00925       }
00926    }
00927 
00928    return 0;
00929 }
00930 
00931 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00932    const char *str)
00933 {
00934    struct ast_event_ie_str_payload *str_payload;
00935    size_t payload_len;
00936 
00937    payload_len = sizeof(*str_payload) + strlen(str);
00938    str_payload = alloca(payload_len);
00939 
00940    strcpy(str_payload->str, str);
00941    str_payload->hash = ast_str_hash(str);
00942 
00943    return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
00944 }
00945 
00946 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00947    uint32_t data)
00948 {
00949    data = htonl(data);
00950    return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00951 }
00952 
00953 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00954    const void *data, size_t data_len)
00955 {
00956    struct ast_event_ie *ie;
00957    unsigned int extra_len;
00958    uint16_t event_len;
00959 
00960    event_len = ntohs((*event)->event_len);
00961    extra_len = sizeof(*ie) + data_len;
00962 
00963    if (!(*event = ast_realloc(*event, event_len + extra_len)))
00964       return -1;
00965 
00966    ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00967    ie->ie_type = htons(ie_type);
00968    ie->ie_payload_len = htons(data_len);
00969    memcpy(ie->ie_payload, data, data_len);
00970 
00971    (*event)->event_len = htons(event_len + extra_len);
00972 
00973    return 0;
00974 }
00975 
00976 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00977 {
00978    va_list ap;
00979    struct ast_event *event;
00980    enum ast_event_ie_type ie_type;
00981    struct ast_event_ie_val *ie_val;
00982    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00983 
00984    /* Invalid type */
00985    if (type >= AST_EVENT_TOTAL) {
00986       ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00987          "type '%d'!\n", type);
00988       return NULL;
00989    }
00990 
00991    va_start(ap, type);
00992    for (ie_type = va_arg(ap, enum ast_event_ie_type);
00993       ie_type != AST_EVENT_IE_END;
00994       ie_type = va_arg(ap, enum ast_event_ie_type))
00995    {
00996       struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00997       memset(ie_value, 0, sizeof(*ie_value));
00998       ie_value->ie_type = ie_type;
00999       ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01000       if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
01001          ie_value->payload.uint = va_arg(ap, uint32_t);
01002       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
01003          ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
01004       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
01005          void *data = va_arg(ap, void *);
01006          size_t datalen = va_arg(ap, size_t);
01007          ie_value->payload.raw = alloca(datalen);
01008          memcpy(ie_value->payload.raw, data, datalen);
01009          ie_value->raw_datalen = datalen;
01010       }
01011       AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
01012    }
01013    va_end(ap);
01014 
01015    if (!(event = ast_calloc(1, sizeof(*event))))
01016       return NULL;
01017 
01018    event->type = htons(type);
01019    event->event_len = htons(sizeof(*event));
01020 
01021    AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
01022       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
01023          ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
01024       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
01025          ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
01026       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
01027          ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
01028 
01029       if (!event)
01030          break;
01031    }
01032 
01033    if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
01034       /* If the event is originating on this server, add the server's
01035        * entity ID to the event. */
01036       ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
01037    }
01038 
01039    return event;
01040 }
01041 
01042 void ast_event_destroy(struct ast_event *event)
01043 {
01044    ast_free(event);
01045 }
01046 
01047 static void ast_event_ref_destroy(void *obj)
01048 {
01049    struct ast_event_ref *event_ref = obj;
01050 
01051    ast_event_destroy(event_ref->event);
01052 }
01053 
01054 static struct ast_event *ast_event_dup(const struct ast_event *event)
01055 {
01056    struct ast_event *dup_event;
01057    uint16_t event_len;
01058 
01059    event_len = ast_event_get_size(event);
01060 
01061    if (!(dup_event = ast_calloc(1, event_len))) {
01062       return NULL;
01063    }
01064 
01065    memcpy(dup_event, event, event_len);
01066 
01067    return dup_event;
01068 }
01069 
01070 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
01071 {
01072    va_list ap;
01073    enum ast_event_ie_type ie_type;
01074    struct ast_event *dup_event = NULL;
01075    struct ast_event_ref *cached_event_ref;
01076    struct ast_event *cache_arg_event;
01077    struct ast_event_ref tmp_event_ref = {
01078       .event = NULL,
01079    };
01080    struct ao2_container *container = NULL;
01081 
01082    if (type >= AST_EVENT_TOTAL) {
01083       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01084       return NULL;
01085    }
01086 
01087    if (!(container = ast_event_cache[type].container)) {
01088       ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01089       return NULL;
01090    }
01091 
01092    if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01093       return NULL;
01094    }
01095 
01096    va_start(ap, type);
01097    for (ie_type = va_arg(ap, enum ast_event_ie_type);
01098       ie_type != AST_EVENT_IE_END;
01099       ie_type = va_arg(ap, enum ast_event_ie_type))
01100    {
01101       enum ast_event_ie_pltype ie_pltype;
01102 
01103       ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01104 
01105       switch (ie_pltype) {
01106       case AST_EVENT_IE_PLTYPE_UINT:
01107          ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01108          break;
01109       case AST_EVENT_IE_PLTYPE_STR:
01110          ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01111          break;
01112       case AST_EVENT_IE_PLTYPE_RAW:
01113       {
01114          void *data = va_arg(ap, void *);
01115          size_t datalen = va_arg(ap, size_t);
01116          ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01117       }
01118       case AST_EVENT_IE_PLTYPE_EXISTS:
01119          ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01120          break;
01121       case AST_EVENT_IE_PLTYPE_UNKNOWN:
01122          break;
01123       }
01124    }
01125    va_end(ap);
01126 
01127    tmp_event_ref.event = cache_arg_event;
01128 
01129    cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01130 
01131    ast_event_destroy(cache_arg_event);
01132    cache_arg_event = NULL;
01133 
01134    if (cached_event_ref) {
01135       dup_event = ast_event_dup(cached_event_ref->event);
01136       ao2_ref(cached_event_ref, -1);
01137       cached_event_ref = NULL;
01138    }
01139 
01140    return dup_event;
01141 }
01142 
01143 static struct ast_event_ref *alloc_event_ref(void)
01144 {
01145    return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01146 }
01147 
01148 /*! \brief Duplicate an event and add it to the cache
01149  * \note This assumes this index in to the cache is locked */
01150 static int ast_event_dup_and_cache(const struct ast_event *event)
01151 {
01152    struct ast_event *dup_event;
01153    struct ast_event_ref *event_ref;
01154 
01155    if (!(dup_event = ast_event_dup(event))) {
01156       return -1;
01157    }
01158 
01159    if (!(event_ref = alloc_event_ref())) {
01160       ast_event_destroy(dup_event);
01161       return -1;
01162    }
01163 
01164    event_ref->event = dup_event;
01165 
01166    ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
01167 
01168    ao2_ref(event_ref, -1);
01169 
01170    return 0;
01171 }
01172 
01173 int ast_event_queue_and_cache(struct ast_event *event)
01174 {
01175    struct ao2_container *container;
01176    struct ast_event_ref tmp_event_ref = {
01177       .event = event,
01178    };
01179    int res = -1;
01180 
01181    if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
01182       ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01183       goto queue_event;
01184    }
01185 
01186    /* Remove matches from the cache */
01187    ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01188          ast_event_cmp, &tmp_event_ref);
01189 
01190    res = ast_event_dup_and_cache(event);
01191 
01192 queue_event:
01193    return ast_event_queue(event) ? -1 : res;
01194 }
01195 
01196 static int handle_event(void *data)
01197 {
01198    struct ast_event_ref *event_ref = data;
01199    struct ast_event_sub *sub;
01200    const enum ast_event_type event_types[] = {
01201       ntohs(event_ref->event->type),
01202       AST_EVENT_ALL
01203    };
01204    int i;
01205 
01206    for (i = 0; i < ARRAY_LEN(event_types); i++) {
01207       AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
01208       AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
01209          struct ast_event_ie_val *ie_val;
01210          AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01211             if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01212                break;
01213             }
01214          }
01215          if (ie_val) {
01216             continue;
01217          }
01218          sub->cb(event_ref->event, sub->userdata);
01219       }
01220       AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
01221    }
01222 
01223    ao2_ref(event_ref, -1);
01224 
01225    return 0;
01226 }
01227 
01228 int ast_event_queue(struct ast_event *event)
01229 {
01230    struct ast_event_ref *event_ref;
01231    uint16_t host_event_type;
01232 
01233    host_event_type = ntohs(event->type);
01234 
01235    /* Invalid type */
01236    if (host_event_type >= AST_EVENT_TOTAL) {
01237       ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01238          "type '%d'!\n", host_event_type);
01239       return -1;
01240    }
01241 
01242    /* If nobody has subscribed to this event type, throw it away now */
01243    if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01244          == AST_EVENT_SUB_NONE) {
01245       ast_event_destroy(event);
01246       return 0;
01247    }
01248 
01249    if (!(event_ref = alloc_event_ref())) {
01250       return -1;
01251    }
01252 
01253    event_ref->event = event;
01254 
01255    return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01256 }
01257 
01258 static int ast_event_hash_mwi(const void *obj, const int flags)
01259 {
01260    const struct ast_event *event = obj;
01261    const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01262    const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01263 
01264    return ast_str_hash_add(context, ast_str_hash(mailbox));
01265 }
01266 
01267 /*!
01268  * \internal
01269  * \brief Hash function for AST_EVENT_DEVICE_STATE
01270  *
01271  * \param[in] obj an ast_event
01272  * \param[in] flags unused
01273  *
01274  * \return hash value
01275  */
01276 static int ast_event_hash_devstate(const void *obj, const int flags)
01277 {
01278    const struct ast_event *event = obj;
01279 
01280    return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01281 }
01282 
01283 /*!
01284  * \internal
01285  * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
01286  *
01287  * \param[in] obj an ast_event
01288  * \param[in] flags unused
01289  *
01290  * \return hash value
01291  */
01292 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01293 {
01294    const struct ast_event *event = obj;
01295 
01296    return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01297 }
01298 
01299 static int ast_event_hash(const void *obj, const int flags)
01300 {
01301    const struct ast_event_ref *event_ref;
01302    const struct ast_event *event;
01303    ao2_hash_fn *hash_fn;
01304 
01305    event_ref = obj;
01306    event = event_ref->event;
01307 
01308    if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01309       return 0;
01310    }
01311 
01312    return hash_fn(event, flags);
01313 }
01314 
01315 /*!
01316  * \internal
01317  * \brief Compare two events
01318  *
01319  * \param[in] obj the first event, as an ast_event_ref
01320  * \param[in] arg the second event, as an ast_event_ref
01321  * \param[in] flags unused
01322  *
01323  * \pre Both events must be the same type.
01324  * \pre The event type must be declared as a cached event type in ast_event_cache
01325  *
01326  * \details This function takes two events, and determines if they are considered
01327  * equivalent.  The values of information elements specified in the cache arguments
01328  * for the event type are used to determine if the events are equivalent.
01329  *
01330  * \retval 0 No match
01331  * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
01332  */
01333 static int ast_event_cmp(void *obj, void *arg, int flags)
01334 {
01335    struct ast_event_ref *event_ref, *event_ref2;
01336    struct ast_event *event, *event2;
01337    int res = CMP_MATCH;
01338    int i;
01339    enum ast_event_ie_type *cache_args;
01340 
01341    event_ref = obj;
01342    event = event_ref->event;
01343 
01344    event_ref2 = arg;
01345    event2 = event_ref2->event;
01346 
01347    cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01348 
01349    for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01350       struct ast_event_ie_val ie_val = {
01351          .ie_pltype = ast_event_get_ie_pltype(cache_args[i]),
01352          .ie_type = cache_args[i],
01353       };
01354 
01355       if (!match_ie_val(event, &ie_val, event2)) {
01356          res = 0;
01357          break;
01358       }
01359    }
01360 
01361    return res;
01362 }
01363 
01364 static void dump_raw_ie(struct ast_event_iterator *i, struct ast_cli_args *a)
01365 {
01366    char eid_buf[32];
01367    enum ast_event_ie_type ie_type;
01368    const char *ie_type_name;
01369 
01370    ie_type = ast_event_iterator_get_ie_type(i);
01371    ie_type_name = ast_event_get_ie_type_name(ie_type);
01372 
01373    switch (ie_type) {
01374    case AST_EVENT_IE_EID:
01375       ast_eid_to_str(eid_buf, sizeof(eid_buf), ast_event_iterator_get_ie_raw(i));
01376       ast_cli(a->fd, "%.30s: %s\n", ie_type_name, eid_buf);
01377       break;
01378    default:
01379       ast_cli(a->fd, "%s\n", ie_type_name);
01380       break;
01381    }
01382 }
01383 
01384 static int event_dump_cli(void *obj, void *arg, int flags)
01385 {
01386    const struct ast_event_ref *event_ref = obj;
01387    const struct ast_event *event = event_ref->event;
01388    struct ast_cli_args *a = arg;
01389    struct ast_event_iterator i;
01390 
01391    if (ast_event_iterator_init(&i, event)) {
01392       ast_cli(a->fd, "Failed to initialize event iterator.  :-(\n");
01393       return 0;
01394    }
01395 
01396    ast_cli(a->fd, "Event: %s\n", ast_event_get_type_name(event));
01397 
01398    do {
01399       enum ast_event_ie_type ie_type;
01400       enum ast_event_ie_pltype ie_pltype;
01401       const char *ie_type_name;
01402 
01403       ie_type = ast_event_iterator_get_ie_type(&i);
01404       ie_type_name = ast_event_get_ie_type_name(ie_type);
01405       ie_pltype = ast_event_get_ie_pltype(ie_type);
01406 
01407       switch (ie_pltype) {
01408       case AST_EVENT_IE_PLTYPE_UNKNOWN:
01409       case AST_EVENT_IE_PLTYPE_EXISTS:
01410          ast_cli(a->fd, "%s\n", ie_type_name);
01411          break;
01412       case AST_EVENT_IE_PLTYPE_STR:
01413          ast_cli(a->fd, "%.30s: %s\n", ie_type_name,
01414                ast_event_iterator_get_ie_str(&i));
01415          break;
01416       case AST_EVENT_IE_PLTYPE_UINT:
01417          ast_cli(a->fd, "%.30s: %u\n", ie_type_name,
01418                ast_event_iterator_get_ie_uint(&i));
01419          break;
01420       case AST_EVENT_IE_PLTYPE_RAW:
01421          dump_raw_ie(&i, a);
01422          break;
01423       }
01424    } while (!ast_event_iterator_next(&i));
01425 
01426    ast_cli(a->fd, "\n");
01427 
01428    return 0;
01429 }
01430 
01431 static char *event_dump_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01432 {
01433    enum ast_event_type event_type;
01434    enum ast_event_ie_type *cache_args;
01435    int i;
01436 
01437    switch (cmd) {
01438    case CLI_INIT:
01439       e->command = "event dump cache";
01440       e->usage =
01441          "Usage: event dump cache <event type>\n"
01442          "       Dump all of the cached events for the given event type.\n"
01443          "       This is primarily intended for debugging.\n";
01444       return NULL;
01445    case CLI_GENERATE:
01446       if (a->pos == 3) {
01447          return ast_cli_complete(a->word, cached_event_types, a->n);
01448       }
01449       return NULL;
01450    case CLI_HANDLER:
01451       break;
01452    }
01453 
01454    if (a->argc != e->args + 1) {
01455       return CLI_SHOWUSAGE;
01456    }
01457 
01458    if (ast_event_str_to_event_type(a->argv[e->args], &event_type)) {
01459       ast_cli(a->fd, "Invalid cached event type: '%s'\n", a->argv[e->args]);
01460       return CLI_SHOWUSAGE;
01461    }
01462 
01463    if (!ast_event_cache[event_type].container) {
01464       ast_cli(a->fd, "Event type '%s' has no cache.\n", a->argv[e->args]);
01465       return CLI_SUCCESS;
01466    }
01467 
01468    ast_cli(a->fd, "Event Type: %s\n", a->argv[e->args]);
01469    ast_cli(a->fd, "Cache Unique Keys:\n");
01470    cache_args = ast_event_cache[event_type].cache_args;
01471    for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01472       ast_cli(a->fd, "--> %s\n", ast_event_get_ie_type_name(cache_args[i]));
01473    }
01474 
01475    ast_cli(a->fd, "\n--- Begin Cache Dump ---\n\n");
01476    ao2_callback(ast_event_cache[event_type].container, OBJ_NODATA, event_dump_cli, a);
01477    ast_cli(a->fd, "--- End Cache Dump ---\n\n");
01478 
01479    return CLI_SUCCESS;
01480 }
01481 
01482 static struct ast_cli_entry event_cli[] = {
01483    AST_CLI_DEFINE(event_dump_cache, "Dump the internal event cache (for debugging)"),
01484 };
01485 
01486 int ast_event_init(void)
01487 {
01488    int i;
01489 
01490    for (i = 0; i < AST_EVENT_TOTAL; i++) {
01491       AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01492    }
01493 
01494    for (i = 0; i < AST_EVENT_TOTAL; i++) {
01495       if (!ast_event_cache[i].hash_fn) {
01496          /* This event type is not cached. */
01497          continue;
01498       }
01499 
01500       if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01501             ast_event_hash, ast_event_cmp))) {
01502          return -1;
01503       }
01504    }
01505 
01506    if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01507       return -1;
01508    }
01509 
01510    ast_cli_register_multiple(event_cli, ARRAY_LEN(event_cli));
01511 
01512    return 0;
01513 }