Mon Oct 8 12:39:12 2012

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.

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 lid_cmp   app_cmp
#define lid_hash   app_hash
#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)
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 (void)
static char * handle_cli_status (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void parse_apps (const char *val)
static void parse_events (const char *val)
static int print_app (void *obj, void *arg, int flags)
static void print_cel_sub (const struct ast_event *event, void *data)

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 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 = { .handler = handle_cli_status , .summary = "Display the CEL status" ,__VA_ARGS__ }
static int64_t eventset
 which events we want to track
static struct ast_datastore_info fabricated_channel_datastore
static struct ao2_containerlinkedids
static ast_mutex_t reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }


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 72 of file cel.c.

Referenced by do_reload().

#define CEL_ENABLED_DEFAULT   0

CEL is off by default.

Definition at line 54 of file cel.c.

Referenced by do_reload().

#define CEL_MAX_EVENT_IDS   64

Maximum possible CEL event IDs.

Note:
This limit is currently imposed by the eventset definition

Definition at line 67 of file cel.c.

#define lid_cmp   app_cmp

Definition at line 706 of file cel.c.

Referenced by ast_cel_engine_init().

#define lid_hash   app_hash

Definition at line 705 of file cel.c.

Referenced by ast_cel_engine_init().

#define NUM_APP_BUCKETS   97

Number of buckets for the appset container.

Definition at line 77 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 698 of file cel.c.

References app1, app2, CMP_MATCH, and CMP_STOP.

Referenced by ast_cel_engine_init().

00699 {
00700    const char *app1 = obj, *app2 = arg;
00701 
00702    return !strcasecmp(app1, app2) ? CMP_MATCH | CMP_STOP : 0;
00703 }

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

Definition at line 693 of file cel.c.

References ast_str_case_hash().

Referenced by ast_cel_engine_init().

00694 {
00695    return ast_str_case_hash((const char *) obj);
00696 }

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 136 of file cel.c.

00137 {
00138    return cel_enabled;
00139 }

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 368 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_strlen_zero(), ast_channel::linkedid, linkedids, LOG_ERROR, and OBJ_POINTER.

Referenced by ast_channel_change_linkedid(), and ast_channel_destructor().

00369 {
00370    const char *linkedid = chan->linkedid;
00371    char *lid;
00372 
00373    /* make sure we need to do all this work */
00374 
00375    if (ast_strlen_zero(linkedid) || !ast_cel_track_event(AST_CEL_LINKEDID_END)) {
00376       return;
00377    }
00378 
00379    if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) {
00380       ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n", linkedid);
00381       return;
00382    }
00383 
00384    /* We have a ref for each channel with this linkedid, the link and the above find, so if
00385     * before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */
00386    if (ao2_ref(lid, -1) == 3) {
00387       ao2_unlink(linkedids, lid);
00388       ast_cel_report_event(chan, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
00389    }
00390    ao2_ref(lid, -1);
00391 }

int ast_cel_engine_init ( void   ) 

Provided by cel.c

Definition at line 716 of file cel.c.

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

Referenced by main().

00717 {
00718    if (!(appset = ao2_container_alloc(NUM_APP_BUCKETS, app_hash, app_cmp))) {
00719       return -1;
00720    }
00721    if (!(linkedids = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp))) {
00722       ao2_ref(appset, -1);
00723       return -1;
00724    }
00725 
00726    if (do_reload() || ast_cli_register(&cli_status)) {
00727       ao2_ref(appset, -1);
00728       appset = NULL;
00729       ao2_ref(linkedids, -1);
00730       linkedids = NULL;
00731       return -1;
00732    }
00733 
00734    ast_register_atexit(ast_cel_engine_term);
00735 
00736    return 0;
00737 }

int ast_cel_engine_reload ( void   ) 

Provided by cel.c

Definition at line 739 of file cel.c.

References do_reload().

00740 {
00741    return do_reload();
00742 }

static void ast_cel_engine_term ( void   )  [static]

Definition at line 708 of file cel.c.

References ao2_ref, and appset.

Referenced by ast_cel_engine_init().

00709 {
00710    if (appset) {
00711       ao2_ref(appset, -1);
00712       appset = NULL;
00713    }
00714 }

struct ast_channel* ast_cel_fabricate_channel_from_event ( const struct ast_event event  ) 

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 401 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, fabricated_channel_datastore, 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.

00402 {
00403    struct varshead *headp;
00404    struct ast_var_t *newvariable;
00405    char timebuf[30];
00406    struct ast_channel *tchan;
00407    struct ast_cel_event_record record = {
00408       .version = AST_CEL_EVENT_RECORD_VERSION,
00409    };
00410    struct ast_datastore *datastore;
00411    char *app_data;
00412 
00413    /* do not call ast_channel_alloc because this is not really a real channel */
00414    if (!(tchan = ast_dummy_channel_alloc())) {
00415       return NULL;
00416    }
00417 
00418    headp = &tchan->varshead;
00419 
00420    /* first, get the variables from the event */
00421    if (ast_cel_fill_record(event, &record)) {
00422       ast_channel_unref(tchan);
00423       return NULL;
00424    }
00425 
00426    /* next, fill the channel with their data */
00427    if ((newvariable = ast_var_assign("eventtype", record.event_name))) {
00428       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00429    }
00430 
00431    if (ast_strlen_zero(cel_dateformat)) {
00432       snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
00433             (long) record.event_time.tv_usec);
00434    } else {
00435       struct ast_tm tm;
00436       ast_localtime(&record.event_time, &tm, NULL);
00437       ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
00438    }
00439 
00440    if ((newvariable = ast_var_assign("eventtime", timebuf))) {
00441       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00442    }
00443 
00444    if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
00445       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00446    }
00447    if ((newvariable = ast_var_assign("eventextra", record.extra))) {
00448       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00449    }
00450 
00451    tchan->caller.id.name.valid = 1;
00452    tchan->caller.id.name.str = ast_strdup(record.caller_id_name);
00453    tchan->caller.id.number.valid = 1;
00454    tchan->caller.id.number.str = ast_strdup(record.caller_id_num);
00455    tchan->caller.ani.number.valid = 1;
00456    tchan->caller.ani.number.str = ast_strdup(record.caller_id_ani);
00457    tchan->redirecting.from.number.valid = 1;
00458    tchan->redirecting.from.number.str = ast_strdup(record.caller_id_rdnis);
00459    tchan->dialed.number.str = ast_strdup(record.caller_id_dnid);
00460 
00461    ast_copy_string(tchan->exten, record.extension, sizeof(tchan->exten));
00462    ast_copy_string(tchan->context, record.context, sizeof(tchan->context));
00463    ast_string_field_set(tchan, name, record.channel_name);
00464    ast_string_field_set(tchan, uniqueid, record.unique_id);
00465    ast_string_field_set(tchan, linkedid, record.linked_id);
00466    ast_string_field_set(tchan, accountcode, record.account_code);
00467    ast_string_field_set(tchan, peeraccount, record.peer_account);
00468    ast_string_field_set(tchan, userfield, record.user_field);
00469 
00470    if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
00471       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
00472    }
00473 
00474    tchan->amaflags = record.amaflag;
00475 
00476    /* We need to store an 'application name' and 'application
00477     * data' on the channel for logging purposes, but the channel
00478     * structure only provides a place to store pointers, and it
00479     * expects these pointers to be pointing to data that does not
00480     * need to be freed. This means that the channel's destructor
00481     * does not attempt to free any storage that these pointers
00482     * point to. However, we can't provide data in that form directly for
00483     * these structure members. In order to ensure that these data
00484     * elements have a lifetime that matches the channel's
00485     * lifetime, we'll put them in a datastore attached to the
00486     * channel, and set's the channel's pointers to point into the
00487     * datastore.  The datastore will then be automatically destroyed
00488     * when the channel is destroyed.
00489     */
00490 
00491    if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
00492       ast_channel_unref(tchan);
00493       return NULL;
00494    }
00495 
00496    if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
00497       ast_datastore_free(datastore);
00498       ast_channel_unref(tchan);
00499       return NULL;
00500    }
00501 
00502    tchan->appl = strcpy(app_data, record.application_name);
00503    tchan->data = strcpy(app_data + strlen(record.application_name) + 1,
00504       record.application_data);
00505 
00506    datastore->data = app_data;
00507    ast_channel_datastore_add(tchan, datastore);
00508 
00509    return tchan;
00510 }

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 648 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().

00649 {
00650    if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
00651       ast_log(LOG_ERROR, "Module ABI mismatch for ast_cel_event_record.  "
00652             "Please ensure all modules were compiled for "
00653             "this version of Asterisk.\n");
00654       return -1;
00655    }
00656 
00657    r->event_type = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TYPE);
00658 
00659    r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
00660    r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
00661 
00662    r->user_defined_name = "";
00663 
00664    if (r->event_type == AST_CEL_USER_DEFINED) {
00665       r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
00666       r->event_name = r->user_defined_name;
00667    } else {
00668       r->event_name = ast_cel_get_type_name(r->event_type);
00669    }
00670 
00671    r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
00672    r->caller_id_num    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
00673    r->caller_id_ani    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
00674    r->caller_id_rdnis  = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDRDNIS), "");
00675    r->caller_id_dnid   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDDNID), "");
00676    r->extension        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTEN), "");
00677    r->context          = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CONTEXT), "");
00678    r->channel_name     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CHANNAME), "");
00679    r->application_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPNAME), "");
00680    r->application_data = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_APPDATA), "");
00681    r->account_code     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00682    r->peer_account     = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_ACCTCODE), "");
00683    r->unique_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_UNIQUEID), "");
00684    r->linked_id        = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_LINKEDID), "");
00685    r->amaflag          = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_AMAFLAGS);
00686    r->user_field       = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USERFIELD), "");
00687    r->peer             = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_PEER), "");
00688    r->extra            = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_EXTRA), "");
00689 
00690    return 0;
00691 }

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 356 of file cel.c.

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

00357 {
00358    if (flag < 0 || flag >= ARRAY_LEN(cel_ama_flags)) {
00359       ast_log(LOG_WARNING, "Invalid AMA flag: %d\n", flag);
00360       return "Unknown";
00361    }
00362 
00363    return S_OR(cel_ama_flags[flag], "Unknown");
00364 }

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 351 of file cel.c.

References S_OR.

Referenced by ast_cel_fill_record(), and handle_cli_status().

00352 {
00353    return S_OR(cel_event_types[type], "Unknown");
00354 }

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 512 of file cel.c.

References ao2_alloc, ao2_find, ao2_link, ao2_ref, ast_log(), ast_strlen_zero(), linkedids, LOG_ERROR, and OBJ_POINTER.

Referenced by ast_cel_report_event(), and ast_channel_change_linkedid().

00513 {
00514    char *lid;
00515 
00516    if (ast_strlen_zero(linkedid)) {
00517       ast_log(LOG_ERROR, "The linkedid should never be empty\n");
00518       return -1;
00519    }
00520 
00521    if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) {
00522       if (!(lid = ao2_alloc(strlen(linkedid) + 1, NULL))) {
00523          return -1;
00524       }
00525       strcpy(lid, linkedid);
00526       if (!ao2_link(linkedids, lid)) {
00527          ao2_ref(lid, -1);
00528          return -1;
00529       }
00530       /* Leave both the link and the alloc refs to show a count of 1 + the link */
00531    }
00532    /* If we've found, go ahead and keep the ref to increment count of how many channels
00533     * have this linkedid. We'll clean it up in check_retire */
00534    return 0;
00535 }

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 537 of file cel.c.

References ast_channel::accountcode, ast_channel::amaflags, ast_party_caller::ani, ao2_find, ao2_ref, app, ast_channel::appl, appset, 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_channel::linkedid, ast_channel::name, ast_party_id::name, ast_party_dialed::number, ast_party_id::number, OBJ_POINTER, ast_channel::peeraccount, ast_channel::redirecting, reload_lock, S_COR, S_OR, ast_party_dialed::str, ast_party_number::str, ast_party_name::str, ast_channel::uniqueid, ast_channel::userfield, 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_request_refer(), local_attended_transfer(), manage_parked_call(), park_call_full(), parked_call_exec(), and pbx_exec().

00539 {
00540    struct timeval eventtime;
00541    struct ast_event *ev;
00542    const char *peername = "";
00543    struct ast_channel *peer;
00544 
00545    /* Make sure a reload is not occurring while we're checking to see if this
00546     * is an event that we care about.  We could lose an important event in this
00547     * process otherwise. */
00548    ast_mutex_lock(&reload_lock);
00549 
00550    /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
00551     * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
00552    if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && chan->linkedid) {
00553       if (ast_cel_linkedid_ref(chan->linkedid)) {
00554          ast_mutex_unlock(&reload_lock);
00555          return -1;
00556       }
00557    }
00558 
00559    if (!cel_enabled || !ast_cel_track_event(event_type)) {
00560       ast_mutex_unlock(&reload_lock);
00561       return 0;
00562    }
00563 
00564    if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
00565       char *app;
00566       if (!(app = ao2_find(appset, (char *) chan->appl, OBJ_POINTER))) {
00567          ast_mutex_unlock(&reload_lock);
00568          return 0;
00569       }
00570       ao2_ref(app, -1);
00571    }
00572 
00573    ast_mutex_unlock(&reload_lock);
00574 
00575    ast_channel_lock(chan);
00576    peer = ast_bridged_channel(chan);
00577    if (peer) {
00578       ast_channel_ref(peer);
00579    }
00580    ast_channel_unlock(chan);
00581 
00582    if (peer) {
00583       ast_channel_lock(peer);
00584       peername = ast_strdupa(peer->name);
00585       ast_channel_unlock(peer);
00586    } else if (peer2) {
00587       ast_channel_lock(peer2);
00588       peername = ast_strdupa(peer2->name);
00589       ast_channel_unlock(peer2);
00590    }
00591 
00592    if (!userdefevname) {
00593       userdefevname = "";
00594    }
00595 
00596    if (!extra) {
00597       extra = "";
00598    }
00599 
00600    eventtime = ast_tvnow();
00601 
00602    ast_channel_lock(chan);
00603 
00604    ev = ast_event_new(AST_EVENT_CEL,
00605       AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
00606       AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
00607       AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
00608       AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
00609       AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
00610          S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""),
00611       AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
00612          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
00613       AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
00614          S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, ""),
00615       AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
00616          S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, ""),
00617       AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
00618          S_OR(chan->dialed.number.str, ""),
00619       AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, chan->exten,
00620       AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, chan->context,
00621       AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, chan->name,
00622       AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->appl, ""),
00623       AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->data, ""),
00624       AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, chan->amaflags,
00625       AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, chan->accountcode,
00626       AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, chan->peeraccount,
00627       AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, chan->uniqueid,
00628       AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, chan->linkedid,
00629       AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, chan->userfield,
00630       AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
00631       AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
00632       AST_EVENT_IE_END);
00633 
00634    ast_channel_unlock(chan);
00635 
00636    if (peer) {
00637       peer = ast_channel_unref(peer);
00638    }
00639 
00640    if (ev && ast_event_queue(ev)) {
00641       ast_event_destroy(ev);
00642       return -1;
00643    }
00644 
00645    return 0;
00646 }

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 214 of file cel.c.

References ARRAY_LEN.

Referenced by parse_events().

00215 {
00216    unsigned int i;
00217 
00218    for (i = 0; i < ARRAY_LEN(cel_event_types); i++) {
00219       if (!cel_event_types[i]) {
00220          continue;
00221       }
00222 
00223       if (!strcasecmp(name, cel_event_types[i])) {
00224          return i;
00225       }
00226    }
00227 
00228    return -1;
00229 }

static int ast_cel_track_event ( enum ast_cel_event_type  et  )  [static]

Definition at line 231 of file cel.c.

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

00232 {
00233    return (eventset & ((int64_t) 1 << et));
00234 }

static int do_reload ( void   )  [static]

Definition at line 294 of file cel.c.

References ao2_callback, appset, ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_mutex_lock, ast_mutex_unlock, ast_true(), ast_variable_retrieve(), ast_verb, CEL_DEFAULT_EVENTS, CEL_ENABLED_DEFAULT, config, CONFIG_STATUS_FILEMISSING, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, parse_apps(), parse_events(), and reload_lock.

00295 {
00296    struct ast_config *config;
00297    const char *enabled_value;
00298    const char *val;
00299    int res = 0;
00300    struct ast_flags config_flags = { 0, };
00301    const char *s;
00302 
00303    ast_mutex_lock(&reload_lock);
00304 
00305    /* Reset all settings before reloading configuration */
00306    cel_enabled = CEL_ENABLED_DEFAULT;
00307    eventset = CEL_DEFAULT_EVENTS;
00308    *cel_dateformat = '\0';
00309    ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00310 
00311    config = ast_config_load2("cel.conf", "cel", config_flags);
00312 
00313    if (config == CONFIG_STATUS_FILEMISSING) {
00314       config = NULL;
00315       goto return_cleanup;
00316    }
00317 
00318    if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
00319       cel_enabled = ast_true(enabled_value);
00320    }
00321 
00322    if (!cel_enabled) {
00323       goto return_cleanup;
00324    }
00325 
00326    /* get the date format for logging */
00327    if ((s = ast_variable_retrieve(config, "general", "dateformat"))) {
00328       ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat));
00329    }
00330 
00331    if ((val = ast_variable_retrieve(config, "general", "events"))) {
00332       parse_events(val);
00333    }
00334 
00335    if ((val = ast_variable_retrieve(config, "general", "apps"))) {
00336       parse_apps(val);
00337    }
00338 
00339 return_cleanup:
00340    ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis");
00341 
00342    ast_mutex_unlock(&reload_lock);
00343 
00344    if (config) {
00345       ast_config_destroy(config);
00346    }
00347 
00348    return res;
00349 }

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

Definition at line 158 of file cel.c.

References ao2_callback, appset, 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(), CLI_FAILURE, CLI_GENERATE, CLI_HANDLER, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, name, OBJ_NODATA, print_app(), print_cel_sub(), and ast_cli_entry::usage.

00159 {
00160    unsigned int i;
00161    struct ast_event_sub *sub;
00162 
00163    switch (cmd) {
00164    case CLI_INIT:
00165       e->command = "cel show status";
00166       e->usage =
00167          "Usage: cel show status\n"
00168          "       Displays the Channel Event Logging system status.\n";
00169       return NULL;
00170    case CLI_GENERATE:
00171       return NULL;
00172    case CLI_HANDLER:
00173       break;
00174    }
00175 
00176    if (a->argc > 3) {
00177       return CLI_SHOWUSAGE;
00178    }
00179 
00180    ast_cli(a->fd, "CEL Logging: %s\n", cel_enabled ? "Enabled" : "Disabled");
00181 
00182    if (!cel_enabled) {
00183       return CLI_SUCCESS;
00184    }
00185 
00186    for (i = 0; i < (sizeof(eventset) * 8); i++) {
00187       const char *name;
00188 
00189       if (!(eventset & ((int64_t) 1 << i))) {
00190          continue;
00191       }
00192 
00193       name = ast_cel_get_type_name(i);
00194       if (strcasecmp(name, "Unknown")) {
00195          ast_cli(a->fd, "CEL Tracking Event: %s\n", name);
00196       }
00197    }
00198 
00199    ao2_callback(appset, OBJ_NODATA, print_app, a);
00200 
00201    if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
00202       return CLI_FAILURE;
00203    }
00204    ast_event_sub_append_ie_uint(sub, AST_EVENT_IE_EVENTTYPE, AST_EVENT_CEL);
00205    ast_event_report_subs(sub);
00206    ast_event_sub_destroy(sub);
00207    sub = NULL;
00208 
00209    return CLI_SUCCESS;
00210 }

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

Definition at line 263 of file cel.c.

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

Referenced by do_reload().

00264 {
00265    char *apps = ast_strdupa(val);
00266    char *cur_app;
00267 
00268    if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) {
00269       ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n");
00270       return;
00271    }
00272 
00273    while ((cur_app = strsep(&apps, ","))) {
00274       char *app;
00275 
00276       cur_app = ast_strip(cur_app);
00277       if (ast_strlen_zero(cur_app)) {
00278          continue;
00279       }
00280 
00281       if (!(app = ao2_alloc(strlen(cur_app) + 1, NULL))) {
00282          continue;
00283       }
00284       strcpy(app, cur_app);
00285 
00286       ao2_link(appset, app);
00287       ao2_ref(app, -1);
00288       app = NULL;
00289    }
00290 }

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

Definition at line 236 of file cel.c.

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

Referenced by do_reload().

00237 {
00238    char *events = ast_strdupa(val);
00239    char *cur_event;
00240 
00241    while ((cur_event = strsep(&events, ","))) {
00242       enum ast_cel_event_type event_type;
00243 
00244       cur_event = ast_strip(cur_event);
00245       if (ast_strlen_zero(cur_event)) {
00246          continue;
00247       }
00248 
00249       event_type = ast_cel_str_to_event_type(cur_event);
00250 
00251       if (event_type == 0) {
00252          /* All events */
00253          eventset = (int64_t) -1;
00254       } else if (event_type == -1) {
00255          ast_log(LOG_WARNING, "Unknown event name '%s'\n",
00256                cur_event);
00257       } else {
00258          eventset |= ((int64_t) 1 << event_type);
00259       }
00260    }
00261 }

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

Definition at line 141 of file cel.c.

References ast_cli(), and ast_cli_args::fd.

Referenced by handle_cli_status().

00142 {
00143    struct ast_cli_args *a = arg;
00144 
00145    ast_cli(a->fd, "CEL Tracking Application: %s\n", (const char *) obj);
00146 
00147    return 0;
00148 }

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

Definition at line 150 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().

00151 {
00152    struct ast_cli_args *a = data;
00153 
00154    ast_cli(a->fd, "CEL Event Subscriber: %s\n",
00155          ast_event_get_ie_str(event, AST_EVENT_IE_DESCRIPTION));
00156 }


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.

Definition at line 86 of file cel.c.

Referenced by ast_cel_engine_init(), ast_cel_engine_term(), ast_cel_report_event(), do_reload(), handle_cli_status(), and parse_apps().

const char* const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] [static]

Map of ast_cel_ama_flags to strings.

Definition at line 129 of file cel.c.

char cel_dateformat[256] [static]

Configured date format for event timestamps.

Definition at line 92 of file cel.c.

unsigned char cel_enabled [static]

Is the CEL subsystem enabled ?

Definition at line 51 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 97 of file cel.c.

struct ast_cli_entry cli_status = { .handler = handle_cli_status , .summary = "Display the CEL status" ,__VA_ARGS__ } [static]

Definition at line 212 of file cel.c.

int64_t eventset [static]

which events we want to track

Note:
bit field, up to 64 events

Definition at line 61 of file cel.c.

struct ast_datastore_info fabricated_channel_datastore [static]

Initial value:

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

Definition at line 396 of file cel.c.

Referenced by ast_cel_fabricate_channel_from_event().

struct ao2_container* linkedids [static]

Definition at line 87 of file cel.c.

Referenced by ast_cel_check_retire_linkedid(), ast_cel_engine_init(), and ast_cel_linkedid_ref().

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

Definition at line 292 of file cel.c.

Referenced by ast_cel_report_event(), do_reload(), and pbx_load_module().


Generated on Mon Oct 8 12:39:12 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7