Fri Jun 19 12:09:43 2009

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: 184631 $")
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 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00323 {
00324    va_list ap;
00325    enum ast_event_ie_type ie_type;
00326    enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00327    struct ast_event_ie_val *ie_val, *sub_ie_val;
00328    struct ast_event_sub *sub;
00329    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00330 
00331    if (type >= AST_EVENT_TOTAL) {
00332       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00333       return res;
00334    }
00335 
00336    va_start(ap, type);
00337    for (ie_type = va_arg(ap, enum ast_event_type);
00338       ie_type != AST_EVENT_IE_END;
00339       ie_type = va_arg(ap, enum ast_event_type))
00340    {
00341       struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00342       memset(ie_value, 0, sizeof(*ie_value));
00343       ie_value->ie_type = ie_type;
00344       ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00345       if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00346          ie_value->payload.uint = va_arg(ap, uint32_t);
00347       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00348          ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00349       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00350          void *data = va_arg(ap, void *);
00351          size_t datalen = va_arg(ap, size_t);
00352          ie_value->payload.raw = alloca(datalen);
00353          memcpy(ie_value->payload.raw, data, datalen);
00354          ie_value->raw_datalen = datalen;
00355       }
00356       AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00357    }
00358    va_end(ap);
00359 
00360    AST_RWDLLIST_RDLOCK(&ast_event_subs[type]);
00361    AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
00362       AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00363          AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
00364             if (sub_ie_val->ie_type == ie_val->ie_type)
00365                break;
00366          }
00367          if (!sub_ie_val) {
00368             if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00369                break;
00370             continue;
00371          }
00372          /* The subscriber doesn't actually care what the value is */
00373          if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00374             continue;
00375          if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00376             ie_val->payload.uint != sub_ie_val->payload.uint)
00377             break;
00378          if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00379             strcmp(ie_val->payload.str, sub_ie_val->payload.str))
00380             break;
00381          if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
00382             memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
00383             break;
00384       }
00385       if (!ie_val)
00386          break;
00387    }
00388    AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
00389 
00390    if (sub) /* All parameters were matched */
00391       return AST_EVENT_SUB_EXISTS;
00392 
00393    AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
00394    if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
00395       res = AST_EVENT_SUB_EXISTS;
00396    AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
00397 
00398    return res;
00399 }
00400 
00401 static int match_ie_val(const struct ast_event *event,
00402       const struct ast_event_ie_val *ie_val, const struct ast_event *event2)
00403 {
00404    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
00405       uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
00406       if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
00407          return 1;
00408       return 0;
00409    }
00410 
00411    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
00412       const char *str;
00413       uint32_t hash;
00414 
00415       hash = event2 ? ast_event_get_ie_str_hash(event2, ie_val->ie_type) : ie_val->payload.hash;
00416       if (hash != ast_event_get_ie_str_hash(event, ie_val->ie_type)) {
00417          return 0;
00418       }
00419 
00420       str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
00421       if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type))) {
00422          return 1;
00423       }
00424 
00425       return 0;
00426    }
00427 
00428    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00429       const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
00430       if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
00431          return 1;
00432       return 0;
00433    }
00434 
00435    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
00436       if (ast_event_get_ie_raw(event, ie_val->ie_type))
00437          return 1;
00438       return 0;
00439    }
00440 
00441    return 0;
00442 }
00443 
00444 static int dump_cache_cb(void *obj, void *arg, int flags)
00445 {
00446    const struct ast_event_ref *event_ref = obj;
00447    const struct ast_event *event = event_ref->event;
00448    const struct ast_event_sub *event_sub = arg;
00449    struct ast_event_ie_val *ie_val = NULL;
00450 
00451    AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00452       if (!match_ie_val(event, ie_val, NULL)) {
00453          break;
00454       }
00455    }
00456 
00457    if (!ie_val) {
00458       /* All parameters were matched on this cache entry, so dump it */
00459       event_sub->cb(event, event_sub->userdata);
00460    }
00461 
00462    return 0;
00463 }
00464 
00465 /*! \brief Dump the event cache for the subscribed event type */
00466 void ast_event_dump_cache(const struct ast_event_sub *event_sub)
00467 {
00468    ao2_callback(ast_event_cache[event_sub->type].container, OBJ_NODATA,
00469          dump_cache_cb, (void *) event_sub);
00470 }
00471 
00472 static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
00473 {
00474    struct ast_event_ie_val *ie_val;
00475    struct ast_event *event;
00476 
00477    event = ast_event_new(AST_EVENT_SUB,
00478       AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00479       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00480       AST_EVENT_IE_END);
00481 
00482    if (!event)
00483       return NULL;
00484 
00485    AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00486       switch (ie_val->ie_pltype) {
00487       case AST_EVENT_IE_PLTYPE_UNKNOWN:
00488          break;
00489       case AST_EVENT_IE_PLTYPE_EXISTS:
00490          ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00491          break;
00492       case AST_EVENT_IE_PLTYPE_UINT:
00493          ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00494          break;
00495       case AST_EVENT_IE_PLTYPE_STR:
00496          ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00497          break;
00498       case AST_EVENT_IE_PLTYPE_RAW:
00499          ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00500          break;
00501       }
00502       if (!event)
00503          break;
00504    }
00505 
00506    return event;
00507 }
00508 
00509 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
00510 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00511 {
00512    struct ast_event *event;
00513    struct ast_event_sub *sub;
00514    enum ast_event_type event_type = -1;
00515    struct ast_event_ie_val *ie_val;
00516 
00517    if (event_sub->type != AST_EVENT_SUB)
00518       return;
00519 
00520    AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00521       if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00522          event_type = ie_val->payload.uint;
00523          break;
00524       }
00525    }
00526 
00527    if (event_type == -1)
00528       return;
00529 
00530    AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
00531    AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00532       if (event_sub == sub)
00533          continue;
00534 
00535       event = gen_sub_event(sub);
00536 
00537       if (!event)
00538          continue;
00539 
00540       event_sub->cb(event, event_sub->userdata);
00541 
00542       ast_event_destroy(event);
00543    }
00544    AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
00545 }
00546 
00547 struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, 
00548    ast_event_cb_t cb, void *userdata)
00549 {
00550    struct ast_event_sub *sub;
00551 
00552    if (type < 0 || type >= AST_EVENT_TOTAL) {
00553       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00554       return NULL;
00555    }
00556 
00557    if (!(sub = ast_calloc(1, sizeof(*sub))))
00558       return NULL;
00559 
00560    sub->type = type;
00561    sub->cb = cb;
00562    sub->userdata = userdata;
00563    sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00564 
00565    return sub;
00566 }
00567 
00568 int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
00569    enum ast_event_ie_type ie_type, uint32_t unsigned_int)
00570 {
00571    struct ast_event_ie_val *ie_val;
00572 
00573    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00574       return -1;
00575 
00576    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00577       return -1;
00578 
00579    ie_val->ie_type = ie_type;
00580    ie_val->payload.uint = unsigned_int;
00581    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
00582 
00583    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00584 
00585    return 0;
00586 }
00587 
00588 int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
00589    enum ast_event_ie_type ie_type)
00590 {
00591    struct ast_event_ie_val *ie_val;
00592 
00593    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00594       return -1;
00595 
00596    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00597       return -1;
00598 
00599    ie_val->ie_type = ie_type;
00600    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
00601 
00602    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00603 
00604    return 0;
00605 }
00606 
00607 int ast_event_sub_append_ie_str(struct ast_event_sub *sub,  
00608    enum ast_event_ie_type ie_type, const char *str)
00609 {
00610    struct ast_event_ie_val *ie_val;
00611 
00612    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00613       return -1;
00614 
00615    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00616       return -1;
00617 
00618    ie_val->ie_type = ie_type;
00619    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
00620 
00621    if (!(ie_val->payload.str = ast_strdup(str))) {
00622       ast_free(ie_val);
00623       return -1;
00624    }
00625 
00626    ie_val->payload.hash = ast_str_hash(str);
00627 
00628    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00629 
00630    return 0;
00631 }
00632 
00633 int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,  
00634    enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
00635 {
00636    struct ast_event_ie_val *ie_val;
00637 
00638    if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
00639       return -1;
00640 
00641    if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00642       return -1;
00643 
00644    ie_val->ie_type = ie_type;
00645    ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
00646    ie_val->raw_datalen = raw_datalen;
00647 
00648    if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
00649       ast_free(ie_val);
00650       return -1;
00651    }
00652 
00653    memcpy(ie_val->payload.raw, data, raw_datalen);
00654 
00655    AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00656 
00657    return 0;
00658 }
00659 
00660 int ast_event_sub_activate(struct ast_event_sub *sub)
00661 {
00662    if (ast_event_check_subscriber(AST_EVENT_SUB,
00663       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00664       AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00665       struct ast_event *event;
00666 
00667       event = gen_sub_event(sub);
00668 
00669       if (event)
00670          ast_event_queue(event);
00671    }
00672 
00673    AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00674    AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
00675    AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00676 
00677    return 0;
00678 }
00679 
00680 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
00681    void *userdata, ...)
00682 {
00683    va_list ap;
00684    enum ast_event_ie_type ie_type;
00685    struct ast_event_sub *sub;
00686 
00687    if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
00688       return NULL;
00689 
00690    va_start(ap, userdata);
00691    for (ie_type = va_arg(ap, enum ast_event_type);
00692       ie_type != AST_EVENT_IE_END;
00693       ie_type = va_arg(ap, enum ast_event_type))
00694    {
00695       enum ast_event_ie_pltype ie_pltype;
00696 
00697       ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00698 
00699       switch (ie_pltype) {
00700       case AST_EVENT_IE_PLTYPE_UNKNOWN:
00701          break;
00702       case AST_EVENT_IE_PLTYPE_UINT:
00703       {
00704          uint32_t unsigned_int = va_arg(ap, uint32_t);
00705          ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
00706          break;
00707       }
00708       case AST_EVENT_IE_PLTYPE_STR:
00709       {
00710          const char *str = va_arg(ap, const char *);
00711          ast_event_sub_append_ie_str(sub, ie_type, str);
00712          break;
00713       }
00714       case AST_EVENT_IE_PLTYPE_RAW:
00715       {
00716          void *data = va_arg(ap, void *);
00717          size_t data_len = va_arg(ap, size_t);
00718          ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
00719          break;
00720       }
00721       case AST_EVENT_IE_PLTYPE_EXISTS:
00722          ast_event_sub_append_ie_exists(sub, ie_type);
00723          break;
00724       }
00725    }
00726    va_end(ap);
00727 
00728    ast_event_sub_activate(sub);
00729 
00730    return sub;
00731 }
00732 
00733 void ast_event_sub_destroy(struct ast_event_sub *sub)
00734 {
00735    struct ast_event_ie_val *ie_val;
00736 
00737    while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
00738       ast_event_ie_val_destroy(ie_val);
00739 
00740    ast_free(sub);
00741 }
00742 
00743 struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
00744 {
00745    struct ast_event *event;
00746 
00747    AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
00748    AST_DLLIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
00749    AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
00750 
00751    if (ast_event_check_subscriber(AST_EVENT_UNSUB,
00752       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00753       AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00754       
00755       event = ast_event_new(AST_EVENT_UNSUB,
00756          AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00757          AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00758          AST_EVENT_IE_END);
00759 
00760       if (event)
00761          ast_event_queue(event);
00762    }
00763 
00764    ast_event_sub_destroy(sub);
00765 
00766    return NULL;
00767 }
00768 
00769 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00770 {
00771    iterator->event_len = ntohs(event->event_len);
00772    iterator->event = event;
00773    iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00774    return;
00775 }
00776 
00777 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00778 {
00779    iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00780    return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00781 }
00782 
00783 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00784 {
00785    return ntohs(iterator->ie->ie_type);
00786 }
00787 
00788 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00789 {
00790    return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00791 }
00792 
00793 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00794 {
00795    const struct ast_event_ie_str_payload *str_payload;
00796 
00797    str_payload = (struct ast_event_ie_str_payload *) iterator->ie->ie_payload;
00798 
00799    return str_payload->str;
00800 }
00801 
00802 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00803 {
00804    return iterator->ie->ie_payload;
00805 }
00806 
00807 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00808 {
00809    return ntohs(event->type);
00810 }
00811 
00812 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00813 {
00814    const uint32_t *ie_val;
00815 
00816    ie_val = ast_event_get_ie_raw(event, ie_type);
00817 
00818    return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00819 }
00820 
00821 uint32_t ast_event_get_ie_str_hash(const struct ast_event *event, enum ast_event_ie_type ie_type)
00822 {
00823    const struct ast_event_ie_str_payload *str_payload;
00824 
00825    str_payload = ast_event_get_ie_raw(event, ie_type);
00826 
00827    return str_payload->hash;
00828 }
00829 
00830 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00831 {
00832    const struct ast_event_ie_str_payload *str_payload;
00833 
00834    str_payload = ast_event_get_ie_raw(event, ie_type);
00835 
00836    return str_payload->str;
00837 }
00838 
00839 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00840 {
00841    struct ast_event_iterator iterator;
00842    int res = 0;
00843 
00844    for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00845       if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
00846          return ast_event_iterator_get_ie_raw(&iterator);
00847    }
00848 
00849    return NULL;
00850 }
00851 
00852 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00853    const char *str)
00854 {
00855    struct ast_event_ie_str_payload *str_payload;
00856    size_t payload_len;
00857 
00858    payload_len = sizeof(*str_payload) + strlen(str);
00859    str_payload = alloca(payload_len);
00860 
00861    strcpy(str_payload->str, str);
00862    str_payload->hash = ast_str_hash(str);
00863 
00864    return ast_event_append_ie_raw(event, ie_type, str_payload, payload_len);
00865 }
00866 
00867 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00868    uint32_t data)
00869 {
00870    data = htonl(data);
00871    return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00872 }
00873 
00874 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00875    const void *data, size_t data_len)
00876 {
00877    struct ast_event_ie *ie;
00878    unsigned int extra_len;
00879    uint16_t event_len;
00880 
00881    event_len = ntohs((*event)->event_len);
00882    extra_len = sizeof(*ie) + data_len;
00883 
00884    if (!(*event = ast_realloc(*event, event_len + extra_len)))
00885       return -1;
00886 
00887    ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00888    ie->ie_type = htons(ie_type);
00889    ie->ie_payload_len = htons(data_len);
00890    memcpy(ie->ie_payload, data, data_len);
00891 
00892    (*event)->event_len = htons(event_len + extra_len);
00893 
00894    return 0;
00895 }
00896 
00897 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00898 {
00899    va_list ap;
00900    struct ast_event *event;
00901    enum ast_event_type ie_type;
00902    struct ast_event_ie_val *ie_val;
00903    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00904 
00905    /* Invalid type */
00906    if (type >= AST_EVENT_TOTAL) {
00907       ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00908          "type '%d'!\n", type);
00909       return NULL;
00910    }
00911 
00912    va_start(ap, type);
00913    for (ie_type = va_arg(ap, enum ast_event_type);
00914       ie_type != AST_EVENT_IE_END;
00915       ie_type = va_arg(ap, enum ast_event_type))
00916    {
00917       struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
00918       memset(ie_value, 0, sizeof(*ie_value));
00919       ie_value->ie_type = ie_type;
00920       ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00921       if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00922          ie_value->payload.uint = va_arg(ap, uint32_t);
00923       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00924          ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
00925       else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
00926          void *data = va_arg(ap, void *);
00927          size_t datalen = va_arg(ap, size_t);
00928          ie_value->payload.raw = alloca(datalen);
00929          memcpy(ie_value->payload.raw, data, datalen);
00930          ie_value->raw_datalen = datalen;
00931       }
00932       AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
00933    }
00934    va_end(ap);
00935 
00936    if (!(event = ast_calloc(1, sizeof(*event))))
00937       return NULL;
00938 
00939    event->type = htons(type);
00940    event->event_len = htons(sizeof(*event));
00941 
00942    AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00943       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00944          ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00945       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00946          ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00947       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
00948          ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
00949 
00950       if (!event)
00951          break;
00952    }
00953 
00954    if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
00955       /* If the event is originating on this server, add the server's
00956        * entity ID to the event. */
00957       ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &ast_eid_default, sizeof(ast_eid_default));
00958    }
00959 
00960    return event;
00961 }
00962 
00963 void ast_event_destroy(struct ast_event *event)
00964 {
00965    ast_free(event);
00966 }
00967 
00968 static void ast_event_ref_destroy(void *obj)
00969 {
00970    struct ast_event_ref *event_ref = obj;
00971 
00972    ast_event_destroy(event_ref->event);
00973 }
00974 
00975 static struct ast_event *ast_event_dup(const struct ast_event *event)
00976 {
00977    struct ast_event *dup_event;
00978    uint16_t event_len;
00979 
00980    event_len = ast_event_get_size(event);
00981 
00982    if (!(dup_event = ast_calloc(1, event_len))) {
00983       return NULL;
00984    }
00985 
00986    memcpy(dup_event, event, event_len);
00987 
00988    return dup_event;
00989 }
00990 
00991 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
00992 {
00993    va_list ap;
00994    enum ast_event_ie_type ie_type;
00995    struct ast_event *dup_event = NULL;
00996    struct ast_event_ref *cached_event_ref;
00997    struct ast_event *cache_arg_event;
00998    struct ast_event_ref tmp_event_ref = {
00999       .event = NULL,
01000    };
01001    struct ao2_container *container = NULL;
01002 
01003    if (type >= AST_EVENT_TOTAL) {
01004       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
01005       return NULL;
01006    }
01007 
01008    if (!(container = ast_event_cache[type].container)) {
01009       ast_log(LOG_ERROR, "%u is not a cached event type\n", type);
01010       return NULL;
01011    }
01012 
01013    if (!(cache_arg_event = ast_event_new(type, AST_EVENT_IE_END))) {
01014       return NULL;
01015    }
01016 
01017    va_start(ap, type);
01018    for (ie_type = va_arg(ap, enum ast_event_type);
01019       ie_type != AST_EVENT_IE_END;
01020       ie_type = va_arg(ap, enum ast_event_type))
01021    {
01022       enum ast_event_ie_pltype ie_pltype;
01023 
01024       ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
01025 
01026       switch (ie_pltype) {
01027       case AST_EVENT_IE_PLTYPE_UINT:
01028          ast_event_append_ie_uint(&cache_arg_event, ie_type, va_arg(ap, uint32_t));
01029          break;
01030       case AST_EVENT_IE_PLTYPE_STR:
01031          ast_event_append_ie_str(&cache_arg_event, ie_type, va_arg(ap, const char *));
01032          break;
01033       case AST_EVENT_IE_PLTYPE_RAW:
01034       {
01035          void *data = va_arg(ap, void *);
01036          size_t datalen = va_arg(ap, size_t);
01037          ast_event_append_ie_raw(&cache_arg_event, ie_type, data, datalen);
01038       }
01039       case AST_EVENT_IE_PLTYPE_EXISTS:
01040          ast_log(LOG_WARNING, "PLTYPE_EXISTS not supported by this function\n");
01041          break;
01042       case AST_EVENT_IE_PLTYPE_UNKNOWN:
01043          break;
01044       }
01045    }
01046    va_end(ap);
01047 
01048    tmp_event_ref.event = cache_arg_event;
01049 
01050    cached_event_ref = ao2_find(container, &tmp_event_ref, OBJ_POINTER);
01051 
01052    ast_event_destroy(cache_arg_event);
01053    cache_arg_event = NULL;
01054 
01055    if (cached_event_ref) {
01056       dup_event = ast_event_dup(cached_event_ref->event);
01057       ao2_ref(cached_event_ref, -1);
01058       cached_event_ref = NULL;
01059    }
01060 
01061    return dup_event;
01062 }
01063 
01064 static struct ast_event_ref *alloc_event_ref(void)
01065 {
01066    return ao2_alloc(sizeof(struct ast_event_ref), ast_event_ref_destroy);
01067 }
01068 
01069 /*! \brief Duplicate an event and add it to the cache
01070  * \note This assumes this index in to the cache is locked */
01071 static int attribute_unused ast_event_dup_and_cache(const struct ast_event *event)
01072 {
01073    struct ast_event *dup_event;
01074    struct ast_event_ref *event_ref;
01075 
01076    if (!(dup_event = ast_event_dup(event))) {
01077       return -1;
01078    }
01079 
01080    if (!(event_ref = alloc_event_ref())) {
01081       ast_event_destroy(dup_event);
01082       return -1;
01083    }
01084 
01085    event_ref->event = dup_event;
01086 
01087    ao2_link(ast_event_cache[ast_event_get_type(event)].container, event_ref);
01088 
01089    ao2_ref(event_ref, -1);
01090 
01091    return 0;
01092 }
01093 
01094 int ast_event_queue_and_cache(struct ast_event *event)
01095 {
01096    struct ao2_container *container;
01097    struct ast_event_ref tmp_event_ref = {
01098       .event = event,
01099    };
01100 
01101    if (!(container = ast_event_cache[ast_event_get_type(event)].container)) {
01102       ast_log(LOG_WARNING, "cache requested for non-cached event type\n");
01103       goto queue_event;
01104    }
01105 
01106    /* Remove matches from the cache */
01107    ao2_callback(container, OBJ_POINTER | OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA,
01108          ast_event_cmp, &tmp_event_ref);
01109 
01110 queue_event:
01111    return ast_event_queue(event);
01112 }
01113 
01114 static int handle_event(void *data)
01115 {
01116    struct ast_event_ref *event_ref = data;
01117    struct ast_event_sub *sub;
01118    uint16_t host_event_type;
01119 
01120    host_event_type = ntohs(event_ref->event->type);
01121 
01122    /* Subscribers to this specific event first */
01123    AST_RWDLLIST_RDLOCK(&ast_event_subs[host_event_type]);
01124    AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
01125       struct ast_event_ie_val *ie_val;
01126       AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
01127          if (!match_ie_val(event_ref->event, ie_val, NULL)) {
01128             break;
01129          }
01130       }
01131       if (ie_val) {
01132          continue;
01133       }
01134       sub->cb(event_ref->event, sub->userdata);
01135    }
01136    AST_RWDLLIST_UNLOCK(&ast_event_subs[host_event_type]);
01137 
01138    /* Now to subscribers to all event types */
01139    AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
01140    AST_RWDLLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry) {
01141       sub->cb(event_ref->event, sub->userdata);
01142    }
01143    AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
01144 
01145    ao2_ref(event_ref, -1);
01146 
01147    return 0;
01148 }
01149 
01150 int ast_event_queue(struct ast_event *event)
01151 {
01152    struct ast_event_ref *event_ref;
01153    uint16_t host_event_type;
01154 
01155    host_event_type = ntohs(event->type);
01156 
01157    /* Invalid type */
01158    if (host_event_type >= AST_EVENT_TOTAL) {
01159       ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
01160          "type '%d'!\n", host_event_type);
01161       return -1;
01162    }
01163 
01164    /* If nobody has subscribed to this event type, throw it away now */
01165    if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END)
01166          == AST_EVENT_SUB_NONE) {
01167       ast_event_destroy(event);
01168       return 0;
01169    }
01170 
01171    if (!(event_ref = alloc_event_ref())) {
01172       return -1;
01173    }
01174 
01175    event_ref->event = event;
01176 
01177    return ast_taskprocessor_push(event_dispatcher, handle_event, event_ref);
01178 }
01179 
01180 static int ast_event_hash_mwi(const void *obj, const int flags)
01181 {
01182    const struct ast_event *event = obj;
01183    const char *mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
01184    const char *context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT);
01185 
01186    return ast_str_hash_add(context, ast_str_hash(mailbox));
01187 }
01188 
01189 /*!
01190  * \internal
01191  * \brief Hash function for AST_EVENT_DEVICE_STATE
01192  *
01193  * \param[in] obj an ast_event
01194  * \param[in] flags unused
01195  *
01196  * \return hash value
01197  */
01198 static int ast_event_hash_devstate(const void *obj, const int flags)
01199 {
01200    const struct ast_event *event = obj;
01201 
01202    return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01203 }
01204 
01205 /*!
01206  * \internal
01207  * \brief Hash function for AST_EVENT_DEVICE_STATE_CHANGE
01208  *
01209  * \param[in] obj an ast_event
01210  * \param[in] flags unused
01211  *
01212  * \return hash value
01213  */
01214 static int ast_event_hash_devstate_change(const void *obj, const int flags)
01215 {
01216    const struct ast_event *event = obj;
01217 
01218    return ast_str_hash(ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE));
01219 }
01220 
01221 static int ast_event_hash(const void *obj, const int flags)
01222 {
01223    const struct ast_event_ref *event_ref;
01224    const struct ast_event *event;
01225    ao2_hash_fn *hash_fn;
01226 
01227    event_ref = obj;
01228    event = event_ref->event;
01229 
01230    if (!(hash_fn = ast_event_cache[ast_event_get_type(event)].hash_fn)) {
01231       return 0;
01232    }
01233 
01234    return hash_fn(event, flags);
01235 }
01236 
01237 /*!
01238  * \internal
01239  * \brief Compare two events
01240  *
01241  * \param[in] obj the first event, as an ast_event_ref
01242  * \param[in] arg the second event, as an ast_event_ref
01243  * \param[in] flags unused
01244  *
01245  * \pre Both events must be the same type.
01246  * \pre The event type must be declared as a cached event type in ast_event_cache
01247  *
01248  * \details This function takes two events, and determines if they are considered
01249  * equivalent.  The values of information elements specified in the cache arguments
01250  * for the event type are used to determine if the events are equivalent.
01251  *
01252  * \retval 0 No match
01253  * \retval CMP_MATCH The events are considered equivalent based on the cache arguments
01254  */
01255 static int ast_event_cmp(void *obj, void *arg, int flags)
01256 {
01257    struct ast_event_ref *event_ref, *event_ref2;
01258    struct ast_event *event, *event2;
01259    int res = CMP_MATCH;
01260    int i;
01261    enum ast_event_ie_type *cache_args;
01262 
01263    event_ref = obj;
01264    event = event_ref->event;
01265 
01266    event_ref2 = arg;
01267    event2 = event_ref2->event;
01268 
01269    cache_args = ast_event_cache[ast_event_get_type(event)].cache_args;
01270 
01271    for (i = 0; i < ARRAY_LEN(ast_event_cache[0].cache_args) && cache_args[i]; i++) {
01272       struct ast_event_ie_val ie_val = {
01273          .ie_type = cache_args[i],
01274       };
01275 
01276       if (!match_ie_val(event, &ie_val, event2)) {
01277          res = 0;
01278          break;
01279       }
01280    }
01281 
01282    return res;
01283 }
01284 
01285 int ast_event_init(void)
01286 {
01287    int i;
01288 
01289    for (i = 0; i < AST_EVENT_TOTAL; i++) {
01290       AST_RWDLLIST_HEAD_INIT(&ast_event_subs[i]);
01291    }
01292 
01293    for (i = 0; i < AST_EVENT_TOTAL; i++) {
01294       if (!ast_event_cache[i].hash_fn) {
01295          /* This event type is not cached. */
01296          continue;
01297       }
01298 
01299       if (!(ast_event_cache[i].container = ao2_container_alloc(NUM_CACHE_BUCKETS,
01300             ast_event_hash, ast_event_cmp))) {
01301          return -1;
01302       }
01303    }
01304 
01305    if (!(event_dispatcher = ast_taskprocessor_get("core_event_dispatcher", 0))) {
01306       return -1;
01307    }
01308 
01309    return 0;
01310 }

Generated on Fri Jun 19 12:09:43 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7