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_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 (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_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 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_container * | linkedids |
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. |
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 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().
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 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.
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.
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 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.
event | the CEL event |
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.
[in] | event | the CEL event |
[out] | r | the ast_cel_event_record to fill in |
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.
[in] | flag | the flag to convert to a string |
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.
type | the type to get the name of |
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.
-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.
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 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.
name | the event type name as a 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 }
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.
const char* const cel_ama_flags[AST_CEL_AMA_FLAG_TOTAL] [static] |
const char cel_conf_file[] = "cel.conf" [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] |
Lock protecting CEL.
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().