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

Generated on Mon Oct 8 12:39:02 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7