[asterisk-commits] kmoore: branch kmoore/bridge_construction-cel_channels r389424 - /team/kmoore...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue May 21 15:31:46 CDT 2013


Author: kmoore
Date: Tue May 21 15:31:43 2013
New Revision: 389424

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=389424
Log:
Get CEL core converted over to the config framework, still needs some tweaks from mjordan's CDR rework

Modified:
    team/kmoore/bridge_construction-cel_channels/main/cel.c

Modified: team/kmoore/bridge_construction-cel_channels/main/cel.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/bridge_construction-cel_channels/main/cel.c?view=diff&rev=389424&r1=389423&r2=389424
==============================================================================
--- team/kmoore/bridge_construction-cel_channels/main/cel.c (original)
+++ team/kmoore/bridge_construction-cel_channels/main/cel.c Tue May 21 15:31:43 2013
@@ -53,6 +53,7 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/utils.h"
 #include "asterisk/config.h"
+#include "asterisk/config_options.h"
 #include "asterisk/cli.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/stasis_message_router.h"
@@ -60,6 +61,71 @@
 #include "asterisk/stasis_bridging.h"
 #include "asterisk/bridging.h"
 
+/*** DOCUMENTATION
+	<configInfo name="cel" language="en_US">
+		<configFile name="cel.conf">
+			<configObject name="general">
+				<synopsis>Options that apply globally to Channel Event Logging (CEL)</synopsis>
+				<configOption name="enable">
+					<synopsis>Determines whether CEL is enabled</synopsis>
+				</configOption>
+				<configOption name="dateformat">
+					<synopsis>The format to be used for dates when logging</synopsis>
+				</configOption>
+				<configOption name="apps">
+					<synopsis>List of apps for CEL to track</synopsis>
+					<description><para>A case-insensitive, comma-separated list of applications
+					to track when one or both of APP_START and APP_END events are flagged for
+					tracking</para></description>
+				</configOption>
+				<configOption name="events">
+					<synopsis>List of events for CEL to track</synopsis>
+					<description><para>A case-sensitive, comma-separated list of event names
+					to track. These event names do not include the leading <literal>AST_CEL</literal>.
+					</para>
+					<enumlist>
+						<enum name="ALL">
+							<para>Special value which tracks all events.</para>
+						</enum>
+						<enum name="CHAN_START"/>
+						<enum name="CHAN_END"/>
+						<enum name="ANSWER"/>
+						<enum name="HANGUP"/>
+						<enum name="APP_START"/>
+						<enum name="APP_END"/>
+						<enum name="BRIDGE_START"/>
+						<enum name="BRIDGE_END"/>
+						<enum name="BRIDGE_UPDATE"/>
+						<enum name="CONF_START"/>
+						<enum name="CONF_END"/>
+						<enum name="PARK_START"/>
+						<enum name="PARK_END"/>
+						<enum name="TRANSFER"/>
+						<enum name="USER_DEFINED"/>
+						<enum name="CONF_ENTER"/>
+						<enum name="CONF_EXIT"/>
+						<enum name="BLINDTRANSFER"/>
+						<enum name="ATTENDEDTRANSFER"/>
+						<enum name="PICKUP"/>
+						<enum name="FORWARD"/>
+						<enum name="3WAY_START"/>
+						<enum name="3WAY_END"/>
+						<enum name="HOOKFLASH"/>
+						<enum name="LINKEDID_END"/>
+
+					</enumlist>
+					</description>
+				</configOption>
+			</configObject>
+			<configObject name="ignored">
+				<configOption name=".*">
+					<synopsis>Dummy option used to ignore unused options in unused sections.</synopsis>
+				</configOption>
+			</configObject>
+		</configFile>
+	</configInfo>
+ ***/
+
 /*! Message router for state that CEL needs to know about */
 static struct stasis_message_router *cel_state_router;
 
@@ -80,30 +146,12 @@
 
 /*! Container for dial end multichannel blobs for holding on to dial statuses */
 static struct ao2_container *cel_dialstatus_store;
-
-/*! Is the CEL subsystem enabled ? */
-static unsigned char cel_enabled;
-
-/*! \brief CEL is off by default */
-#define CEL_ENABLED_DEFAULT		0
-
-/*!
- * \brief which events we want to track
- *
- * \note bit field, up to 64 events
- */
-static int64_t eventset;
 
 /*!
  * \brief Maximum possible CEL event IDs
  * \note This limit is currently imposed by the eventset definition
  */
 #define CEL_MAX_EVENT_IDS 64
-
-/*!
- * \brief Track no events by default.
- */
-#define CEL_DEFAULT_EVENTS	0
 
 /*!
  * \brief Number of buckets for the appset container
@@ -122,13 +170,135 @@
  * in the configuration as applications that CEL events should be generated
  * for when they start and end on a channel.
  */
-static struct ao2_container *appset;
 static struct ao2_container *linkedids;
 
-/*!
- * \brief Configured date format for event timestamps
- */
-static char cel_dateformat[256];
+/*! \brief A structure to hold global configuration-related options */
+struct cel_general_config {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(date_format); /*!< The desired date format for logging */
+	);
+	int enable;			/*!< Whether CEL is enabled */
+	int64_t events;			/*!< The events to be logged */
+	struct ao2_container *apps;	/*!< The apps for which to log app start and end events */
+};
+
+/*! \brief Destructor for cel_config */
+static void cel_general_config_dtor(void *obj)
+{
+	struct cel_general_config *cfg = obj;
+	ast_string_field_free_memory(cfg);
+	ao2_cleanup(cfg->apps);
+	cfg->apps = NULL;
+}
+
+static void *cel_general_config_alloc(void)
+{
+	RAII_VAR(struct cel_general_config *, cfg, NULL, ao2_cleanup);
+
+	if (!(cfg = ao2_alloc(sizeof(*cfg), cel_general_config_dtor))) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(cfg, 64)) {
+		return NULL;
+	}
+
+	if (!(cfg->apps = ast_str_container_alloc(NUM_APP_BUCKETS))) {
+		return NULL;
+	}
+
+	ao2_ref(cfg, +1);
+	return cfg;
+}
+
+/*! \brief A container that holds all config-related information */
+struct cel_config {
+	struct cel_general_config *general;
+};
+
+
+static AO2_GLOBAL_OBJ_STATIC(cel_configs);
+
+/*! \brief Destructor for cel_config */
+static void cel_config_dtor(void *obj)
+{
+	struct cel_config *cfg = obj;
+	ao2_cleanup(cfg->general);
+	cfg->general = NULL;
+}
+
+static void *cel_config_alloc(void)
+{
+	RAII_VAR(struct cel_config *, cfg, NULL, ao2_cleanup);
+
+	if (!(cfg = ao2_alloc(sizeof(*cfg), cel_config_dtor))) {
+		return NULL;
+	}
+
+	if (!(cfg->general = cel_general_config_alloc())) {
+		return NULL;
+	}
+
+	ao2_ref(cfg, +1);
+	return cfg;
+}
+
+/*! \brief An aco_type structure to link the "general" category to the cel_general_config type */
+static struct aco_type general_option = {
+	.type = ACO_GLOBAL,
+	.name = "general",
+	.item_offset = offsetof(struct cel_config, general),
+	.category_match = ACO_WHITELIST,
+	.category = "^general$",
+};
+
+/*! \brief An aco_type structure to catch all the config secions that we don't care about */
+static struct aco_type ignore_option = {
+	.type = ACO_GLOBAL,
+	.name = "ignored",
+	.category_match = ACO_WHITELIST,
+	.category = "^.*$",
+};
+
+/*! \brief The config file to be processed for the module. */
+static struct aco_file cel_conf = {
+	.filename = "cel.conf",					/*!< The name of the config file */
+	.types = ACO_TYPES(&general_option, &ignore_option),	/*!< The mapping object types to be processed */
+};
+
+static int cel_pre_apply_config(void);
+
+CONFIG_INFO_CORE("cel", cel_cfg_info, cel_configs, cel_config_alloc,
+	.files = ACO_FILES(&cel_conf),
+	.pre_apply_config = cel_pre_apply_config,
+);
+
+static int cel_pre_apply_config(void)
+{
+	struct cel_config *cfg = aco_pending_config(&cel_cfg_info);
+
+	if (!cfg->general) {
+		return -1;
+	}
+
+	if (!ao2_container_count(cfg->general->apps)) {
+		return 0;
+	}
+
+	if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_START)) {
+		return 0;
+	}
+
+	if (cfg->general->events & ((int64_t) 1 << AST_CEL_APP_END)) {
+		return 0;
+	}
+
+	ast_log(LOG_ERROR, "Applications are listed to be tracked, but APP events are not tracked\n");
+	return -1;
+}
+
+static struct aco_type *general_options[] = ACO_TYPES(&general_option);
+static struct aco_type *ignore_options[] = ACO_TYPES(&ignore_option);
 
 /*!
  * \brief Map of ast_cel_event_type to strings
@@ -277,7 +447,13 @@
 
 unsigned int ast_cel_check_enabled(void)
 {
-	return cel_enabled;
+	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
+
+	if (!cfg || !cfg->general) {
+		return 0;
+	}
+
+	return cfg->general->enable;
 }
 
 static int print_app(void *obj, void *arg, int flags)
@@ -301,6 +477,11 @@
 {
 	unsigned int i;
 	struct ast_event_sub *sub;
+	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
+
+	if (!cfg || !cfg->general) {
+		return CLI_FAILURE;
+	}
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -319,16 +500,16 @@
 		return CLI_SHOWUSAGE;
 	}
 
-	ast_cli(a->fd, "CEL Logging: %s\n", cel_enabled ? "Enabled" : "Disabled");
-
-	if (!cel_enabled) {
+	ast_cli(a->fd, "CEL Logging: %s\n", ast_cel_check_enabled() ? "Enabled" : "Disabled");
+
+	if (!cfg->general->enable) {
 		return CLI_SUCCESS;
 	}
 
-	for (i = 0; i < (sizeof(eventset) * 8); i++) {
+	for (i = 0; i < (sizeof(cfg->general->events) * 8); i++) {
 		const char *name;
 
-		if (!(eventset & ((int64_t) 1 << i))) {
+		if (!(cfg->general->events & ((int64_t) 1 << i))) {
 			continue;
 		}
 
@@ -338,7 +519,7 @@
 		}
 	}
 
-	ao2_callback(appset, OBJ_NODATA, print_app, a);
+	ao2_callback(cfg->general->apps, OBJ_NODATA, print_app, a);
 
 	if (!(sub = ast_event_subscribe_new(AST_EVENT_SUB, print_cel_sub, a))) {
 		return CLI_FAILURE;
@@ -372,12 +553,19 @@
 
 static int ast_cel_track_event(enum ast_cel_event_type et)
 {
-	return (eventset & ((int64_t) 1 << et));
-}
-
-static void parse_events(const char *val)
-{
-	char *events = ast_strdupa(val);
+	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
+
+	if (!cfg || !cfg->general) {
+		return 0;
+	}
+
+	return (cfg->general->events & ((int64_t) 1 << et));
+}
+
+static int events_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct cel_general_config *cfg = obj;
+	char *events = ast_strdupa(var->value);
 	char *cur_event;
 
 	while ((cur_event = strsep(&events, ","))) {
@@ -392,25 +580,23 @@
 
 		if (event_type == 0) {
 			/* All events */
-			eventset = (int64_t) -1;
+			cfg->events = (int64_t) -1;
 		} else if (event_type == -1) {
-			ast_log(LOG_WARNING, "Unknown event name '%s'\n",
-					cur_event);
+			ast_log(LOG_ERROR, "Unknown event name '%s'\n", cur_event);
+			return -1;
 		} else {
-			eventset |= ((int64_t) 1 << event_type);
-		}
-	}
-}
-
-static void parse_apps(const char *val)
-{
-	char *apps = ast_strdupa(val);
+			cfg->events |= ((int64_t) 1 << event_type);
+		}
+	}
+
+	return 0;
+}
+
+static int apps_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct cel_general_config *cfg = obj;
+	char *apps = ast_strdupa(var->value);
 	char *cur_app;
-
-	if (!ast_cel_track_event(AST_CEL_APP_START) && !ast_cel_track_event(AST_CEL_APP_END)) {
-		ast_log(LOG_WARNING, "An apps= config line, but not tracking APP events\n");
-		return;
-	}
 
 	while ((cur_app = strsep(&apps, ","))) {
 		cur_app = ast_strip(cur_app);
@@ -419,67 +605,21 @@
 		}
 
 		cur_app = ast_str_to_lower(cur_app);
-		ast_str_container_add(appset, cur_app);
-	}
-}
-
-AST_MUTEX_DEFINE_STATIC(reload_lock);
+		ast_str_container_add(cfg->apps, cur_app);
+	}
+
+	return 0;
+}
 
 static int do_reload(void)
 {
-	struct ast_config *config;
-	const char *enabled_value;
-	const char *val;
-	int res = 0;
-	struct ast_flags config_flags = { 0, };
-	const char *s;
-
-	ast_mutex_lock(&reload_lock);
-
-	/* Reset all settings before reloading configuration */
-	cel_enabled = CEL_ENABLED_DEFAULT;
-	eventset = CEL_DEFAULT_EVENTS;
-	*cel_dateformat = '\0';
-	ao2_callback(appset, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
-
-	config = ast_config_load2("cel.conf", "cel", config_flags);
-
-	if (config == CONFIG_STATUS_FILEMISSING) {
-		config = NULL;
-		goto return_cleanup;
-	}
-
-	if ((enabled_value = ast_variable_retrieve(config, "general", "enable"))) {
-		cel_enabled = ast_true(enabled_value);
-	}
-
-	if (!cel_enabled) {
-		goto return_cleanup;
-	}
-
-	/* get the date format for logging */
-	if ((s = ast_variable_retrieve(config, "general", "dateformat"))) {
-		ast_copy_string(cel_dateformat, s, sizeof(cel_dateformat));
-	}
-
-	if ((val = ast_variable_retrieve(config, "general", "events"))) {
-		parse_events(val);
-	}
-
-	if ((val = ast_variable_retrieve(config, "general", "apps"))) {
-		parse_apps(val);
-	}
-
-return_cleanup:
-	ast_verb(3, "CEL logging %sabled.\n", cel_enabled ? "en" : "dis");
-
-	ast_mutex_unlock(&reload_lock);
-
-	if (config) {
-		ast_config_destroy(config);
-	}
-
-	return res;
+	if (aco_process_config(&cel_cfg_info, 1)) {
+		return -1;
+	}
+
+	ast_verb(3, "CEL logging %sabled.\n", ast_cel_check_enabled() ? "en" : "dis");
+
+	return 0;
 }
 
 const char *ast_cel_get_type_name(enum ast_cel_event_type type)
@@ -495,6 +635,25 @@
 	}
 
 	return S_OR(cel_ama_flags[flag], "Unknown");
+}
+
+static int cel_track_app(const char *const_app)
+{
+	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
+	RAII_VAR(char *, app, NULL, ao2_cleanup);
+	char *app_lower;
+
+	if (!cfg || !cfg->general) {
+		return 0;
+	}
+
+	app_lower = ast_str_to_lower(ast_strdupa(const_app));
+	app = ao2_find(cfg->general->apps, app_lower, OBJ_KEY);
+	if (!app) {
+		return 0;
+	}
+
+	return 1;
 }
 
 static int report_event_snapshot(struct ast_channel_snapshot *snapshot,
@@ -506,8 +665,13 @@
 	char *linkedid = ast_strdupa(snapshot->linkedid);
 	char *peer_name = "";
 	RAII_VAR(struct bridge_assoc *, assoc, NULL, ao2_cleanup);
-
-	if (!cel_enabled) {
+	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
+
+	if (!cfg || !cfg->general) {
+		return 0;
+	}
+
+	if (!cfg->general->enable) {
 		return 0;
 	}
 
@@ -520,35 +684,22 @@
 		}
 	}
 
-	/* Make sure a reload is not occurring while we're checking to see if this
-	 * is an event that we care about.  We could lose an important event in this
-	 * process otherwise. */
-	ast_mutex_lock(&reload_lock);
-
 	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
 	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
 	if (ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
 		if (ast_cel_linkedid_ref(linkedid)) {
-			ast_mutex_unlock(&reload_lock);
 			return -1;
 		}
 	}
 
 	if (!ast_cel_track_event(event_type)) {
-		ast_mutex_unlock(&reload_lock);
 		return 0;
 	}
 
-	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
-		RAII_VAR(char *, app, NULL, ao2_cleanup);
-		char *app_lower = ast_str_to_lower(ast_strdupa(snapshot->appl));
-		if (!(app = ao2_find(appset, app_lower, OBJ_POINTER))) {
-			ast_mutex_unlock(&reload_lock);
-			return 0;
-		}
-	}
-
-	ast_mutex_unlock(&reload_lock);
+	if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
+		&& !cel_track_app(snapshot->appl)) {
+		return 0;
+	}
 
 	eventtime = ast_tvnow();
 
@@ -631,6 +782,11 @@
 	};
 	struct ast_datastore *datastore;
 	char *app_data;
+	RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
+
+	if (!cfg || !cfg->general) {
+		return NULL;
+	}
 
 	/* do not call ast_channel_alloc because this is not really a real channel */
 	if (!(tchan = ast_dummy_channel_alloc())) {
@@ -652,13 +808,13 @@
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
 	}
 
-	if (ast_strlen_zero(cel_dateformat)) {
+	if (ast_strlen_zero(cfg->general->date_format)) {
 		snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
 				(long) record.event_time.tv_usec);
 	} else {
 		struct ast_tm tm;
 		ast_localtime(&record.event_time, &tm, NULL);
-		ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
+		ast_strftime(timebuf, sizeof(timebuf), cfg->general->date_format, &tm);
 	}
 
 	if ((newvariable = ast_var_assign("eventtime", timebuf))) {
@@ -770,35 +926,26 @@
 	struct ast_channel *peer;
 	char *linkedid = ast_strdupa(ast_channel_linkedid(chan));
 
-	/* Make sure a reload is not occurring while we're checking to see if this
-	 * is an event that we care about.  We could lose an important event in this
-	 * process otherwise. */
-	ast_mutex_lock(&reload_lock);
+	if (!ast_cel_check_enabled()) {
+		return 0;
+	}
 
 	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
 	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
-	if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
+	if (ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
 		if (ast_cel_linkedid_ref(linkedid)) {
-			ast_mutex_unlock(&reload_lock);
 			return -1;
 		}
 	}
 
-	if (!cel_enabled || !ast_cel_track_event(event_type)) {
-		ast_mutex_unlock(&reload_lock);
+	if (!ast_cel_track_event(event_type)) {
 		return 0;
 	}
 
-	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
-		RAII_VAR(char *, app, NULL, ao2_cleanup);
-		char *app_lower = ast_str_to_lower(ast_strdupa(ast_channel_appl(chan)));
-		if (!(app = ao2_find(appset, app_lower, OBJ_POINTER))) {
-			ast_mutex_unlock(&reload_lock);
-			return 0;
-		}
-	}
-
-	ast_mutex_unlock(&reload_lock);
+	if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
+		&& !cel_track_app(ast_channel_appl(chan))) {
+		return 0;
+	}
 
 	ast_channel_lock(chan);
 	peer = ast_bridged_channel(chan);
@@ -1137,8 +1284,6 @@
 	cel_state_topic = NULL;
 	cel_channel_forwarder = stasis_unsubscribe(cel_channel_forwarder);
 	cel_bridge_forwarder = stasis_unsubscribe(cel_bridge_forwarder);
-	ao2_cleanup(appset);
-	appset = NULL;
 	ao2_cleanup(linkedids);
 	linkedids = NULL;
 	ast_cli_unregister(&cli_status);
@@ -1148,13 +1293,14 @@
 	bridge_primaries = NULL;
 }
 
+static int ignore_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	return 0;
+}
+
 int ast_cel_engine_init(void)
 {
 	int ret = 0;
-	if (!(appset = ast_str_container_alloc(NUM_APP_BUCKETS))) {
-		return -1;
-	}
-
 	if (!(linkedids = ast_str_container_alloc(NUM_APP_BUCKETS))) {
 		return -1;
 	}
@@ -1163,7 +1309,21 @@
 		return -1;
 	}
 
-	if (do_reload() || ast_cli_register(&cli_status)) {
+	if (aco_info_init(&cel_cfg_info)) {
+		return -1;
+	}
+
+	aco_option_register(&cel_cfg_info, "enable", ACO_EXACT, general_options, "no", OPT_BOOL_T, 1, FLDSET(struct cel_general_config, enable));
+	aco_option_register(&cel_cfg_info, "dateformat", ACO_EXACT, general_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct cel_general_config, date_format));
+	aco_option_register_custom(&cel_cfg_info, "apps", ACO_EXACT, general_options, "", apps_handler, 0);
+	aco_option_register_custom(&cel_cfg_info, "events", ACO_EXACT, general_options, "", events_handler, 0);
+	aco_option_register_custom(&cel_cfg_info, ".*", ACO_EXACT, ignore_options, "", ignore_handler, 0);
+
+	if (aco_process_config(&cel_cfg_info, 0)) {
+		return -1;
+	}
+
+	if (ast_cli_register(&cli_status)) {
 		return -1;
 	}
 




More information about the asterisk-commits mailing list