[svn-commits] mmichelson: branch mmichelson/agent_experiment r372130 - /team/mmichelson/age...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Sep 3 13:36:24 CDT 2012


Author: mmichelson
Date: Mon Sep  3 13:36:20 2012
New Revision: 372130

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=372130
Log:
Naive configuration implementation.

This hasn't been too well thought out at this point,
but this now uses the configuration framework to set
some basic options.

Next thing I'm going to do is to address the configuration
changes in agent login. The agent structure contains state
information, so there is no need for it to exist outside of
a call to agent_login. Therefore, the state machine will likely
undergo a change to get rid of the "logged out" state since
the agent will not actually exist in that state. The current
logic that exists for entering and exiting the logged out state
will instead happen during agent allocation and destruction.


Modified:
    team/mmichelson/agent_experiment/channels/chan_agent2.c

Modified: team/mmichelson/agent_experiment/channels/chan_agent2.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/agent_experiment/channels/chan_agent2.c?view=diff&rev=372130&r1=372129&r2=372130
==============================================================================
--- team/mmichelson/agent_experiment/channels/chan_agent2.c (original)
+++ team/mmichelson/agent_experiment/channels/chan_agent2.c Mon Sep  3 13:36:20 2012
@@ -22,6 +22,114 @@
 #include "asterisk/app.h"
 #include "asterisk/channel.h"
 #include "asterisk/bridging.h"
+#include "asterisk/config_options.h"
+
+#define AGENT_BUCKETS 37
+
+struct agent_config {
+	struct ao2_container *agents;
+};
+
+struct agent_cfg {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(id);
+		AST_STRING_FIELD(name);
+		AST_STRING_FIELD(bridge);
+	);
+	int ackcall;
+	int wrapuptime;
+};
+
+static void agent_cfg_destructor(void *obj)
+{
+	struct agent_cfg *cfg = obj;
+	ast_string_field_free_memory(cfg);
+}
+
+static void *agent_cfg_alloc(const char *cat) {
+	struct agent_cfg *cfg;
+
+	cfg = ao2_alloc(sizeof(*cfg), agent_cfg_destructor);
+
+	if (!cfg) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(cfg, 64)) {
+		ao2_ref(cfg, -1);
+		return NULL;
+	}
+
+	ast_string_field_set(cfg, id, cat);
+	return cfg;
+}
+
+static int agent_cfg_hash(const void *obj, const int flags)
+{
+	const struct agent_cfg *cfg = obj;
+	const char *id = (flags & OBJ_KEY) ? obj : cfg->id;
+	return ast_str_case_hash(id);
+}
+
+static int agent_cfg_cmp(void *obj, void *arg, int flags)
+{
+	struct agent_cfg *cfg1 = obj;
+	struct agent_cfg *cfg2 = arg;
+	const char *id = (flags & OBJ_KEY) ? arg : cfg2->id;
+	return strcasecmp(cfg1->id, id) ? 0 : (CMP_MATCH | CMP_STOP);
+}
+
+static void *agent_cfg_find(struct ao2_container *newcontainer, const char *category)
+{
+	return ao2_find(newcontainer, category, OBJ_KEY);
+}
+
+static struct aco_type agent_option = {
+	.type = ACO_GLOBAL,
+	.category_match = ACO_BLACKLIST,
+	.category = "^(general|agents)$",
+	.item_alloc = agent_cfg_alloc,
+	.item_find = agent_cfg_find,
+	.item_offset = offsetof(struct agent_config, agents),
+};
+
+struct aco_type *agent_options[] = ACO_TYPES(&agent_option);
+
+struct aco_file agent_conf = {
+	.filename = "agents.conf",
+	.types = ACO_TYPES(&agent_option),
+};
+
+static AO2_GLOBAL_OBJ_STATIC(globals);
+
+static void agent_config_destroy(void *obj)
+{
+	struct agent_config *config = obj;
+	ao2_ref(config->agents, -1);
+}
+
+static void *agent_config_alloc(void)
+{
+	struct agent_config *config;
+
+	config = ao2_alloc(sizeof(*config), agent_config_destroy);
+
+	if (!config) {
+		return NULL;
+	}
+
+	config->agents = ao2_container_alloc(AGENT_BUCKETS, agent_cfg_hash, agent_cfg_cmp); 
+	if (!config->agents) {
+		ao2_ref(config, -1);
+		return NULL;
+	}
+
+	return config;
+}
+
+CONFIG_INFO_STANDARD(cfg_info, globals, agent_config_alloc,
+	.files = ACO_FILES(&agent_conf),
+);
 
 static int agent_call(struct ast_channel *chan, const char *addr, int timeout);
 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap,
@@ -38,8 +146,8 @@
 struct agent_state;
 
 struct agent {
-	/*! The name of the agent */
-	const char *name;
+	/*! Configuration information for the agent */
+	struct agent_cfg *cfg;
 	/*! The current state of the agent */
 	const struct agent_state *current_state;
 	/*! The bridge the agent waits in while logged in */
@@ -50,25 +158,23 @@
 	const struct ast_channel_tech *saved_channel_tech;
 };
 
-#define AGENT_BUCKETS 37
-
 struct ao2_container *agents;
 
 static int agent_hash(const void *obj, int flags)
 {
 	const struct agent *agent = obj;
-	const char *name = (flags & OBJ_KEY) ? obj : agent->name;
-
-	return ast_str_case_hash(flags & OBJ_KEY ? name : agent->name);
-}
-
-static int agent_cmp(void *obj1, void *arg, int flags)
-{
-	const struct agent *agent1 = obj1;
+	const char *id = (flags & OBJ_KEY) ? obj : agent->cfg->id;
+
+	return ast_str_case_hash(id);
+}
+
+static int agent_cmp(void *obj, void *arg, int flags)
+{
+	const struct agent *agent1 = obj;
 	const struct agent *agent2 = arg;
-	const char *name = (flags & OBJ_KEY) ? arg : agent2->name;
-
-	return (!strcasecmp(agent1->name, name) ? (CMP_MATCH | CMP_STOP) : 0);
+	const char *id = (flags & OBJ_KEY) ? arg : agent2->cfg->id;
+
+	return (!strcasecmp(agent1->cfg->id, id) ? (CMP_MATCH | CMP_STOP) : 0);
 }
 
 /*!
@@ -216,14 +322,14 @@
 
 static int change_agent_state(struct agent *agent, const struct agent_state *new_state)
 {
-	ast_debug(1, "Agent %s exiting state %s\n", agent->name, agent->current_state->name);
+	ast_debug(1, "Agent %s exiting state %s\n", agent->cfg->id, agent->current_state->name);
 	if (agent->current_state->exit && agent->current_state->exit(agent)) {
 		return -1;
 	}
 
 	agent->current_state = new_state;
 
-	ast_debug(1, "Agent %s entering state %s\n", agent->name, agent->current_state->name);
+	ast_debug(1, "Agent %s entering state %s\n", agent->cfg->id, agent->current_state->name);
 	if (agent->current_state->enter && agent->current_state->enter(agent)) {
 		return -1;
 	}
@@ -231,9 +337,9 @@
 	return 0;
 }
 
-static struct agent *find_agent(const char *name)
-{
-	return ao2_find(agents, name, OBJ_KEY);
+static struct agent *find_agent(const char *id)
+{
+	return ao2_find(agents, id, OBJ_KEY);
 }
 
 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap,
@@ -258,6 +364,11 @@
 
 static int agent_call(struct ast_channel *chan, const char *addr, int timeout)
 {
+	/*XXX Address lock inversion here. chan comes in locked and then we lock
+	 * the agent. Other places have the agent locked first, then the channel.
+	 * We may need to reverse the lock order because other channel tech callbacks
+	 * will be called with the channel already locked as well.
+	 */
 	RAII_VAR(struct agent *, agent, find_agent(addr), ao2_cleanup);
 	SCOPED_AO2LOCK(lock, agent);
 
@@ -334,11 +445,21 @@
 
 static int load_module(void)
 {
-	if (ast_register_application_xml(login_app, login_exec) < 0) {
+	if (aco_info_init(&cfg_info)) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
+
 	agents = ao2_container_alloc(AGENT_BUCKETS, agent_hash, agent_cmp); 
 	if (!agents) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+
+	aco_option_register(&cfg_info, "name", ACO_EXACT, agent_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, name));
+	aco_option_register(&cfg_info, "bridge", ACO_EXACT, agent_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, bridge));
+	aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_options, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ackcall));
+	aco_option_register(&cfg_info, "wrapuptime", ACO_EXACT, agent_options, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, wrapuptime));
+
+	if (ast_register_application_xml(login_app, login_exec) < 0) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
 	return AST_MODULE_LOAD_SUCCESS;




More information about the svn-commits mailing list