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) |
struct ast_channel * | ast_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_container * | appset |
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 = 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_container * | linkedids |
static ast_mutex_t | reload_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
Channel Event Logging API.
Definition in file cel.c.
#define CEL_DEFAULT_EVENTS 0 |
#define CEL_ENABLED_DEFAULT 0 |
#define CEL_MAX_EVENT_IDS 64 |
#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().
static int app_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
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.
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.
chan | channel that is being destroyed or its linkedid is changing |
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.
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(), 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 721 of file cel.c.
References ao2_container_alloc, ao2_ref, 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().
00722 { 00723 if (!(appset = ao2_container_alloc(NUM_APP_BUCKETS, app_hash, app_cmp))) { 00724 return -1; 00725 } 00726 if (!(linkedids = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp))) { 00727 ao2_ref(appset, -1); 00728 return -1; 00729 } 00730 00731 if (do_reload() || ast_cli_register(&cli_status)) { 00732 ao2_ref(appset, -1); 00733 appset = NULL; 00734 ao2_ref(linkedids, -1); 00735 linkedids = NULL; 00736 return -1; 00737 } 00738 00739 ast_register_atexit(ast_cel_engine_term); 00740 00741 return 0; 00742 }
int ast_cel_engine_reload | ( | void | ) |
Provided by cel.c
Definition at line 744 of file cel.c.
References do_reload().
00745 { 00746 return do_reload(); 00747 }
static void ast_cel_engine_term | ( | void | ) | [static] |
Definition at line 708 of file cel.c.
References ao2_ref, and ast_cli_unregister().
Referenced by ast_cel_engine_init().
00709 { 00710 if (appset) { 00711 ao2_ref(appset, -1); 00712 appset = NULL; 00713 } 00714 if (linkedids) { 00715 ao2_ref(linkedids, -1); 00716 linkedids = NULL; 00717 } 00718 ast_cli_unregister(&cli_status); 00719 }
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.
event | the CEL event |
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, 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.
[in] | event | the CEL event |
[out] | r | the ast_cel_event_record to fill in |
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.
[in] | flag | the flag to convert to a string |
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.
type | the type to get the name of |
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.
-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(), 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.
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. |
0 | success | |
non-zero | failure |
Definition at line 537 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_request_refer(), local_attended_transfer(), manage_parked_call(), park_call_full(), parked_call_exec(), pbx_exec(), and wait_for_answer().
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.
name | the event type name as a 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, 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.
Referenced by ast_cel_engine_init(), and ast_cel_engine_reload().
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, 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, 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().
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, and LOG_WARNING.
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 }
struct ao2_container* appset [static] |
const char* const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] [static] |
char cel_dateformat[256] [static] |
unsigned char cel_enabled [static] |
const char* const cel_event_types[CEL_MAX_EVENT_IDS] [static] |
struct ast_cli_entry cli_status = AST_CLI_DEFINE(handle_cli_status, "Display the CEL status") [static] |
int64_t eventset [static] |
struct ast_datastore_info fabricated_channel_datastore [static] |
{ .type = "CEL fabricated channel", .destroy = ast_free_ptr, }
struct ao2_container* linkedids [static] |
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(), and do_reload().