Tue Aug 24 2010 19:41:30

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: 269418 $")
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 int ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00813 {
00814    int res = 0;
00815 
00816    iterator->event_len = ntohs(event->event_len);
00817    iterator->event = event;
00818    if (iterator->event_len >= sizeof(*event) + sizeof(struct ast_event_ie)) {
00819       iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00820    } else {
00821       iterator->ie = NULL;
00822       res = -1;
00823    }
00824 
00825    return res;
00826 }
00827 
00828 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00829 {
00830    iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00831    return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00832 }
00833 
00834 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00835 {
00836    return ntohs(iterator->ie->ie_type);
00837 }
00838 
00839 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00840 {
00841    return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00842 }
00843 
00844 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00845 {
00846    const struct ast_event_ie_str_payload *str_payload;
00847 
00848    str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
00849 
00850    return str_payload ? str_payload->str : NULL;
00851 }
00852 
00853 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00854 {
00855    return iterator->ie->ie_payload;
00856 }
00857 
00858 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00859 {
00860    return ntohs(event->type);
00861 }
00862 
00863 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00864 {
00865    const uint32_t *ie_val;
00866 
00867    ie_val = ast_event_get_ie_raw(event, ie_type);
00868 
00869    return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00870 }
00871 
00872 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
00873 {
00874    const struct ast_event_ie_str_payload *str_payload;
00875 
00876    str_payload = ast_event_get_ie_raw(event, ie_type);
00877 
00878    return str_payload ? str_payload->hash : 0;
00879 }
00880 
00881 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00882 {
00883    const struct ast_event_ie_str_payload *str_payload;
00884 
00885    str_payload = ast_event_get_ie_raw(event, ie_type);
00886 
00887    return str_payload ? str_payload->str : NULL;
00888 }
00889 
00890 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00891 {
00892    struct ast_event_iterator iterator;
00893    int res = 0;
00894 
00895    for (res = ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00896       if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
00897          return ast_event_iterator_get_ie_raw(&iterator);
00898       }
00899    }
00900 
00901    return NULL;
00902 }
00903 
00904 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00905    const char *str)
00906 {
00907    struct ast_event_ie_str_payload *str_payload;
00908    size_t payload_len;
00909 
00910    payload_len = sizeof(*str_payload) + strlen(str);
00911    str_payload = alloca(payload_len);
00912 
00913    strcpy(str_payload->str, str);
00914    str_payload->hash = ast_str_hash(str);
00915 
00916    return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
00917 }
00918 
00919 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00920    uint32_t data)
00921 {
00922    data = htonl(data);
00923    return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00924 }
00925 
00926 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00927    const void *data, size_t data_len)
00928 {
00929    struct ast_event_ie *ie;
00930    unsigned int extra_len;
00931    uint16_t event_len;
00932 
00933    event_len = ntohs((*event)->event_len);
00934    extra_len = sizeof(*ie) + data_len;
00935 
00936    if (!(*event = ast_realloc(*event, event_len + extra_len)))
00937       return -1;
00938 
00939    ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00940    ie->ie_type = htons(ie_type);
00941    ie->ie_payload_len = htons(data_len);
00942    memcpy(ie->ie_payload, data, data_len);
00943 
00944    (*event)->event_len = htons(event_len + extra_len);
00945 
00946    return 0;
00947 }
00948 
00949 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00950 {
00951    va_list ap;
00952    struct ast_event *event;
00953    enum ast_event_ie_type ie_type;
00954    struct ast_event_ie_val *ie_val;
00955    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00956 
00957    /* Invalid type */
00958    if (type >= AST_EVENT_TOTAL) {
00959       ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00960          "type '%d'!\n", type);
00961       return NULL;
00962    }
00963 
00964    va_start(ap, type);
00965    for (ie_type = va_arg(ap, enum ast_event_ie_type);
00966       ie_type != AST_EVENT_IE_END;
00967       ie_type = va_arg(ap, enum ast_event_ie_type))
00968    {
00969       struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00970       memset(ie_value, 0, sizeof(*ie_value));
00971       ie_value->ie_type = ie_type;
00972       ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00973       if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00974          ie_value->payload.uint = va_arg(ap, uint32_t);
00975       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00976          ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00977       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00978          void *data = va_arg(ap, void *);
00979          size_t datalen = va_arg(ap, size_t);
00980          ie_value->payload.raw = alloca(datalen);
00981          memcpy(ie_value->payload.raw, data, datalen);
00982          ie_value->raw_datalen = datalen;
00983       }
00984       AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00985    }
00986    va_end(ap);
00987 
00988    if (!(event = ast_calloc(1, sizeof(*event))))
00989       return NULL;
00990 
00991    event->type = htons(type);
00992    event->event_len = htons(sizeof(*event));
00993 
00994    AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00995       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00996          ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00997       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00998          ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00999       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
01000          ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
01001 
01002       if (!event)
01003          break;
01004    }
01005 
01006    if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
01007       /* If the event is originating on this server, add the server's
01008        * entity ID to the event. */
01009       ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
01010    }
01011 
01012    return event;
01013 }
01014 
01015 void ast_event_destroy(struct ast_event *event)
01016 {
01017    ast_free(event);
01018 }
01019 
01020 static void ast_event_ref_destroy(void *obj)
01021 {
01022    struct ast_event_ref *event_ref = obj;
01023 
01024    ast_event_destroy(event_ref->event);
01025 }
01026 
01027 static struct ast_event *ast_event_dup(const struct ast_event *event)
01028 {
01029    struct ast_event *dup_event;
01030    uint16_t event_len;
01031 
01032    event_len = ast_event_get_size(event);
01033 
01034    if (!(dup_event = ast_calloc(1, event_len))) {
01035       return NULL;
01036    }
01037 
01038    memcpy(dup_event, event, event_len);
01039 
01040    return dup_event;
01041 }
01042 
01043 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
01044 {
01045    va_list ap;
01046    enum ast_event_ie_type ie_type;
01047    struct ast_event *dup_event = NULL;
01048    struct ast_event_ref *cached_event_ref;
01049    struct ast_event *cache_arg_event;
01050    struct ast_event_ref tmp_event_ref = {
01051       .event = NULL,
01052    };
01053    struct ao2_container *container = NULL;
01054 
01055    if (type >= AST_EVENT_TOTAL) {
01056       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01057       return NULL;
01058    }
01059 
01060    if (!(container = ast_event_cache[type].container)) {
01061       ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01062       return NULL;
01063    }
01064 
01065    if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01066       return NULL;
01067    }
01068 
01069    va_start(ap, type);
01070    for (ie_type = va_arg(ap, enum ast_event_ie_type);
01071       ie_type != AST_EVENT_IE_END;
01072       ie_type = va_arg(ap, enum ast_event_ie_type))
01073    {
01074       enum ast_event_ie_pltype ie_pltype;
01075 
01076       ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01077 
01078       switch (ie_pltype) {
01079       case AST_EVENT_IE_PLTYPE_UINT:
01080          ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01081          break;
01082       case AST_EVENT_IE_PLTYPE_STR:
01083          ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01084          break;
01085       case AST_EVENT_IE_PLTYPE_RAW:
01086       {
01087          void *data = va_arg(ap, void *);
01088          size_t datalen = va_arg(ap, size_t);
01089          ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01090       }
01091       case AST_EVENT_IE_PLTYPE_EXISTS:
01092          ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01093          break;
01094       case AST_EVENT_IE_PLTYPE_UNKNOWN:
01095          break;
01096       }
01097    }
01098    va_end(ap);
01099 
01100    tmp_event_ref.event = cache_arg_event;
01101 
01102    cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01103 
01104    ast_event_destroy(cache_arg_event);
01105    cache_arg_event = NULL;
01106 
01107    if (cached_event_ref) {
01108       dup_event = ast_event_dup(cached_event_ref->event);
01109       ao2_ref(cached_event_ref, -1);
01110       cached_event_ref = NULL;
01111    }
01112 
01113    return dup_event;
01114 }
01115 
01116 static struct ast_event_ref *alloc_event_ref(void)
01117 {
01118    return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01119 }
01120 
01121 /*! \brief Duplicate an event and add it to the cache
01122  * \note This assumes this index in to the cache is locked */
01123 static int ast_event_dup_and_cache(const struct ast_event *event)
01124 {
01125    struct ast_event *dup_event;
01126    struct ast_event_ref *event_ref;
01127 
01128    if (!(dup_event = ast_event_dup(event))) {
01129       return -1;
01130    }
01131 
01132    if (!(event_ref = alloc_event_ref())) {
01133       ast_event_destroy(dup_event);
01134       return -1;
01135    }
01136 
01137    event_ref->event = dup_event;
01138 
01139    ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
01140 
01141    ao2_ref(event_ref, -1);
01142 
01143    return 0;
01144 }
01145 
01146 int ast_event_queue_and_cache(struct ast_event *event)
01147 {
01148    struct ao2_container *container;
01149    struct ast_event_ref tmp_event_ref = {
01150       .event = event,
01151    };
01152    int res = -1;
01153 
01154    if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
01155       ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01156       goto queue_event;
01157    }
01158 
01159    /* Remove matches from the cache */
01160    ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01161          ast_event_cmp, &tmp_event_ref);
01162 
01163    res = ast_event_dup_and_cache(event);
01164 
01165 queue_event:
01166    return ast_event_queue(event) ? -1 : res;
01167 }
01168 
01169 static int handle_event(void *data)
01170 {
01171    struct ast_event_ref *event_ref = data;
01172    struct ast_event_sub *sub;
01173    const enum ast_event_type event_types[] = {
01174       ntohs(event_ref->event->type),
01175       AST_EVENT_ALL
01176    };
01177    int i;
01178 
01179    for (i = 0; i < ARRAY_LEN(event_types); i++) {
01180       AST_RWDLLIST_RDLOCK(&ast_event_subs[event_types[i]]);
01181       AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_types[i]], sub, entry) {
01182          struct ast_event_ie_val *ie_val;
01183          AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01184             if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01185                break;
01186             }
01187          }
01188          if (ie_val) {
01189             continue;
01190          }
01191          sub->cb(event_ref->event, sub->userdata);
01192       }
01193       AST_RWDLLIST_UNLOCK(&ast_event_subs[event_types[i]]);
01194    }
01195 
01196    ao2_ref(event_ref, -1);
01197 
01198    return 0;
01199 }
01200 
01201 int ast_event_queue(struct ast_event *event)
01202 {
01203    struct ast_event_ref *event_ref;
01204    uint16_t host_event_type;
01205 
01206    host_event_type = ntohs(event->type);
01207 
01208    /* Invalid type */
01209    if (host_event_type >= AST_EVENT_TOTAL) {
01210       ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01211          "type '%d'!\n", host_event_type);
01212       return -1;
01213    }
01214 
01215    /* If nobody has subscribed to this event type, throw it away now */
01216    if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01217          == AST_EVENT_SUB_NONE) {
01218       ast_event_destroy(event);
01219       return 0;
01220    }
01221 
01222    if (!(event_ref = alloc_event_ref())) {
01223       return -1;
01224    }
01225 
01226    event_ref->event = event;
01227 
01228    return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01229 }
01230 
01231 static int ast_event_hash_mwi(const void *obj, const int flags)
01232 {
01233    const struct ast_event *event = obj;
01234    const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01235    const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01236 
01237    return ast_str_hash_add(context, ast_str_hash(mailbox));
01238 }
01239 
01240 /*!
01241  * \internal
01242  * \brief Hash function for AST_EVENT_DEVICE_STATE
01243  *
01244  * \param[in] obj an ast_event
01245  * \param[in] flags unused
01246  *
01247  * \return hash value
01248  */
01249 static int ast_event_hash_devstate(const void *obj, const int flags)
01250 {
01251    const struct ast_event *event = obj;
01252 
01253    return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01254 }
01255 
01256 /*!
01257  * \internal
01258  * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
01259  *
01260  * \param[in] obj an ast_event
01261  * \param[in] flags unused
01262  *
01263  * \return hash value
01264  */
01265 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01266 {
01267    const struct ast_event *event = obj;
01268 
01269    return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01270 }
01271 
01272 static int ast_event_hash(const void *obj, const int flags)
01273 {
01274    const struct ast_event_ref *event_ref;
01275    const struct ast_event *event;
01276    ao2_hash_fn *hash_fn;
01277 
01278    event_ref = obj;
01279    event = event_ref->event;
01280 
01281    if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01282       return 0;
01283    }
01284 
01285    return hash_fn(event, flags);
01286 }
01287 
01288 /*!
01289  * \internal
01290  * \brief Compare two events
01291  *
01292  * \param[in] obj the first event, as an ast_event_ref
01293  * \param[in] arg the second event, as an ast_event_ref
01294  * \param[in] flags unused
01295  *
01296  * \pre Both events must be the same type.
01297  * \pre The event type must be declared as a cached event type in ast_event_cache
01298  *
01299  * \details This function takes two events, and determines if they are considered
01300  * equivalent.  The values of information elements specified in the cache arguments
01301  * for the event type are used to determine if the events are equivalent.
01302  *
01303  * \retval 0 No match
01304  * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
01305  */
01306 static int ast_event_cmp(void *obj, void *arg, int flags)
01307 {
01308    struct ast_event_ref *event_ref, *event_ref2;
01309    struct ast_event *event, *event2;
01310    int res = CMP_MATCH;
01311    int i;
01312    enum ast_event_ie_type *cache_args;
01313 
01314    event_ref = obj;
01315    event = event_ref->event;
01316 
01317    event_ref2 = arg;
01318    event2 = event_ref2->event;
01319 
01320    cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01321 
01322    for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01323       struct ast_event_ie_val ie_val = {
01324          .ie_pltype = ast_event_get_ie_pltype(cache_args[i]),
01325          .ie_type = cache_args[i],
01326       };
01327 
01328       if (!match_ie_val(event, &ie_val, event2)) {
01329          res = 0;
01330          break;
01331       }
01332    }
01333 
01334    return res;
01335 }
01336 
01337 int ast_event_init(void)
01338 {
01339    int i;
01340 
01341    for (i = 0; i < AST_EVENT_TOTAL; i++) {
01342       AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01343    }
01344 
01345    for (i = 0; i < AST_EVENT_TOTAL; i++) {
01346       if (!ast_event_cache[i].hash_fn) {
01347          /* This event type is not cached. */
01348          continue;
01349       }
01350 
01351       if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01352             ast_event_hash, ast_event_cmp))) {
01353          return -1;
01354       }
01355    }
01356 
01357    if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01358       return -1;
01359    }
01360 
01361    return 0;
01362 }