Mon Jun 18 2012 03:55:33

Asterisk developer's documentation


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