Mon Sep 20 2010 00:22:38

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