Refactor CEL channel events on top of Stasis-Core

This uses the channel state change events from Stasis-Core to determine
when channel-related CEL events should be raised. Those refactored in
this patch are:
* AST_CEL_CHANNEL_START
* AST_CEL_ANSWER
* AST_CEL_APP_START
* AST_CEL_APP_END
* AST_CEL_HANGUP
* AST_CEL_CHANNEL_END

Retirement of Linked IDs is also refactored.

CEL configuration has been refactored to use the config framework.

Note: Some HANGUP events are not generated correctly because the bridge
layer does not propagate hangupcause/hangupsource information yet.

Review: https://reviewboard.asterisk.org/r/2544/
(closes issue ASTERISK-21563)


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@391622 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/78/78/1
Kinsey Moore 12 years ago
parent 65c492e851
commit 4f84e48028

@ -146,10 +146,11 @@ typedef void *(*aco_snapshot_alloc)(void);
/*! \brief The representation of a single configuration file to be processed */ /*! \brief The representation of a single configuration file to be processed */
struct aco_file { struct aco_file {
const char *filename; /*!< \brief The filename to be processed */ const char *filename; /*!< The filename to be processed */
const char *alias; /*!< \brief An alias filename to be tried if 'filename' cannot be found */ const char *alias; /*!< An alias filename to be tried if 'filename' cannot be found */
const char **preload; /*!< \brief A null-terminated oredered array of categories to be loaded first */ const char **preload; /*!< A null-terminated ordered array of categories to be loaded first */
struct aco_type *types[]; /*!< The list of types for this config. Required. Use a sentinel! */ const char *skip_category; /*!< A regular expression of categories to skip in the file. Use when a file is processed by multiple modules */
struct aco_type *types[]; /*!< The list of types for this config. Required. Use a sentinel! */
}; };
struct aco_info { struct aco_info {

@ -45,6 +45,8 @@ struct ast_bridge_snapshot {
struct ao2_container *channels; struct ao2_container *channels;
/*! Bridge flags to tweak behavior */ /*! Bridge flags to tweak behavior */
struct ast_flags feature_flags; struct ast_flags feature_flags;
/*! Bridge capabilities */
uint32_t capabilities;
/*! Number of channels participating in the bridge */ /*! Number of channels participating in the bridge */
unsigned int num_channels; unsigned int num_channels;
/*! Number of active channels in the bridge. */ /*! Number of active channels in the bridge. */

@ -52,6 +52,9 @@ struct ast_channel_snapshot {
AST_STRING_FIELD(exten); /*!< Dialplan: Current extension number */ AST_STRING_FIELD(exten); /*!< Dialplan: Current extension number */
AST_STRING_FIELD(caller_name); /*!< Caller ID Name */ AST_STRING_FIELD(caller_name); /*!< Caller ID Name */
AST_STRING_FIELD(caller_number); /*!< Caller ID Number */ AST_STRING_FIELD(caller_number); /*!< Caller ID Number */
AST_STRING_FIELD(caller_ani); /*!< Caller ID ANI Number */
AST_STRING_FIELD(caller_rdnis); /*!< Caller ID RDNIS Number */
AST_STRING_FIELD(caller_dnid); /*!< Caller ID DNID Number */
AST_STRING_FIELD(connected_name); /*!< Connected Line Name */ AST_STRING_FIELD(connected_name); /*!< Connected Line Name */
AST_STRING_FIELD(connected_number); /*!< Connected Line Number */ AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
AST_STRING_FIELD(language); /*!< The default spoken language for the channel */ AST_STRING_FIELD(language); /*!< The default spoken language for the channel */

@ -1067,4 +1067,46 @@ static force_inline int attribute_pure ast_str_case_hash(const char *str)
return abs(hash); return abs(hash);
} }
/*!
* \brief Convert a string to all lower-case
*
* \param str The string to be converted to lower case
*
* \retval str for convenience
*/
static force_inline char *attribute_pure ast_str_to_lower(char *str)
{
char *str_orig = str;
if (!str) {
return str;
}
for (; *str; ++str) {
*str = tolower(*str);
}
return str_orig;
}
/*!
* \brief Convert a string to all upper-case
*
* \param str The string to be converted to upper case
*
* \retval str for convenience
*/
static force_inline char *attribute_pure ast_str_to_upper(char *str)
{
char *str_orig = str;
if (!str) {
return str;
}
for (; *str; ++str) {
*str = toupper(*str);
}
return str_orig;
}
#endif /* _ASTERISK_STRINGS_H */ #endif /* _ASTERISK_STRINGS_H */

@ -4323,11 +4323,6 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
if (ast_cel_engine_init()) {
printf("%s", term_quit());
exit(1);
}
if (ast_device_state_engine_init()) { if (ast_device_state_engine_init()) {
printf("%s", term_quit()); printf("%s", term_quit());
exit(1); exit(1);
@ -4371,6 +4366,11 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
if (ast_cel_engine_init()) {
printf("%s", term_quit());
exit(1);
}
if (ast_local_init()) { if (ast_local_init()) {
printf("%s", term_quit()); printf("%s", term_quit());
exit(1); exit(1);

File diff suppressed because it is too large Load Diff

@ -1058,14 +1058,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
ast_channel_timingfd_set(tmp, ast_timer_fd(ast_channel_timer(tmp))); ast_channel_timingfd_set(tmp, ast_timer_fd(ast_channel_timer(tmp)));
} }
/*
* This is the last place the channel constructor can fail.
*
* The destructor takes advantage of this fact to ensure that the
* AST_CEL_CHANNEL_END is not posted if we have not posted the
* AST_CEL_CHANNEL_START yet.
*/
if (needqueue && ast_channel_internal_alertpipe_init(tmp)) { if (needqueue && ast_channel_internal_alertpipe_init(tmp)) {
return ast_channel_unref(tmp); return ast_channel_unref(tmp);
} }
@ -1151,7 +1143,6 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
ast_cdr_start(ast_channel_cdr(tmp)); ast_cdr_start(ast_channel_cdr(tmp));
ast_atomic_fetchadd_int(&chancount, +1); ast_atomic_fetchadd_int(&chancount, +1);
ast_cel_report_event(tmp, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
headp = ast_channel_varshead(tmp); headp = ast_channel_varshead(tmp);
AST_LIST_HEAD_INIT_NOLOCK(headp); AST_LIST_HEAD_INIT_NOLOCK(headp);
@ -2389,11 +2380,6 @@ static void ast_channel_destructor(void *obj)
publish_cache_clear(chan); publish_cache_clear(chan);
if (ast_channel_internal_is_finalized(chan)) {
ast_cel_report_event(chan, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
ast_cel_check_retire_linkedid(chan);
}
ast_pbx_hangup_handler_destroy(chan); ast_pbx_hangup_handler_destroy(chan);
ast_channel_lock(chan); ast_channel_lock(chan);
@ -2808,8 +2794,6 @@ static void destroy_hooks(struct ast_channel *chan)
/*! \brief Hangup a channel */ /*! \brief Hangup a channel */
int ast_hangup(struct ast_channel *chan) int ast_hangup(struct ast_channel *chan)
{ {
char extra_str[64]; /* used for cel logging below */
ast_autoservice_stop(chan); ast_autoservice_stop(chan);
ast_channel_lock(chan); ast_channel_lock(chan);
@ -2884,9 +2868,6 @@ int ast_hangup(struct ast_channel *chan)
ast_channel_generatordata_set(chan, NULL); ast_channel_generatordata_set(chan, NULL);
ast_channel_generator_set(chan, NULL); ast_channel_generator_set(chan, NULL);
snprintf(extra_str, sizeof(extra_str), "%d,%s,%s", ast_channel_hangupcause(chan), ast_channel_hangupsource(chan), S_OR(pbx_builtin_getvar_helper(chan, "DIALSTATUS"), ""));
ast_cel_report_event(chan, AST_CEL_HANGUP, NULL, extra_str, NULL);
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)) { if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING)) {
ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd " ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
"is blocked by thread %ld in procedure %s! Expect a failure\n", "is blocked by thread %ld in procedure %s! Expect a failure\n",
@ -2951,11 +2932,9 @@ int ast_raw_answer(struct ast_channel *chan, int cdr_answer)
if (cdr_answer) { if (cdr_answer) {
ast_cdr_answer(ast_channel_cdr(chan)); ast_cdr_answer(ast_channel_cdr(chan));
} }
ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
ast_channel_unlock(chan); ast_channel_unlock(chan);
break; break;
case AST_STATE_UP: case AST_STATE_UP:
ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
/* Calling ast_cdr_answer when it it has previously been called /* Calling ast_cdr_answer when it it has previously been called
* is essentially a no-op, so it is safe. * is essentially a no-op, so it is safe.
*/ */
@ -4101,8 +4080,6 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
} else { } else {
/* Answer the CDR */ /* Answer the CDR */
ast_setstate(chan, AST_STATE_UP); ast_setstate(chan, AST_STATE_UP);
/* removed a call to ast_cdr_answer(chan->cdr) from here. */
ast_cel_report_event(chan, AST_CEL_ANSWER, NULL, NULL, NULL);
} }
} else if (f->subclass.integer == AST_CONTROL_READ_ACTION) { } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) {
read_action_payload = f->data.ptr; read_action_payload = f->data.ptr;
@ -6611,7 +6588,6 @@ static void ast_channel_change_linkedid(struct ast_channel *chan, const char *li
return; return;
} }
ast_cel_check_retire_linkedid(chan);
ast_channel_linkedid_set(chan, linkedid); ast_channel_linkedid_set(chan, linkedid);
ast_cel_linkedid_ref(linkedid); ast_cel_linkedid_ref(linkedid);
} }

@ -435,12 +435,23 @@ static int process_category(struct ast_config *cfg, struct aco_info *info, struc
* We do not grab a reference to these objects, as the info already holds references to them. This * We do not grab a reference to these objects, as the info already holds references to them. This
* pointer is just a convenience. Do not actually store it somewhere. */ * pointer is just a convenience. Do not actually store it somewhere. */
void **field; void **field;
regex_t *regex_skip;
/* Skip preloaded categories if we aren't preloading */ /* Skip preloaded categories if we aren't preloading */
if (!preload && is_preload(file, cat)) { if (!preload && is_preload(file, cat)) {
return 0; return 0;
} }
/* Skip the category if we've been told to ignore it */
if (!ast_strlen_zero(file->skip_category)) {
regex_skip = build_regex(file->skip_category);
if (!regexec(regex_skip, cat, 0, NULL, 0)) {
ast_free(regex_skip);
return 0;
}
ast_free(regex_skip);
}
/* Find aco_type by category, if not found it is an error */ /* Find aco_type by category, if not found it is an error */
if (!(type = internal_aco_type_find(file, cfg, cat))) { if (!(type = internal_aco_type_find(file, cfg, cat))) {
ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename); ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);

@ -1574,14 +1574,12 @@ int pbx_exec(struct ast_channel *c, /*!< Channel */
ast_channel_appl_set(c, app->name); ast_channel_appl_set(c, app->name);
ast_channel_data_set(c, data); ast_channel_data_set(c, data);
ast_cel_report_event(c, AST_CEL_APP_START, NULL, NULL, NULL);
if (app->module) if (app->module)
u = __ast_module_user_add(app->module, c); u = __ast_module_user_add(app->module, c);
res = app->execute(c, S_OR(data, "")); res = app->execute(c, S_OR(data, ""));
if (app->module && u) if (app->module && u)
__ast_module_user_remove(app->module, u); __ast_module_user_remove(app->module, u);
ast_cel_report_event(c, AST_CEL_APP_END, NULL, NULL, NULL);
/* restore channel values */ /* restore channel values */
ast_channel_appl_set(c, saved_c_appl); ast_channel_appl_set(c, saved_c_appl);
ast_channel_data_set(c, saved_c_data); ast_channel_data_set(c, saved_c_data);

@ -94,6 +94,7 @@ struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge
ast_string_field_set(snapshot, technology, bridge->technology->name); ast_string_field_set(snapshot, technology, bridge->technology->name);
snapshot->feature_flags = bridge->feature_flags; snapshot->feature_flags = bridge->feature_flags;
snapshot->capabilities = bridge->technology->capabilities;
snapshot->num_channels = bridge->num_channels; snapshot->num_channels = bridge->num_channels;
snapshot->num_active = bridge->num_active; snapshot->num_active = bridge->num_active;

@ -35,6 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/stasis.h" #include "asterisk/stasis.h"
#include "asterisk/astobj2.h" #include "asterisk/astobj2.h"
#include "asterisk/stasis_channels.h" #include "asterisk/stasis_channels.h"
#include "asterisk/pbx.h"
/*** DOCUMENTATION /*** DOCUMENTATION
<managerEvent language="en_US" name="VarSet"> <managerEvent language="en_US" name="VarSet">
@ -159,6 +160,13 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
ast_string_field_set(snapshot, caller_number, ast_string_field_set(snapshot, caller_number,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "")); S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
ast_string_field_set(snapshot, caller_ani,
S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
ast_string_field_set(snapshot, caller_rdnis,
S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
ast_string_field_set(snapshot, caller_dnid,
S_OR(ast_channel_dialed(chan)->number.str, ""));
ast_string_field_set(snapshot, connected_name, ast_string_field_set(snapshot, connected_name,
S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "")); S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
ast_string_field_set(snapshot, connected_number, ast_string_field_set(snapshot, connected_number,

Loading…
Cancel
Save