Thu Jul 9 13:40:33 2009

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, 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: 159855 $")
00029 
00030 #include "asterisk/_private.h"
00031 #include "asterisk/event.h"
00032 #include "asterisk/linkedlists.h"
00033 #include "asterisk/lock.h"
00034 #include "asterisk/utils.h"
00035 #include "asterisk/unaligned.h"
00036 
00037 /* Only use one thread for now to ensure ordered delivery */
00038 #define NUM_EVENT_THREADS 1
00039 
00040 /*!
00041  * \brief An event information element
00042  *
00043  * \note The format of this structure is important.  Since these events may
00044  *       be sent directly over a network, changing this structure will break
00045  *       compatibility with older versions.  However, at this point, this code
00046  *       has not made it into a release, so it is still fair game for change.
00047  */
00048 struct ast_event_ie {
00049    enum ast_event_ie_type ie_type:16;
00050    /*! Total length of the IE payload */
00051    uint16_t ie_payload_len;
00052    unsigned char ie_payload[0];
00053 } __attribute__((packed));
00054 
00055 /*!
00056  * \brief An event
00057  *
00058  * An ast_event consists of an event header (this structure), and zero or
00059  * more information elements defined by ast_event_ie.
00060  *
00061  * \note The format of this structure is important.  Since these events may
00062  *       be sent directly over a network, changing this structure will break
00063  *       compatibility with older versions.  However, at this point, this code
00064  *       has not made it into a release, so it is still fair game for change.
00065  */
00066 struct ast_event {
00067    /*! Event type */
00068    enum ast_event_type type:16;
00069    /*! Total length of the event */
00070    uint16_t event_len:16;
00071    /*! The data payload of the event, made up of information elements */
00072    unsigned char payload[0];
00073 } __attribute__((packed));
00074 
00075 struct ast_event_ref {
00076    struct ast_event *event;
00077    AST_LIST_ENTRY(ast_event_ref) entry;
00078 };
00079 
00080 struct ast_event_iterator {
00081    uint16_t event_len;
00082    const struct ast_event *event;
00083    struct ast_event_ie *ie;
00084 };
00085 
00086 /*! \brief data shared between event dispatching threads */
00087 static struct {
00088    ast_cond_t cond;
00089    ast_mutex_t lock;
00090    AST_LIST_HEAD_NOLOCK(, ast_event_ref) event_q;
00091 } event_thread = {
00092    .lock = AST_MUTEX_INIT_VALUE,
00093 };
00094 
00095 struct ast_event_ie_val {
00096    AST_LIST_ENTRY(ast_event_ie_val) entry;
00097    enum ast_event_ie_type ie_type;
00098    enum ast_event_ie_pltype ie_pltype;
00099    union {
00100       uint32_t uint;
00101       const char *str;
00102    } payload;
00103 };
00104 
00105 /*! \brief Event subscription */
00106 struct ast_event_sub {
00107    enum ast_event_type type;
00108    ast_event_cb_t cb;
00109    void *userdata;
00110    uint32_t uniqueid;
00111    AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
00112    AST_RWLIST_ENTRY(ast_event_sub) entry;
00113 };
00114 
00115 static uint32_t sub_uniqueid;
00116 
00117 /*! \brief Event subscriptions
00118  * The event subscribers are indexed by which event they are subscribed to */
00119 static AST_RWLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_EVENT_TOTAL];
00120 
00121 /*! \brief Cached events
00122  * The event cache is indexed on the event type.  The purpose of this is 
00123  * for events that express some sort of state.  So, when someone first
00124  * needs to know this state, it can get the last known state from the cache. */
00125 static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL];
00126 
00127 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
00128 {
00129    if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00130       ast_free((void *) ie_val->payload.str);
00131 
00132    ast_free(ie_val);
00133 }
00134 
00135 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type type, ...)
00136 {
00137    va_list ap;
00138    enum ast_event_ie_type ie_type;
00139    enum ast_event_subscriber_res res = AST_EVENT_SUB_NONE;
00140    struct ast_event_ie_val *ie_val, *sub_ie_val;
00141    struct ast_event_sub *sub;
00142    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00143 
00144    if (type >= AST_EVENT_TOTAL) {
00145       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00146       return res;
00147    }
00148 
00149    va_start(ap, type);
00150    for (ie_type = va_arg(ap, enum ast_event_type);
00151       ie_type != AST_EVENT_IE_END;
00152       ie_type = va_arg(ap, enum ast_event_type))
00153    {
00154       struct ast_event_ie_val *ie_val = alloca(sizeof(*ie_val));
00155       memset(ie_val, 0, sizeof(*ie_val));
00156       ie_val->ie_type = ie_type;
00157       ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00158       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00159          ie_val->payload.uint = va_arg(ap, uint32_t);
00160       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00161          ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
00162       AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
00163    }
00164    va_end(ap);
00165 
00166    AST_RWLIST_RDLOCK(&ast_event_subs[type]);
00167    AST_RWLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
00168       AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00169          AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
00170             if (sub_ie_val->ie_type == ie_val->ie_type)
00171                break;
00172          }
00173          if (!sub_ie_val) {
00174             if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00175                break;
00176             continue;
00177          }
00178          /* The subscriber doesn't actually care what the value is */
00179          if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
00180             continue;
00181          if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00182             ie_val->payload.uint != sub_ie_val->payload.uint)
00183             break;
00184          if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00185             strcmp(ie_val->payload.str, sub_ie_val->payload.str))
00186             break;
00187       }
00188       if (!ie_val)
00189          break;
00190    }
00191    AST_RWLIST_UNLOCK(&ast_event_subs[type]);
00192 
00193    if (sub) /* All parameters were matched */
00194       return AST_EVENT_SUB_EXISTS;
00195 
00196    AST_RWLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
00197    if (!AST_LIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
00198       res = AST_EVENT_SUB_EXISTS;
00199    AST_RWLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
00200 
00201    return res;
00202 }
00203 
00204 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
00205 void ast_event_report_subs(const struct ast_event_sub *event_sub)
00206 {
00207    struct ast_event *event;
00208    struct ast_event_sub *sub;
00209    enum ast_event_type event_type = -1;
00210    struct ast_event_ie_val *ie_val;
00211 
00212    if (event_sub->type != AST_EVENT_SUB)
00213       return;
00214 
00215    AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
00216       if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
00217          event_type = ie_val->payload.uint;
00218          break;
00219       }
00220    }
00221 
00222    if (event_type == -1)
00223       return;
00224 
00225    AST_RWLIST_RDLOCK(&ast_event_subs[event_type]);
00226    AST_RWLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
00227       if (event_sub == sub)
00228          continue;
00229 
00230       event = ast_event_new(AST_EVENT_SUB,
00231          AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00232          AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00233          AST_EVENT_IE_END);
00234 
00235       AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00236          switch (ie_val->ie_pltype) {
00237          case AST_EVENT_IE_PLTYPE_EXISTS:
00238             ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00239             break;
00240          case AST_EVENT_IE_PLTYPE_UINT:
00241             ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00242             break;
00243          case AST_EVENT_IE_PLTYPE_STR:
00244             ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00245             break;
00246          }
00247          if (!event)
00248             break;
00249       }
00250 
00251       if (!event)
00252          continue;
00253 
00254       event_sub->cb(event, event_sub->userdata);
00255 
00256       ast_event_destroy(event);
00257    }
00258    AST_RWLIST_UNLOCK(&ast_event_subs[event_type]);
00259 }
00260 
00261 struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
00262    void *userdata, ...)
00263 {
00264    va_list ap;
00265    enum ast_event_ie_type ie_type;
00266    struct ast_event_sub *sub;
00267    struct ast_event *event;
00268 
00269    if (type >= AST_EVENT_TOTAL) {
00270       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00271       return NULL;
00272    }
00273 
00274    if (!(sub = ast_calloc(1, sizeof(*sub))))
00275       return NULL;
00276 
00277    va_start(ap, userdata);
00278    for (ie_type = va_arg(ap, enum ast_event_type);
00279       ie_type != AST_EVENT_IE_END;
00280       ie_type = va_arg(ap, enum ast_event_type))
00281    {
00282       struct ast_event_ie_val *ie_val;
00283       if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
00284          continue;
00285       ie_val->ie_type = ie_type;
00286       ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00287       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00288          ie_val->payload.uint = va_arg(ap, uint32_t);
00289       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
00290          if (!(ie_val->payload.str = ast_strdup(va_arg(ap, const char *)))) {
00291             ast_free(ie_val);
00292             continue;
00293          }
00294       }
00295       AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
00296    }
00297    va_end(ap);
00298 
00299    sub->type = type;
00300    sub->cb = cb;
00301    sub->userdata = userdata;
00302    sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
00303 
00304    if (ast_event_check_subscriber(AST_EVENT_SUB,
00305       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, type,
00306       AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00307       struct ast_event_ie_val *ie_val;
00308 
00309       event = ast_event_new(AST_EVENT_SUB,
00310          AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00311          AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00312          AST_EVENT_IE_END);
00313 
00314       AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00315          switch (ie_val->ie_pltype) {
00316          case AST_EVENT_IE_PLTYPE_EXISTS:
00317             ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
00318             break;
00319          case AST_EVENT_IE_PLTYPE_UINT:
00320             ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00321             break;
00322          case AST_EVENT_IE_PLTYPE_STR:
00323             ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00324             break;
00325          }
00326          if (!event)
00327             break;
00328       }
00329 
00330       if (event)
00331          ast_event_queue(event);
00332    }
00333 
00334    AST_RWLIST_WRLOCK(&ast_event_subs[type]);
00335    AST_RWLIST_INSERT_TAIL(&ast_event_subs[type], sub, entry);
00336    AST_RWLIST_UNLOCK(&ast_event_subs[type]);
00337 
00338    return sub;
00339 }
00340 
00341 static void ast_event_sub_destroy(struct ast_event_sub *sub)
00342 {
00343    struct ast_event_ie_val *ie_val;
00344 
00345    while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
00346       ast_event_ie_val_destroy(ie_val);
00347 
00348    ast_free(sub);
00349 }
00350 
00351 void ast_event_unsubscribe(struct ast_event_sub *sub)
00352 {
00353    struct ast_event *event;
00354 
00355    AST_RWLIST_WRLOCK(&ast_event_subs[sub->type]);
00356    AST_LIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
00357    AST_RWLIST_UNLOCK(&ast_event_subs[sub->type]);
00358 
00359    if (ast_event_check_subscriber(AST_EVENT_UNSUB,
00360       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00361       AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
00362       
00363       event = ast_event_new(AST_EVENT_UNSUB,
00364          AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
00365          AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
00366          AST_EVENT_IE_END);
00367 
00368       if (event)
00369          ast_event_queue(event);
00370    }
00371 
00372    ast_event_sub_destroy(sub);
00373 }
00374 
00375 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
00376 {
00377    iterator->event_len = ntohs(event->event_len);
00378    iterator->event = event;
00379    iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
00380    return;
00381 }
00382 
00383 int ast_event_iterator_next(struct ast_event_iterator *iterator)
00384 {
00385    iterator->ie = (struct ast_event_ie *) ( ((char *) iterator->ie) + sizeof(*iterator->ie) + ntohs(iterator->ie->ie_payload_len));
00386    return ((iterator->event_len <= (((char *) iterator->ie) - ((char *) iterator->event))) ? -1 : 0);
00387 }
00388 
00389 enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator)
00390 {
00391    return ntohs(iterator->ie->ie_type);
00392 }
00393 
00394 uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator)
00395 {
00396    return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
00397 }
00398 
00399 const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
00400 {
00401    return (const char*)iterator->ie->ie_payload;
00402 }
00403 
00404 void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator)
00405 {
00406    return iterator->ie->ie_payload;
00407 }
00408 
00409 enum ast_event_type ast_event_get_type(const struct ast_event *event)
00410 {
00411    return ntohs(event->type);
00412 }
00413 
00414 uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
00415 {
00416    const uint32_t *ie_val;
00417 
00418    ie_val = ast_event_get_ie_raw(event, ie_type);
00419 
00420    return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
00421 }
00422 
00423 const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
00424 {
00425    return ast_event_get_ie_raw(event, ie_type);
00426 }
00427 
00428 const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type)
00429 {
00430    struct ast_event_iterator iterator;
00431    int res = 0;
00432 
00433    for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
00434       if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
00435          return ast_event_iterator_get_ie_raw(&iterator);
00436    }
00437 
00438    return NULL;
00439 }
00440 
00441 int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
00442    const char *str)
00443 {
00444    return ast_event_append_ie_raw(event, ie_type, str, strlen(str) + 1);
00445 }
00446 
00447 int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
00448    uint32_t data)
00449 {
00450    data = htonl(data);
00451    return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
00452 }
00453 
00454 int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
00455    const void *data, size_t data_len)
00456 {
00457    struct ast_event_ie *ie;
00458    unsigned int extra_len;
00459    uint16_t event_len;
00460 
00461    event_len = ntohs((*event)->event_len);
00462    extra_len = sizeof(*ie) + data_len;
00463 
00464    if (!(*event = ast_realloc(*event, event_len + extra_len)))
00465       return -1;
00466 
00467    ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
00468    ie->ie_type = htons(ie_type);
00469    ie->ie_payload_len = htons(data_len);
00470    memcpy(ie->ie_payload, data, data_len);
00471 
00472    (*event)->event_len = htons(event_len + extra_len);
00473 
00474    return 0;
00475 }
00476 
00477 struct ast_event *ast_event_new(enum ast_event_type type, ...)
00478 {
00479    va_list ap;
00480    struct ast_event *event;
00481    enum ast_event_type ie_type;
00482    struct ast_event_ie_val *ie_val;
00483    AST_LIST_HEAD_NOLOCK_STATIC(ie_vals, ast_event_ie_val);
00484 
00485    /* Invalid type */
00486    if (type >= AST_EVENT_TOTAL) {
00487       ast_log(LOG_WARNING, "Someone tried to create an event of invalid "
00488          "type '%d'!\n", type);
00489       return NULL;
00490    }
00491 
00492    va_start(ap, type);
00493    for (ie_type = va_arg(ap, enum ast_event_type);
00494       ie_type != AST_EVENT_IE_END;
00495       ie_type = va_arg(ap, enum ast_event_type))
00496    {
00497       struct ast_event_ie_val *ie_val = alloca(sizeof(*ie_val));
00498       memset(ie_val, 0, sizeof(*ie_val));
00499       ie_val->ie_type = ie_type;
00500       ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00501       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00502          ie_val->payload.uint = va_arg(ap, uint32_t);
00503       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00504          ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
00505       AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
00506    }
00507    va_end(ap);
00508 
00509    if (!(event = ast_calloc(1, sizeof(*event))))
00510       return NULL;
00511 
00512    event->type = htons(type);
00513    event->event_len = htons(sizeof(*event));
00514 
00515    AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
00516       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00517          ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
00518       else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00519          ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
00520 
00521       if (!event)
00522          break;
00523    }
00524 
00525    return event;
00526 }
00527 
00528 void ast_event_destroy(struct ast_event *event)
00529 {
00530    ast_free(event);
00531 }
00532 
00533 static void ast_event_ref_destroy(struct ast_event_ref *event_ref)
00534 {
00535    ast_event_destroy(event_ref->event);
00536    ast_free(event_ref);
00537 }
00538 
00539 static struct ast_event *ast_event_dup(const struct ast_event *event)
00540 {
00541    struct ast_event *dup_event;
00542    uint16_t event_len;
00543 
00544    event_len = ntohs(event->event_len);
00545 
00546    if (!(dup_event = ast_calloc(1, event_len)))
00547       return NULL;
00548    
00549    memcpy(dup_event, event, event_len);
00550 
00551    return dup_event;
00552 }
00553 
00554 struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
00555 {
00556    va_list ap;
00557    enum ast_event_ie_type ie_type;
00558    struct ast_event *dup_event = NULL;
00559    struct ast_event_ref *event_ref;
00560    struct cache_arg {
00561       AST_LIST_ENTRY(cache_arg) entry;
00562       enum ast_event_ie_type ie_type;
00563       enum ast_event_ie_pltype ie_pltype;
00564       union {
00565          uint32_t uint;
00566          const char *str;
00567       } payload;
00568    } *cache_arg;
00569    AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg);
00570 
00571    if (type >= AST_EVENT_TOTAL) {
00572       ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
00573       return NULL;
00574    }
00575 
00576    va_start(ap, type);
00577    for (ie_type = va_arg(ap, enum ast_event_type);
00578       ie_type != AST_EVENT_IE_END;
00579       ie_type = va_arg(ap, enum ast_event_type))
00580    {
00581       cache_arg = alloca(sizeof(*cache_arg));
00582       memset(cache_arg, 0, sizeof(*cache_arg));
00583       cache_arg->ie_type = ie_type;
00584       cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00585       if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
00586          cache_arg->payload.uint = va_arg(ap, uint32_t);
00587       else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
00588          cache_arg->payload.str = ast_strdupa(va_arg(ap, const char *));
00589       AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
00590    }
00591    va_end(ap);
00592 
00593    if (AST_LIST_EMPTY(&cache_args)) {
00594       ast_log(LOG_ERROR, "Events can not be retrieved from the cache without "
00595          "specifying at least one IE type!\n");
00596       return NULL;
00597    }
00598 
00599    AST_RWLIST_RDLOCK(&ast_event_cache[type]);
00600    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
00601       AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
00602          if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00603             (cache_arg->payload.uint ==
00604              ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) ||
00605 
00606             (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00607             (!strcmp(cache_arg->payload.str,
00608               ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) ||
00609 
00610             (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
00611              ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) ) 
00612          {
00613             break;   
00614          }
00615       }
00616       if (!cache_arg) {
00617          /* All parameters were matched on this cache entry, so return it */
00618          dup_event = ast_event_dup(event_ref->event);
00619          break;
00620       }
00621    }
00622    AST_RWLIST_TRAVERSE_SAFE_END
00623    AST_RWLIST_UNLOCK(&ast_event_cache[type]);
00624 
00625    return dup_event;
00626 }
00627 
00628 /*! \brief Duplicate an event and add it to the cache
00629  * \note This assumes this index in to the cache is locked */
00630 static int ast_event_dup_and_cache(const struct ast_event *event)
00631 {
00632    struct ast_event *dup_event;
00633    struct ast_event_ref *event_ref;
00634 
00635    if (!(dup_event = ast_event_dup(event)))
00636       return -1;
00637    if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
00638       return -1;
00639    
00640    event_ref->event = dup_event;
00641 
00642    AST_LIST_INSERT_TAIL(&ast_event_cache[ntohs(event->type)], event_ref, entry);
00643 
00644    return 0;
00645 }
00646 
00647 int ast_event_queue_and_cache(struct ast_event *event, ...)
00648 {
00649    va_list ap;
00650    enum ast_event_type ie_type;
00651    uint16_t host_event_type;
00652    struct ast_event_ref *event_ref;
00653    int res;
00654    struct cache_arg {
00655       AST_LIST_ENTRY(cache_arg) entry;
00656       enum ast_event_ie_type ie_type;
00657       enum ast_event_ie_pltype ie_pltype;
00658    } *cache_arg;
00659    AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg);
00660 
00661    host_event_type = ntohs(event->type);
00662 
00663    /* Invalid type */
00664    if (host_event_type >= AST_EVENT_TOTAL) {
00665       ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
00666          "type '%d'!\n", host_event_type);
00667       return -1;
00668    }
00669 
00670    va_start(ap, event);
00671    for (ie_type = va_arg(ap, enum ast_event_type);
00672       ie_type != AST_EVENT_IE_END;
00673       ie_type = va_arg(ap, enum ast_event_type))
00674    {
00675       cache_arg = alloca(sizeof(*cache_arg));
00676       memset(cache_arg, 0, sizeof(*cache_arg));
00677       cache_arg->ie_type = ie_type;
00678       cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
00679       AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
00680    }
00681    va_end(ap);
00682 
00683    if (AST_LIST_EMPTY(&cache_args)) {
00684       ast_log(LOG_ERROR, "Events can not be cached without specifying at "
00685          "least one IE type!\n");
00686       return ast_event_queue(event);
00687    }
00688  
00689    AST_RWLIST_WRLOCK(&ast_event_cache[host_event_type]);
00690    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[host_event_type], event_ref, entry) {
00691       AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
00692          if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00693             (ast_event_get_ie_uint(event, cache_arg->ie_type) ==
00694              ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) ||
00695 
00696             (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00697             (!strcmp(ast_event_get_ie_str(event, cache_arg->ie_type),
00698               ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) ||
00699 
00700             (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
00701              ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) )
00702          {
00703             break;   
00704          }
00705       }
00706       if (!cache_arg) {
00707          /* All parameters were matched on this cache entry, so remove it */
00708          AST_LIST_REMOVE_CURRENT(entry);
00709          ast_event_ref_destroy(event_ref);
00710       }
00711    }
00712    AST_RWLIST_TRAVERSE_SAFE_END;
00713    res = ast_event_dup_and_cache(event);
00714    AST_RWLIST_UNLOCK(&ast_event_cache[host_event_type]);
00715 
00716    return (ast_event_queue(event) || res) ? -1 : 0;
00717 }
00718 
00719 int ast_event_queue(struct ast_event *event)
00720 {
00721    struct ast_event_ref *event_ref;
00722    uint16_t host_event_type;
00723 
00724    host_event_type = ntohs(event->type);
00725 
00726    /* Invalid type */
00727    if (host_event_type >= AST_EVENT_TOTAL) {
00728       ast_log(LOG_WARNING, "Someone tried to queue an event of invalid "
00729          "type '%d'!\n", host_event_type);
00730       return -1;
00731    }
00732 
00733    /* If nobody has subscribed to this event type, throw it away now */
00734    if (ast_event_check_subscriber(host_event_type, AST_EVENT_IE_END) 
00735       == AST_EVENT_SUB_NONE) {
00736       ast_event_destroy(event);
00737       return 0;
00738    }
00739 
00740    if (!(event_ref = ast_calloc(1, sizeof(*event_ref))))
00741       return -1;
00742 
00743    event_ref->event = event;
00744 
00745    ast_mutex_lock(&event_thread.lock);
00746    AST_LIST_INSERT_TAIL(&event_thread.event_q, event_ref, entry);
00747    ast_cond_signal(&event_thread.cond);
00748    ast_mutex_unlock(&event_thread.lock);
00749 
00750    return 0;
00751 }
00752 
00753 static void *ast_event_dispatcher(void *unused)
00754 {
00755    for (;;) {
00756       struct ast_event_ref *event_ref;
00757       struct ast_event_sub *sub;
00758       uint16_t host_event_type;
00759 
00760       ast_mutex_lock(&event_thread.lock);
00761       while (!(event_ref = AST_LIST_REMOVE_HEAD(&event_thread.event_q, entry)))
00762          ast_cond_wait(&event_thread.cond, &event_thread.lock);
00763       ast_mutex_unlock(&event_thread.lock);
00764 
00765       host_event_type = ntohs(event_ref->event->type);
00766 
00767       /* Subscribers to this specific event first */
00768       AST_RWLIST_RDLOCK(&ast_event_subs[host_event_type]);
00769       AST_RWLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
00770          struct ast_event_ie_val *ie_val;
00771          AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
00772             if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
00773                ast_event_get_ie_raw(event_ref->event, ie_val->ie_type)) {
00774                continue;
00775             } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
00776                ast_event_get_ie_uint(event_ref->event, ie_val->ie_type) 
00777                == ie_val->payload.uint) {
00778                continue;
00779             } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
00780                !strcmp(ast_event_get_ie_str(event_ref->event, ie_val->ie_type),
00781                   ie_val->payload.str)) {
00782                continue;
00783             }
00784             break;
00785          }
00786          if (ie_val)
00787             continue;
00788          sub->cb(event_ref->event, sub->userdata);
00789       }
00790       AST_RWLIST_UNLOCK(&ast_event_subs[host_event_type]);
00791 
00792       /* Now to subscribers to all event types */
00793       AST_RWLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
00794       AST_RWLIST_TRAVERSE(&ast_event_subs[AST_EVENT_ALL], sub, entry)
00795          sub->cb(event_ref->event, sub->userdata);
00796       AST_RWLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
00797 
00798       ast_event_ref_destroy(event_ref);
00799    }
00800 
00801    return NULL;
00802 }
00803 
00804 void ast_event_init(void)
00805 {
00806    int i;
00807 
00808    for (i = 0; i < AST_EVENT_TOTAL; i++)
00809       AST_RWLIST_HEAD_INIT(&ast_event_subs[i]);
00810 
00811    for (i = 0; i < AST_EVENT_TOTAL; i++)
00812       AST_RWLIST_HEAD_INIT(&ast_event_cache[i]);
00813 
00814    ast_cond_init(&event_thread.cond, NULL);
00815 
00816    for (i = 0; i < NUM_EVENT_THREADS; i++) {
00817       pthread_t dont_care;
00818       ast_pthread_create_background(&dont_care, NULL, ast_event_dispatcher, NULL);
00819    }
00820 }

Generated on Thu Jul 9 13:40:33 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7