Thu Oct 11 06:33:46 2012

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

Generated on Thu Oct 11 06:33:46 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6