Wed Apr 6 11:29:44 2011

Asterisk developer's documentation


event.c

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

Generated on Wed Apr 6 11:29:44 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7