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

Generated on Mon Mar 19 11:30:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7