Mon Aug 31 12:30:07 2015

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

Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1