Wed Aug 7 17:15:53 2019

Asterisk developer's documentation


cel.c File Reference

Channel Event Logging API. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/cel.h"
#include "asterisk/logger.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/astobj2.h"

Go to the source code of this file.

Data Structures

struct  cel_linkedid

Defines

#define CEL_DEFAULT_EVENTS   0
 Track no events by default.
#define CEL_ENABLED_DEFAULT   0
 CEL is off by default.
#define CEL_MAX_EVENT_IDS   64
 Maximum possible CEL event IDs.
#define NUM_APP_BUCKETS   97
 Number of buckets for the appset container.

Functions

static int app_cmp (void *obj, void *arg, int flags)
static int app_hash (const void *obj, const int flags)
unsigned int ast_cel_check_enabled (void)
 Check to see if CEL is enabled.
void ast_cel_check_retire_linkedid (struct ast_channel *chan)
 Check and potentially retire a Linked ID.
int ast_cel_engine_init (void)
int ast_cel_engine_reload (void)
static void ast_cel_engine_term (void)
struct ast_channelast_cel_fabricate_channel_from_event (const struct ast_event *event)
 Create a fake channel from data in a CEL event.
int ast_cel_fill_record (const struct ast_event *e, struct ast_cel_event_record *r)
 Fill in an ast_cel_event_record from a CEL event.
const char * ast_cel_get_ama_flag_name (enum ast_cel_ama_flag flag)
 Convert AMA flag to printable string.
const char * ast_cel_get_type_name (enum ast_cel_event_type type)
 Get the name of a CEL event type.
int ast_cel_linkedid_ref (const char *linkedid)
 Inform CEL that a new linkedid is being used.
int ast_cel_report_event (struct ast_channel *chan, enum ast_cel_event_type event_type, const char *userdefevname, const char *extra, struct ast_channel *peer2)
 Report a channel event.
enum ast_cel_event_type ast_cel_str_to_event_type (const char *name)
 Get the event type from a string.
static int ast_cel_track_event (enum ast_cel_event_type et)
static int do_reload (int is_reload)
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int lid_cmp (void *obj, void *arg, int flags)
static int lid_hash (const void *obj, const int flags)
static void parse_apps (const char *val)
static void parse_events (const char *val)
static void print_cel_sub (const struct ast_event *event, void *data)
static void set_defaults (void)

Variables

static struct ao2_containerappset
 Container of Asterisk application names.
static const char *const cel_ama_flags [AST_CEL_AMA_FLAG_TOTAL]
 Map of ast_cel_ama_flags to strings.
static const char cel_conf_file [] = "cel.conf"
static char cel_dateformat [256]
 Configured date format for event timestamps.
static unsigned char cel_enabled
static const char *const cel_event_types [CEL_MAX_EVENT_IDS]
 Map of ast_cel_event_type to strings.
static struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status")
static int64_t eventset
 which events we want to track
static struct ast_datastore_info fabricated_channel_datastore
static struct ao2_containerlinkedids
 Container of channel references to a linkedid for CEL purposes.
static ast_mutex_t reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
 Lock protecting CEL.

Detailed Description

Channel Event Logging API.

Author:
Steve Murphy <murf@digium.com>
Russell Bryant <russell@digium.com>
Todo:
Do thorough testing of all transfer methods to ensure that BLINDTRANSFER, ATTENDEDTRANSFER, BRIDGE_START, and BRIDGE_END events are all reported as expected.

Definition in file cel.c.


Define Documentation

#define CEL_DEFAULT_EVENTS   0

Track no events by default.

Definition at line 75 of file cel.c.

Referenced by set_defaults().

#define CEL_ENABLED_DEFAULT   0

CEL is off by default.

Definition at line 57 of file cel.c.

Referenced by set_defaults().

#define CEL_MAX_EVENT_IDS   64

Maximum possible CEL event IDs.

Note:
This limit is currently imposed by the eventset definition

Definition at line 70 of file cel.c.

#define NUM_APP_BUCKETS   97

Number of buckets for the appset container.

Definition at line 80 of file cel.c.

Referenced by ast_cel_engine_init().


Function Documentation

static int app_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 812 of file cel.c.

References app1, app2, and CMP_MATCH.

Referenced by ast_cel_engine_init().

00813 {
00814    const char *app1 = obj;
00815    const char *app2 = arg;
00816 
00817    return !strcasecmp(app1, app2) ? CMP_MATCH : 0;
00818 }

static int app_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 807 of file cel.c.

References ast_str_case_hash().

Referenced by ast_cel_engine_init().

00808 {
00809    return ast_str_case_hash((const char *) obj);
00810 }

unsigned int ast_cel_check_enabled ( void   ) 

Check to see if CEL is enabled.

Since:
1.8
Return values:
zero not enabled
non-zero enabled

Definition at line 164 of file cel.c.

00165 {
00166    return cel_enabled;
00167 }

void ast_cel_check_retire_linkedid ( struct ast_channel chan  ) 

Check and potentially retire a Linked ID.

Parameters:
chan channel that is being destroyed or its linkedid is changing
Since:
1.8

If at least one CEL backend is looking for CEL_LINKEDID_END events, this function will check if the given channel is the last active channel with that linkedid, and if it is, emit a CEL_LINKEDID_END event.

Returns:
nothing

Definition at line 429 of file cel.c.

References ao2_find, ao2_ref, ao2_unlink, AST_CEL_LINKEDID_END, ast_cel_report_event(), ast_cel_track_event(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), cel_linkedid::count, cel_linkedid::id, LOG_ERROR, OBJ_POINTER, and reload_lock.

Referenced by ast_channel_change_linkedid(), and ast_channel_destructor().

00430 {
00431    const char *linkedid = chan->linkedid;
00432    struct cel_linkedid *lid;
00433    struct cel_linkedid find_lid;
00434 
00435    if (ast_strlen_zero(linkedid)) {
00436       return;
00437    }
00438 
00439    /* Get the lock in case any CEL events are still in flight when we shutdown. */
00440    ast_mutex_lock(&reload_lock);
00441 
00442    if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)
00443       || !linkedids) {
00444       /*
00445        * CEL is disabled or we are not tracking linkedids
00446        * or the CEL module is shutdown.
00447        */
00448       ast_mutex_unlock(&reload_lock);
00449       return;
00450    }
00451 
00452    find_lid.id = linkedid;
00453    lid = ao2_find(linkedids, &find_lid, OBJ_POINTER);
00454    if (!lid) {
00455       ast_mutex_unlock(&reload_lock);
00456 
00457       /*
00458        * The user may have done a reload to start tracking linkedids
00459        * when a call was already in progress.  This is an unusual kind
00460        * of change to make after starting Asterisk.
00461        */
00462       ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
00463       return;
00464    }
00465 
00466    if (!--lid->count) {
00467       /* No channels use this linkedid anymore. */
00468       ao2_unlink(linkedids, lid);
00469       ast_mutex_unlock(&reload_lock);
00470 
00471       ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
00472    } else {
00473       ast_mutex_unlock(&reload_lock);
00474    }
00475    ao2_ref(lid, -1);
00476 }

int ast_cel_engine_init ( void   ) 

Provided by cel.c

Definition at line 860 of file cel.c.

References ao2_container_alloc, app_cmp(), app_hash(), ast_cel_engine_term(), ast_cli_register(), ast_register_atexit(), do_reload(), lid_cmp(), lid_hash(), and NUM_APP_BUCKETS.

Referenced by main().

00861 {
00862    /*
00863     * Accesses to the appset and linkedids containers have to be
00864     * protected by the reload_lock so they don't need a lock of
00865     * their own.
00866     */
00867    appset = ao2_container_alloc(NUM_APP_BUCKETS, app_hash, app_cmp);
00868    if (!appset) {
00869       return -1;
00870    }
00871    linkedids = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp);
00872    if (!linkedids) {
00873       ast_cel_engine_term();
00874       return -1;
00875    }
00876 
00877    if (do_reload(0) || ast_cli_register(&cli_status)) {
00878       ast_cel_engine_term();
00879       return -1;
00880    }
00881 
00882    ast_register_atexit(ast_cel_engine_term);
00883 
00884    return 0;
00885 }

int ast_cel_engine_reload ( void   ) 

Provided by cel.c

Definition at line 887 of file cel.c.

References do_reload().

00888 {
00889    return do_reload(1);
00890 }

static void ast_cel_engine_term ( void   )  [static]

Definition at line 841 of file cel.c.

References ao2_ref, ast_cli_unregister(), ast_mutex_lock, ast_mutex_unlock, and reload_lock.

Referenced by ast_cel_engine_init().

00842 {
00843    /* Get the lock in case any CEL events are still in flight when we shutdown. */
00844    ast_mutex_lock(&reload_lock);
00845 
00846    if (appset) {
00847       ao2_ref(appset, -1);
00848       appset = NULL;
00849    }
00850    if (linkedids) {
00851       ao2_ref(linkedids, -1);
00852       linkedids = NULL;
00853    }
00854 
00855    ast_mutex_unlock(&reload_lock);
00856 
00857    ast_cli_unregister(&cli_status);
00858 }

struct ast_channel* ast_cel_fabricate_channel_from_event ( const struct ast_event event  )  [read]

Create a fake channel from data in a CEL event.

Note:
This function creates a fake channel containing the serialized channel data in the given cel event. It should be released with ast_channel_unref() but could be released with ast_channel_release().
Parameters:
event the CEL event
Since:
1.8
Returns:
a channel with the data filled in, or NULL on error
Todo:
This function is very expensive, especially given that some CEL backends use it on every CEL event. This function really needs to go away at some point.

Definition at line 486 of file cel.c.

References ast_cel_event_record::account_code, accountcode, ast_cel_event_record::amaflag, ast_channel::amaflags, ast_party_caller::ani, ast_channel::appl, ast_cel_event_record::application_data, ast_cel_event_record::application_name, AST_CEL_EVENT_RECORD_VERSION, ast_cel_fill_record(), ast_channel_datastore_add(), ast_channel_unref, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_dummy_channel_alloc, AST_LIST_INSERT_HEAD, ast_localtime(), ast_malloc, ast_strdup, ast_strftime(), ast_string_field_set, ast_strlen_zero(), ast_var_assign(), ast_channel::caller, ast_cel_event_record::caller_id_ani, ast_cel_event_record::caller_id_dnid, ast_cel_event_record::caller_id_name, ast_cel_event_record::caller_id_num, ast_cel_event_record::caller_id_rdnis, ast_cel_event_record::channel_name, ast_cel_event_record::context, ast_channel::context, ast_datastore::data, ast_channel::data, ast_channel::dialed, ast_cel_event_record::event_name, ast_cel_event_record::event_time, ast_channel::exten, ast_cel_event_record::extension, ast_cel_event_record::extra, ast_party_redirecting::from, ast_party_caller::id, ast_cel_event_record::linked_id, name, ast_party_id::name, ast_party_dialed::number, ast_party_id::number, ast_cel_event_record::peer, ast_cel_event_record::peer_account, ast_channel::redirecting, ast_party_dialed::str, ast_party_number::str, ast_party_name::str, ast_cel_event_record::unique_id, ast_cel_event_record::user_defined_name, ast_cel_event_record::user_field, ast_party_number::valid, ast_party_name::valid, ast_channel::varshead, and ast_cel_event_record::version.

00487 {
00488    struct varshead *headp;
00489    struct ast_var_t *newvariable;
00490    char timebuf[30];
00491    struct ast_channel *tchan;
00492    struct ast_cel_event_record record = {
00493       .version = AST_CEL_EVENT_RECORD_VERSION,
00494    };
00495    struct ast_datastore *datastore;
00496    char *app_data;
00497 
00498    /* do not call ast_channel_alloc because this is not really a real channel */
00499    if (!(tchan = ast_dummy_channel_alloc())) {
00500       return NULL;
00501    }
00502 
00503    headp = &tchan->varshead;
00504 
00505    /* first, get the variables from the event */
00506    if (ast_cel_fill_record(event, &record)) {
00507       ast_channel_unref(tchan);
00508       return NULL;
00509    }
00510 
00511    /* next, fill the channel with their data */
00512    if ((newvariable = ast_var_assign("eventtype", record.event_name))) {
00513       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00514    }
00515 
00516    if (ast_strlen_zero(cel_dateformat)) {
00517       snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
00518             (long) record.event_time.tv_usec);
00519    } else {
00520       struct ast_tm tm;
00521       ast_localtime(&record.event_time, &tm, NULL);
00522       ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
00523    }
00524 
00525    if ((newvariable = ast_var_assign("eventtime", timebuf))) {
00526       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00527    }
00528 
00529    if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
00530       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00531    }
00532    if ((newvariable = ast_var_assign("eventextra", record.extra))) {
00533       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00534    }
00535 
00536    tchan->caller.id.name.valid = 1;
00537    tchan->caller.id.name.str = ast_strdup(record.caller_id_name);
00538    tchan->caller.id.number.valid = 1;
00539    tchan->caller.id.number.str = ast_strdup(record.caller_id_num);
00540    tchan->caller.ani.number.valid = 1;
00541    tchan->caller.ani.number.str = ast_strdup(record.caller_id_ani);
00542    tchan->redirecting.from.number.valid = 1;
00543    tchan->redirecting.from.number.str = ast_strdup(record.caller_id_rdnis);
00544    tchan->dialed.number.str = ast_strdup(record.caller_id_dnid);
00545 
00546    ast_copy_string(tchan->exten, record.extension, sizeof(tchan->exten));
00547    ast_copy_string(tchan->context, record.context, sizeof(tchan->context));
00548    ast_string_field_set(tchan, name, record.channel_name);
00549    ast_string_field_set(tchan, uniqueid, record.unique_id);
00550    ast_string_field_set(tchan, linkedid, record.linked_id);
00551    ast_string_field_set(tchan, accountcode, record.account_code);
00552    ast_string_field_set(tchan, peeraccount, record.peer_account);
00553    ast_string_field_set(tchan, userfield, record.user_field);
00554 
00555    if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
00556       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00557    }
00558 
00559    tchan->amaflags = record.amaflag;
00560 
00561    /* We need to store an 'application name' and 'application
00562     * data' on the channel for logging purposes, but the channel
00563     * structure only provides a place to store pointers, and it
00564     * expects these pointers to be pointing to data that does not
00565     * need to be freed. This means that the channel's destructor
00566     * does not attempt to free any storage that these pointers
00567     * point to. However, we can't provide data in that form directly for
00568     * these structure members. In order to ensure that these data
00569     * elements have a lifetime that matches the channel's
00570     * lifetime, we'll put them in a datastore attached to the
00571     * channel, and set's the channel's pointers to point into the
00572     * datastore.  The datastore will then be automatically destroyed
00573     * when the channel is destroyed.
00574     */
00575 
00576    if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
00577       ast_channel_unref(tchan);
00578       return NULL;
00579    }
00580 
00581    if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
00582       ast_datastore_free(datastore);
00583       ast_channel_unref(tchan);
00584       return NULL;
00585    }
00586 
00587    tchan->appl = strcpy(app_data, record.application_name);
00588    tchan->data = strcpy(app_data + strlen(record.application_name) + 1,
00589       record.application_data);
00590 
00591    datastore->data = app_data;
00592    ast_channel_datastore_add(tchan, datastore);
00593 
00594    return tchan;
00595 }

int ast_cel_fill_record ( const struct ast_event event,
struct ast_cel_event_record r 
)

Fill in an ast_cel_event_record from a CEL event.

Parameters:
[in] event the CEL event
[out] r the ast_cel_event_record to fill in
Since:
1.8
Return values:
0 success
non-zero failure

Definition at line 762 of file cel.c.

References ast_cel_event_record::account_code, ast_cel_event_record::amaflag, ast_cel_event_record::application_data, ast_cel_event_record::application_name, AST_CEL_EVENT_RECORD_VERSION, ast_cel_get_type_name(), AST_CEL_USER_DEFINED, ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_CEL_USERFIELD, ast_log(), ast_cel_event_record::caller_id_ani, ast_cel_event_record::caller_id_dnid, ast_cel_event_record::caller_id_name, ast_cel_event_record::caller_id_num, ast_cel_event_record::caller_id_rdnis, ast_cel_event_record::channel_name, ast_cel_event_record::context, ast_cel_event_record::event_name, ast_cel_event_record::event_time, ast_cel_event_record::event_type, ast_cel_event_record::extension, ast_cel_event_record::extra, ast_cel_event_record::linked_id, LOG_ERROR, ast_cel_event_record::peer, ast_cel_event_record::peer_account, S_OR, ast_cel_event_record::unique_id, ast_cel_event_record::user_defined_name, ast_cel_event_record::user_field, and ast_cel_event_record::version.

Referenced by ast_cel_fabricate_channel_from_event().

00763 {
00764    if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
00765       ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record.  "
00766             "Please ensure all modules were compiled for "
00767             "this version of Asterisk.\n");
00768       return -1;
00769    }
00770 
00771    r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
00772 
00773    r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
00774    r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
00775 
00776    r->user_defined_name = "";
00777 
00778    if (r->event_type == AST_CEL_USER_DEFINED) {
00779       r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
00780       r->event_name = r->user_defined_name;
00781    } else {
00782       r->event_name = ast_cel_get_type_name(r->event_type);
00783    }
00784 
00785    r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
00786    r->caller_id_num    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
00787    r->caller_id_ani    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
00788    r->caller_id_rdnis  = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
00789    r->caller_id_dnid   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
00790    r->extension        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
00791    r->context          = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
00792    r->channel_name     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
00793    r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
00794    r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
00795    r->account_code     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00796    r->peer_account     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00797    r->unique_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
00798    r->linked_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
00799    r->amaflag          = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
00800    r->user_field       = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
00801    r->peer             = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
00802    r->extra            = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
00803 
00804    return 0;
00805 }

const char* ast_cel_get_ama_flag_name ( enum ast_cel_ama_flag  flag  ) 

Convert AMA flag to printable string.

Parameters:
[in] flag the flag to convert to a string
Since:
1.8
Returns:
the string representation of the flag

Definition at line 417 of file cel.c.

References ARRAY_LEN, ast_log(), LOG_WARNING, and S_OR.

00418 {
00419    if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
00420       ast_log(LOG_WARNING, "Invalid AMA flag: %u\n", flag);
00421       return "Unknown";
00422    }
00423 
00424    return S_OR(cel_ama_flags[flag], "Unknown");
00425 }

const char* ast_cel_get_type_name ( enum ast_cel_event_type  type  ) 

Get the name of a CEL event type.

Parameters:
type the type to get the name of
Since:
1.8
Returns:
the string representation of the type

Definition at line 412 of file cel.c.

References S_OR.

Referenced by ast_cel_fill_record(), and handle_cli_status().

00413 {
00414    return S_OR(cel_event_types[type], "Unknown");
00415 }

int ast_cel_linkedid_ref ( const char *  linkedid  ) 

Inform CEL that a new linkedid is being used.

Since:
11
Return values:
-1 error
0 success

Definition at line 597 of file cel.c.

References ao2_alloc, ao2_find, ao2_link, ao2_ref, AST_CEL_LINKEDID_END, ast_cel_track_event(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), cel_linkedid::count, cel_linkedid::id, LOG_ERROR, OBJ_POINTER, and reload_lock.

Referenced by ast_cel_report_event(), and ast_channel_change_linkedid().

00598 {
00599    struct cel_linkedid *lid;
00600    struct cel_linkedid find_lid;
00601 
00602    if (ast_strlen_zero(linkedid)) {
00603       ast_log(LOG_ERROR, "The linkedid should never be empty\n");
00604       return -1;
00605    }
00606 
00607    /* Get the lock in case any CEL events are still in flight when we shutdown. */
00608    ast_mutex_lock(&reload_lock);
00609 
00610    if (!cel_enabled || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
00611       /* CEL is disabled or we are not tracking linkedids. */
00612       ast_mutex_unlock(&reload_lock);
00613       return 0;
00614    }
00615    if (!linkedids) {
00616       /* The CEL module is shutdown.  Abort. */
00617       ast_mutex_unlock(&reload_lock);
00618       return -1;
00619    }
00620 
00621    find_lid.id = linkedid;
00622    lid = ao2_find(linkedids, &find_lid, OBJ_POINTER);
00623    if (!lid) {
00624       /*
00625        * Changes to the lid->count member are protected by the
00626        * reload_lock so the lid object does not need its own lock.
00627        */
00628       lid = ao2_alloc(sizeof(*lid) + strlen(linkedid) + 1, NULL);
00629       if (!lid) {
00630          ast_mutex_unlock(&reload_lock);
00631          return -1;
00632       }
00633       lid->id = (char *) (lid + 1);
00634       strcpy((char *) lid->id, linkedid);/* Safe */
00635 
00636       ao2_link(linkedids, lid);
00637    }
00638    ++lid->count;
00639    ast_mutex_unlock(&reload_lock);
00640    ao2_ref(lid, -1);
00641 
00642    return 0;
00643 }

int ast_cel_report_event ( struct ast_channel chan,
enum ast_cel_event_type  event_type,
const char *  userdefevname,
const char *  extra,
struct ast_channel peer2 
)

Report a channel event.

Parameters:
chan This argument is required. This is the primary channel associated with this channel event.
event_type This is the type of call event being reported.
userdefevname This is an optional custom name for the call event.
extra This is an optional opaque field that will go into the "CEL_EXTRA" information element of the call event.
peer2 All CEL events contain a "peer name" information element. The first place the code will look to get a peer name is from the bridged channel to chan. If chan has no bridged channel and peer2 is specified, then the name of peer2 will go into the "peer name" field. If neither are available, the peer name field will be blank.
Since:
1.8
Precondition:
chan and peer2 are both unlocked
Return values:
0 success
non-zero failure

Definition at line 645 of file cel.c.

References ast_channel::amaflags, ast_party_caller::ani, ao2_find, ao2_ref, app, ast_channel::appl, ast_bridged_channel(), AST_CEL_APP_END, AST_CEL_APP_START, AST_CEL_CHANNEL_START, AST_CEL_LINKEDID_END, ast_cel_linkedid_ref(), ast_cel_track_event(), ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, AST_EVENT_CEL, ast_event_destroy(), AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_END, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_IE_PLTYPE_UINT, ast_event_new(), ast_event_queue(), ast_mutex_lock, ast_mutex_unlock, ast_strdupa, ast_tvnow(), ast_channel::caller, ast_channel::context, ast_channel::data, ast_channel::dialed, ast_channel::exten, ast_party_redirecting::from, ast_party_caller::id, ast_party_id::name, ast_party_dialed::number, ast_party_id::number, OBJ_POINTER, ast_channel::redirecting, reload_lock, S_COR, S_OR, ast_party_dialed::str, ast_party_number::str, ast_party_name::str, ast_party_number::valid, and ast_party_name::valid.

Referenced by __ast_channel_alloc_ap(), __ast_read(), analog_attempt_transfer(), ast_bridge_call(), ast_cel_check_retire_linkedid(), ast_channel_destructor(), ast_do_masquerade(), ast_do_pickup(), ast_hangup(), ast_raw_answer(), builtin_atxfer(), builtin_blindtransfer(), celgenuserevent_exec(), do_forward(), handle_invite_replaces(), handle_request_refer(), local_attended_transfer(), manage_parked_call(), park_call_full(), parked_call_exec(), pbx_exec(), and wait_for_answer().

00647 {
00648    struct timeval eventtime;
00649    struct ast_event *ev;
00650    const char *peername = "";
00651    struct ast_channel *peer;
00652 
00653    /* Make sure a reload is not occurring while we're checking to see if this
00654     * is an event that we care about.  We could lose an important event in this
00655     * process otherwise. */
00656    ast_mutex_lock(&reload_lock);
00657 
00658    if (!appset) {
00659       /* The CEL module is shutdown.  Abort. */
00660       ast_mutex_unlock(&reload_lock);
00661       return -1;
00662    }
00663 
00664    /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
00665     * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
00666    if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && chan->linkedid) {
00667       if (ast_cel_linkedid_ref(chan->linkedid)) {
00668          ast_mutex_unlock(&reload_lock);
00669          return -1;
00670       }
00671    }
00672 
00673    if (!cel_enabled || !ast_cel_track_event(event_type)) {
00674       ast_mutex_unlock(&reload_lock);
00675       return 0;
00676    }
00677 
00678    if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
00679       char *app;
00680       if (!(app = ao2_find(appset, (char *) chan->appl, OBJ_POINTER))) {
00681          ast_mutex_unlock(&reload_lock);
00682          return 0;
00683       }
00684       ao2_ref(app, -1);
00685    }
00686 
00687    ast_mutex_unlock(&reload_lock);
00688 
00689    ast_channel_lock(chan);
00690    peer = ast_bridged_channel(chan);
00691    if (peer) {
00692       ast_channel_ref(peer);
00693    }
00694    ast_channel_unlock(chan);
00695 
00696    if (peer) {
00697       ast_channel_lock(peer);
00698       peername = ast_strdupa(peer->name);
00699       ast_channel_unlock(peer);
00700    } else if (peer2) {
00701       ast_channel_lock(peer2);
00702       peername = ast_strdupa(peer2->name);
00703       ast_channel_unlock(peer2);
00704    }
00705 
00706    if (!userdefevname) {
00707       userdefevname = "";
00708    }
00709 
00710    if (!extra) {
00711       extra = "";
00712    }
00713 
00714    eventtime = ast_tvnow();
00715 
00716    ast_channel_lock(chan);
00717 
00718    ev = ast_event_new(AST_EVENT_CEL,
00719       AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
00720       AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
00721       AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
00722       AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
00723       AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
00724          S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""),
00725       AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
00726          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
00727       AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
00728          S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, ""),
00729       AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
00730          S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, ""),
00731       AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
00732          S_OR(chan->dialed.number.str, ""),
00733       AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, chan->exten,
00734       AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, chan->context,
00735       AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, chan->name,
00736       AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->appl, ""),
00737       AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->data, ""),
00738       AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, chan->amaflags,
00739       AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, chan->accountcode,
00740       AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, chan->peeraccount,
00741       AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, chan->uniqueid,
00742       AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, chan->linkedid,
00743       AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, chan->userfield,
00744       AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
00745       AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
00746       AST_EVENT_IE_END);
00747 
00748    ast_channel_unlock(chan);
00749 
00750    if (peer) {
00751       peer = ast_channel_unref(peer);
00752    }
00753 
00754    if (ev && ast_event_queue(ev)) {
00755       ast_event_destroy(ev);
00756       return -1;
00757    }
00758 
00759    return 0;
00760 }

enum ast_cel_event_type ast_cel_str_to_event_type ( const char *  name  ) 

Get the event type from a string.

Parameters:
name the event type name as a string
Since:
1.8
Returns:
the ast_cel_event_type given by the string

Definition at line 254 of file cel.c.

References ARRAY_LEN.

Referenced by parse_events().

00255 {
00256    unsigned int i;
00257 
00258    for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
00259       if (!cel_event_types[i]) {
00260          continue;
00261       }
00262 
00263       if (!strcasecmp(name, cel_event_types[i])) {
00264          return i;
00265       }
00266    }
00267 
00268    return -1;
00269 }

static int ast_cel_track_event ( enum ast_cel_event_type  et  )  [static]

Definition at line 271 of file cel.c.

Referenced by ast_cel_check_retire_linkedid(), ast_cel_linkedid_ref(), ast_cel_report_event(), and parse_apps().

00272 {
00273    return (eventset & ((int64_t) 1 << et));
00274 }

static int do_reload ( int  is_reload  )  [static]

Definition at line 342 of file cel.c.

References ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_true(), ast_variable_retrieve(), ast_verb, config, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, parse_apps(), parse_events(), reload_lock, and set_defaults().

Referenced by ast_cel_engine_init(), and ast_cel_engine_reload().

00343 {
00344    struct ast_config *config;
00345    const char *enabled_value;
00346    const char *val;
00347    int res = 0;
00348    struct ast_flags config_flags = { 0, };
00349    const char *s;
00350 
00351    ast_mutex_lock(&reload_lock);
00352 
00353    if (!is_reload) {
00354       /* Initialize all settings before first configuration load. */
00355       set_defaults();
00356    }
00357 
00358    /*
00359     * Unfortunately we have to always load the config file because
00360     * other modules read the same file.
00361     */
00362    config = ast_config_load2(cel_conf_file, "cel", config_flags);
00363    if (!config || config == CONFIG_STATUS_FILEINVALID) {
00364       ast_log(LOG_WARNING, "Could not load %s\n", cel_conf_file);
00365       config = NULL;
00366       goto return_cleanup;
00367    }
00368    if (config == CONFIG_STATUS_FILEUNCHANGED) {
00369       /* This should never happen because we always load the config file. */
00370       config = NULL;
00371       goto return_cleanup;
00372    }
00373 
00374    if (is_reload) {
00375       /* Reset all settings before reloading configuration */
00376       set_defaults();
00377    }
00378 
00379    if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00380       cel_enabled = ast_true(enabled_value);
00381    }
00382 
00383    if (!cel_enabled) {
00384       goto return_cleanup;
00385    }
00386 
00387    /* get the date format for logging */
00388    if ((s = ast_variable_retrieve(config, "general", "dateformat"))) {
00389       ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat));
00390    }
00391 
00392    if ((val = ast_variable_retrieve(config, "general", "events"))) {
00393       parse_events(val);
00394    }
00395 
00396    if ((val = ast_variable_retrieve(config, "general", "apps"))) {
00397       parse_apps(val);
00398    }
00399 
00400 return_cleanup:
00401    ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis");
00402 
00403    ast_mutex_unlock(&reload_lock);
00404 
00405    if (config) {
00406       ast_config_destroy(config);
00407    }
00408 
00409    return res;
00410 }

static char* handle_cli_status ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 177 of file cel.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, app, ast_cli_args::argc, ast_cel_get_type_name(), ast_cli(), AST_EVENT_CEL, AST_EVENT_IE_EVENTTYPE, ast_event_report_subs(), AST_EVENT_SUB, ast_event_sub_append_ie_uint(), ast_event_sub_destroy(), ast_event_subscribe_new(), ast_mutex_lock, ast_mutex_unlock, CLI_FAILURE, CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, name, print_cel_sub(), reload_lock, and ast_cli_entry::usage.

00178 {
00179    unsigned int i;
00180    struct ast_event_sub *sub;
00181 
00182    switch (cmd) {
00183    case CLI_INIT:
00184       e->command = "cel show status";
00185       e->usage =
00186          "Usage: cel show status\n"
00187          "       Displays the Channel Event Logging system status.\n";
00188       return NULL;
00189    case CLI_GENERATE:
00190       return NULL;
00191    case CLI_HANDLER:
00192       break;
00193    }
00194 
00195    if (a->argc > 3) {
00196       return CLI_SHOWUSAGE;
00197    }
00198 
00199    ast_cli(a->fd, "CEL Logging: %s\n", cel_enabled ? "Enabled" : "Disabled");
00200 
00201    if (!cel_enabled) {
00202       return CLI_SUCCESS;
00203    }
00204 
00205    for (i = 0; i < (sizeof(eventset) * 8); i++) {
00206       const char *name;
00207 
00208       if (!(eventset & ((int64_t) 1 << i))) {
00209          continue;
00210       }
00211 
00212       name = ast_cel_get_type_name(i);
00213       if (strcasecmp(name, "Unknown")) {
00214          ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
00215       }
00216    }
00217 
00218    /* Accesses to the appset container must be done while holding the reload_lock. */
00219    ast_mutex_lock(&reload_lock);
00220    if (appset) {
00221       struct ao2_iterator iter;
00222       char *app;
00223 
00224       iter = ao2_iterator_init(appset, 0);
00225       for (;;) {
00226          app = ao2_iterator_next(&iter);
00227          if (!app) {
00228             break;
00229          }
00230          ast_mutex_unlock(&reload_lock);
00231 
00232          ast_cli(a->fd, "CEL Tracking Application: %s\n", app);
00233 
00234          ao2_ref(app, -1);
00235          ast_mutex_lock(&reload_lock);
00236       }
00237       ao2_iterator_destroy(&iter);
00238    }
00239    ast_mutex_unlock(&reload_lock);
00240 
00241    if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
00242       return CLI_FAILURE;
00243    }
00244    ast_event_sub_append_ie_uint(sub, AST_EVENT_IE_EVENTTYPE, AST_EVENT_CEL);
00245    ast_event_report_subs(sub);
00246    ast_event_sub_destroy(sub);
00247    sub = NULL;
00248 
00249    return CLI_SUCCESS;
00250 }

static int lid_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 830 of file cel.c.

References CMP_MATCH, and cel_linkedid::id.

Referenced by ast_cel_engine_init().

00831 {
00832    struct cel_linkedid *lid1 = obj;
00833    struct cel_linkedid *lid2 = arg;
00834    const char *key;
00835 
00836    key = lid2->id;
00837 
00838    return !strcasecmp(lid1->id, key) ? CMP_MATCH : 0;
00839 }

static int lid_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 820 of file cel.c.

References ast_str_case_hash(), and cel_linkedid::id.

Referenced by ast_cel_engine_init().

00821 {
00822    const struct cel_linkedid *lid = obj;
00823    const char *key;
00824 
00825    key = lid->id;
00826 
00827    return ast_str_case_hash(key);
00828 }

static void parse_apps ( const char *  val  )  [static]

Definition at line 303 of file cel.c.

References ao2_alloc, ao2_link, ao2_ref, app, AST_CEL_APP_END, AST_CEL_APP_START, ast_cel_track_event(), ast_log(), ast_strdupa, ast_strip(), ast_strlen_zero(), and LOG_WARNING.

Referenced by do_reload().

00304 {
00305    char *apps = ast_strdupa(val);
00306    char *cur_app;
00307 
00308    if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) {
00309       ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n");
00310       return;
00311    }
00312 
00313    while ((cur_app = strsep(&apps, ","))) {
00314       char *app;
00315 
00316       cur_app = ast_strip(cur_app);
00317       if (ast_strlen_zero(cur_app)) {
00318          continue;
00319       }
00320 
00321       /* The app object is immutable so it doesn't need a lock of its own. */
00322       app = ao2_alloc(strlen(cur_app) + 1, NULL);
00323       if (!app) {
00324          continue;
00325       }
00326       strcpy(app, cur_app);/* Safe */
00327 
00328       ao2_link(appset, app);
00329       ao2_ref(app, -1);
00330       app = NULL;
00331    }
00332 }

static void parse_events ( const char *  val  )  [static]

Definition at line 276 of file cel.c.

References ast_cel_str_to_event_type(), ast_log(), ast_strdupa, ast_strip(), ast_strlen_zero(), events, and LOG_WARNING.

Referenced by do_reload().

00277 {
00278    char *events = ast_strdupa(val);
00279    char *cur_event;
00280 
00281    while ((cur_event = strsep(&events, ","))) {
00282       enum ast_cel_event_type event_type;
00283 
00284       cur_event = ast_strip(cur_event);
00285       if (ast_strlen_zero(cur_event)) {
00286          continue;
00287       }
00288 
00289       event_type = ast_cel_str_to_event_type(cur_event);
00290 
00291       if (event_type == 0) {
00292          /* All events */
00293          eventset = (int64_t) -1;
00294       } else if (event_type == -1) {
00295          ast_log(LOG_WARNING, "Unknown event name '%s'\n",
00296                cur_event);
00297       } else {
00298          eventset |= ((int64_t) 1 << event_type);
00299       }
00300    }
00301 }

static void print_cel_sub ( const struct ast_event event,
void *  data 
) [static]

Definition at line 169 of file cel.c.

References ast_cli(), ast_event_get_ie_str(), AST_EVENT_IE_DESCRIPTION, and ast_cli_args::fd.

Referenced by handle_cli_status().

00170 {
00171    struct ast_cli_args *a = data;
00172 
00173    ast_cli(a->fd, "CEL Event Subscriber: %s\n",
00174          ast_event_get_ie_str(event, AST_EVENT_IE_DESCRIPTION));
00175 }

static void set_defaults ( void   )  [static]

Definition at line 334 of file cel.c.

References ao2_callback, CEL_DEFAULT_EVENTS, CEL_ENABLED_DEFAULT, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

Referenced by do_reload().

00335 {
00336    cel_enabled = CEL_ENABLED_DEFAULT;
00337    eventset = CEL_DEFAULT_EVENTS;
00338    *cel_dateformat = '\0';
00339    ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00340 }


Variable Documentation

struct ao2_container* appset [static]

Container of Asterisk application names.

The apps in this container are the applications that were specified in the configuration as applications that CEL events should be generated for when they start and end on a channel.

Note:
Accesses to the appset container must be done while holding the reload_lock.

Definition at line 100 of file cel.c.

const char* const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] [static]

Map of ast_cel_ama_flags to strings.

Definition at line 157 of file cel.c.

const char cel_conf_file[] = "cel.conf" [static]

Config file to load for the CEL feature.

Definition at line 51 of file cel.c.

char cel_dateformat[256] [static]

Configured date format for event timestamps.

Definition at line 120 of file cel.c.

unsigned char cel_enabled [static]

Is the CEL subsystem enabled ?

Definition at line 54 of file cel.c.

const char* const cel_event_types[CEL_MAX_EVENT_IDS] [static]

Map of ast_cel_event_type to strings.

Definition at line 125 of file cel.c.

struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status") [static]

Definition at line 252 of file cel.c.

int64_t eventset [static]

which events we want to track

Note:
bit field, up to 64 events

Definition at line 64 of file cel.c.

Initial value:
 {
   .type = "CEL fabricated channel",
   .destroy = ast_free_ptr,
}

Definition at line 481 of file cel.c.

struct ao2_container* linkedids [static]

Container of channel references to a linkedid for CEL purposes.

Note:
Accesses to the linkedids container must be done while holding the reload_lock.

Definition at line 115 of file cel.c.

ast_mutex_t reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Lock protecting CEL.

Note:
It protects during reloads, shutdown, and accesses to the appset and linkedids containers.

Definition at line 88 of file cel.c.

Referenced by ast_cel_check_retire_linkedid(), ast_cel_engine_term(), ast_cel_linkedid_ref(), ast_cel_report_event(), do_reload(), and handle_cli_status().


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1