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

Generated on Sat Feb 11 06:33:14 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6