Sat Apr 26 2014 22:01:36

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