[asterisk-commits] file: branch file/chan_jingle2 r368694 - /team/file/chan_jingle2/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 8 09:44:50 CDT 2012


Author: file
Date: Fri Jun  8 09:44:47 2012
New Revision: 368694

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=368694
Log:
Use the new config options API from twilson since this is a new module.

Modified:
    team/file/chan_jingle2/channels/chan_jingle2.c

Modified: team/file/chan_jingle2/channels/chan_jingle2.c
URL: http://svnview.digium.com/svn/asterisk/team/file/chan_jingle2/channels/chan_jingle2.c?view=diff&rev=368694&r1=368693&r2=368694
==============================================================================
--- team/file/chan_jingle2/channels/chan_jingle2.c (original)
+++ team/file/chan_jingle2/channels/chan_jingle2.c Fri Jun  8 09:44:47 2012
@@ -50,7 +50,7 @@
 
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
-#include "asterisk/config.h"
+#include "asterisk/config_options.h"
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
 #include "asterisk/sched.h"
@@ -74,10 +74,10 @@
 #define JINGLE_CONFIG "jingle2.conf"
 
 /*! \brief Default maximum number of ICE candidates we will offer */
-#define DEFAULT_MAX_ICE_CANDIDATES 10
+#define DEFAULT_MAX_ICE_CANDIDATES "10"
 
 /*! \brief Default maximum number of payloads we will offer */
-#define DEFAULT_MAX_PAYLOADS 30
+#define DEFAULT_MAX_PAYLOADS "30"
 
 /*! \brief Number of buckets for endpoints */
 #define ENDPOINT_BUCKETS 37
@@ -123,28 +123,31 @@
 	JINGLE_TRANSPORT_NONE = 0,      /*!< No transport specified */
 };
 
+/*! \brief Endpoint state information */
+struct jingle_endpoint_state {
+	struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
+};
+
 /*! \brief Endpoint which contains configuration information and active sessions */
 struct jingle_endpoint {
 	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);         /*!< Name of the endpoint */
+		AST_STRING_FIELD(name);              /*!< Name of the endpoint */
+		AST_STRING_FIELD(context);           /*!< Context to place incoming calls into */
+		AST_STRING_FIELD(accountcode);       /*!< Account code */
+		AST_STRING_FIELD(language);          /*!< Default language for prompts */
+		AST_STRING_FIELD(musicclass);        /*!< Configured music on hold class */
+		AST_STRING_FIELD(parkinglot);        /*!< Configured parking lot */
 		);
 	struct aji_client *connection;          /*!< Connection to use for traffic */
-	iksrule *rule;                          /*!< Action matching rule */
+	iksrule *rule;                          /*!< Active matching rule */
 	unsigned int maxicecandidates;          /*!< Maximum number of ICE candidates we will offer */
 	unsigned int maxpayloads;               /*!< Maximum number of payloads we will offer */
 	struct ast_codec_pref prefs;            /*!< Codec preferences */
-	char context[AST_MAX_CONTEXT];          /*!< Context to place incoming calls into */
-	char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
 	struct ast_format_cap *cap;             /*!< Formats to use */
 	ast_group_t callgroup;                  /*!< Call group */
 	ast_group_t pickupgroup;                /*!< Pickup group */
-	char language[MAX_LANGUAGE];            /*!< Default language for prompts */
-	char musicclass[MAX_MUSICCLASS];        /*!< Configured music on hold class */
-	char parkinglot[AST_MAX_CONTEXT];       /*!< Configured parking lot */
 	enum jingle_transport transport;        /*!< Default transport to use on outgoing sessions */
-	struct ao2_container *sessions;         /*!< Active sessions to or from the endpoint */
-	unsigned int destroy:1;                 /*!< Bit to indicate that the endpoint should be destroyed */
-	unsigned int destroyed:1;               /*!< Bit to indicate this endpoint is effectively destroyed */
+	struct jingle_endpoint_state *state;    /*!< Endpoint state information */
 };
 
 /*! \brief Session which contains information about an active session */
@@ -154,7 +157,7 @@
 		AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
 		AST_STRING_FIELD(video_name); /*!< Name of the video content */
 		);
-	struct jingle_endpoint *endpoint;     /*!< Endpoint we are associated with */
+	struct jingle_endpoint_state *state;  /*!< Endpoint we are associated with */
 	struct aji_client *connection;        /*!< Connection to use for traffic */
 	enum jingle_transport transport;      /*!< Transport type to use for this session */
 	unsigned int maxicecandidates;        /*!< Maximum number of ICE candidates we will offer */
@@ -176,7 +179,12 @@
 static const char desc[] = "Jingle Channel";
 static const char channel_type[] = "Jingle2";
 
-static struct ao2_container *endpoints; /*!< Configured endpoints */
+struct jingle_config {
+	struct ao2_container *endpoints; /*!< Configured endpoints */
+};
+
+static AO2_GLOBAL_OBJ_STATIC(globals);
+
 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
 
 /* \brief Asterisk core interaction functions */
@@ -263,6 +271,32 @@
 	{ "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
 };
 
+/*! \brief Hashing function for Jingle sessions */
+static int jingle_session_hash(const void *obj, const int flags)
+{
+	const struct jingle_session *session = obj;
+	const char *sid = obj;
+
+	return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
+}
+
+/*! \brief Comparator function for Jingle sessions */
+static int jingle_session_cmp(void *obj, void *arg, int flags)
+{
+	struct jingle_session *session1 = obj, *session2 = arg;
+	const char *sid = arg;
+
+	return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+/*! \brief Destructor for Jingle endpoint state */
+static void jingle_endpoint_state_destructor(void *obj)
+{
+	struct jingle_endpoint_state *state = obj;
+
+	ao2_ref(state->sessions, -1);
+}
+
 /*! \brief Destructor for Jingle endpoints */
 static void jingle_endpoint_destructor(void *obj)
 {
@@ -278,9 +312,67 @@
 
 	ast_format_cap_destroy(endpoint->cap);
 
-	ao2_ref(endpoint->sessions, -1);
+	ao2_ref(endpoint->state, -1);
 
 	ast_string_field_free_memory(endpoint);
+}
+
+/*! \brief Allocator function for Jingle endpoint state */
+static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
+{
+	struct jingle_endpoint_state *state;
+
+	if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
+		return NULL;
+	}
+
+	if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
+		ao2_ref(state, -1);
+		return NULL;
+	}
+
+	return state;
+}
+
+/*! \brief State find/create function */
+static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
+{
+	RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
+	RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
+	
+	if (!cfg || !cfg->endpoints || !(endpoint = ao2_find(cfg->endpoints, category, OBJ_KEY))) {
+		return jingle_endpoint_state_create();
+	}
+
+	ao2_ref(endpoint->state, +1);
+	return endpoint->state;
+}
+
+/*! \brief Allocator function for Jingle endpoints */
+static void *jingle_endpoint_alloc(const char *cat)
+{
+	struct jingle_endpoint *endpoint;
+
+	if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(endpoint, 512)) {
+		ao2_ref(endpoint, -1);
+		return NULL;
+	}
+
+	if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
+		ao2_ref(endpoint, -1);
+		return NULL;
+	}
+
+	ast_string_field_set(endpoint, name, cat);
+
+	endpoint->cap = ast_format_cap_alloc_nolock();
+	endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
+
+	return endpoint;
 }
 
 /*! \brief Hashing function for Jingle endpoints */
@@ -300,6 +392,28 @@
 
 	return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
+
+/*! \brief Find function for Jingle endpoints */
+static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
+{
+	return ao2_find(tmp_container, category, OBJ_KEY);
+}
+
+static struct aco_type endpoint_option = {
+        .type = ACO_ITEM,
+        .category_match = ACO_BLACKLIST,
+        .category = "^general$",
+        .item_alloc = jingle_endpoint_alloc,
+        .item_find = jingle_endpoint_find,
+        .item_offset = offsetof(struct jingle_config, endpoints),
+};
+
+struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
+
+struct aco_file jingle_conf = {
+        .filename = "jingle2.conf",
+        .types = ACO_TYPES(&endpoint_option),
+};
 
 /*! \brief Destructor for Jingle sessions */
 static void jingle_session_destructor(void *obj)
@@ -329,23 +443,33 @@
 	ast_string_field_free_memory(session);
 }
 
-/*! \brief Hashing function for Jingle sessions */
-static int jingle_session_hash(const void *obj, const int flags)
-{
-	const struct jingle_session *session = obj;
-	const char *sid = obj;
-
-	return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
-}
-
-/*! \brief Comparator function for Jingle sessions */
-static int jingle_session_cmp(void *obj, void *arg, int flags)
-{
-	struct jingle_session *session1 = obj, *session2 = arg;
-	const char *sid = arg;
-
-	return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
-}
+/*! \brief Destructor called when module configuration goes away */
+static void jingle_config_destructor(void *obj)
+{
+        struct jingle_config *cfg = obj;
+        ao2_cleanup(cfg->endpoints);
+}
+
+/*! \brief Allocator called when module configuration should appear */
+static void *jingle_config_alloc(void)
+{
+        struct jingle_config *cfg;
+
+        if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
+                return NULL;
+        }
+
+        if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
+                ao2_ref(cfg, -1);
+                return NULL;
+        }
+
+        return cfg;
+}
+
+CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
+		     .files = ACO_FILES(&jingle_conf),
+	);
 
 /*! \brief Function called by RTP engine to get local RTP peer */
 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
@@ -444,25 +568,14 @@
 		ast_string_field_set(session, sid, sid);
 	}
 
-	ao2_lock(endpoint);
-
-	/* If the endpoint is effectively destroyed it is not acceptable to create a session on it */
-	if (endpoint->destroyed) {
-		ao2_unlock(endpoint);
-		ao2_ref(session, -1);
-		return NULL;
-	}
-
-	ao2_ref(endpoint, +1);
-	session->endpoint = endpoint;
+	ao2_ref(endpoint->state, +1);
+	session->state = endpoint->state;
 	session->connection = ASTOBJ_REF(endpoint->connection);
 	session->transport = endpoint->transport;
 
 	if (!(session->cap = ast_format_cap_alloc_nolock()) ||
 	    !(session->jointcap = ast_format_cap_alloc_nolock()) ||
 	    !(session->peercap = ast_format_cap_alloc_nolock())) {
-		ao2_unlock(endpoint);
-		ao2_ref(endpoint, -1);
 		ao2_ref(session, -1);
 		return NULL;
 	}
@@ -475,8 +588,6 @@
 
 	/* Sessions always carry audio, but video is optional so don't enable it here */
 	if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
-		ao2_unlock(endpoint);
-		ao2_ref(endpoint, -1);
 		ao2_ref(session, -1);
 		return NULL;
 	}
@@ -487,8 +598,6 @@
 
 	session->maxicecandidates = endpoint->maxicecandidates;
 	session->maxpayloads = endpoint->maxpayloads;
-
-	ao2_unlock(endpoint);
 
 	return session;
 }
@@ -1553,8 +1662,8 @@
 	ast_channel_tech_pvt_set(ast, NULL);
 	session->owner = NULL;
 
-	ao2_unlink(session->endpoint->sessions, session);
-	ao2_ref(session->endpoint, -1);
+	ao2_unlink(session->state->sessions, session);
+	ao2_ref(session->state, -1);
 
 	ao2_unlock(session);
 	ao2_ref(session, -1);
@@ -1565,8 +1674,9 @@
 /*! \brief Function called by core to create a new outgoing Jingle session */
 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
 {
+	RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
+	RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
 	char *dialed, target[200] = "";
-	struct jingle_endpoint *endpoint;
 	struct aji_buddy *buddy;
 	struct jingle_session *session;
 	struct ast_channel *chan;
@@ -1598,20 +1708,19 @@
 		return NULL;
 	}
 
-	if (!(endpoint = ao2_find(endpoints, args.name, OBJ_KEY))) {
+	if (!(endpoint = ao2_find(cfg->endpoints, args.name, OBJ_KEY))) {
 		ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
 		*cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
 		return NULL;
 	}
 
-	ao2_lock(endpoint);
+	ao2_lock(endpoint->state);
 
 	/* If we don't have a connection for the endpoint we can't exactly start a session on it */
 	if (!endpoint->connection) {
 		ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
-		ao2_unlock(endpoint);
-		ao2_ref(endpoint, -1);
+		ao2_unlock(endpoint->state);
 		return NULL;
 	}
 
@@ -1638,20 +1747,18 @@
 		ast_copy_string(target, args.target, sizeof(target));
 	}
 
-	ao2_unlock(endpoint);
+	ao2_unlock(endpoint->state);
 
 	/* If no target was found we can't set up a session */
 	if (ast_strlen_zero(target)) {
 		ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no capable resource for target '%s' was found\n", args.name, args.target);
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
-		ao2_ref(endpoint, -1);
 		return NULL;
 	}
 
 	if (!(session = jingle_alloc(endpoint, target, NULL))) {
 		ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
-		ao2_ref(endpoint, -1);
 		return NULL;
 	}
 
@@ -1665,7 +1772,6 @@
 		ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
 		ao2_ref(session, -1);
-		ao2_ref(endpoint, -1);
 		return NULL;
 	}
 
@@ -1675,8 +1781,7 @@
 	}
 
 	/* We purposely don't decrement the session here as there is a reference on the channel */
-	ao2_link(endpoint->sessions, session);
-	ao2_ref(endpoint, -1);
+	ao2_link(endpoint->state->sessions, session);
 
 	return chan;
 }
@@ -2056,7 +2161,7 @@
 		return;
 	}
 
-	ao2_link(endpoint->sessions, session);
+	ao2_link(endpoint->state->sessions, session);
 
 	ast_setstate(chan, AST_STATE_RING);
 	res = ast_pbx_start(chan);
@@ -2221,7 +2326,7 @@
 	/* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
 	 * this is required or not */
 	if (!ast_strlen_zero(sid)) {
-		session = ao2_find(endpoint->sessions, sid, OBJ_KEY);
+		session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
 	}
 
 	/* Iterate through supported action handlers looking for one that is able to handle this */
@@ -2248,176 +2353,62 @@
 	return IKS_FILTER_EAT;
 }
 
-/*! \brief Internal configuration function for storing connection information */
-static void store_config_connection(struct jingle_endpoint *endpoint, const char *value)
-{
-	struct aji_client *client;
-
-	if (!(client = ast_aji_get_client(value))) {
-		ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", value, endpoint->name);
-		return;
-	}
-
-	if (endpoint->rule) {
-		iks_filter_remove_rule(endpoint->connection->f, endpoint->rule);
-	}
-
-	if (endpoint->connection) {
-		ASTOBJ_UNREF(endpoint->connection, ast_aji_client_destroy);
-	}
-
-	endpoint->connection = client;
-
-	endpoint->rule = iks_filter_add_rule(client->f, jingle_action_hook, endpoint,
-					     IKS_RULE_TYPE, IKS_PAK_IQ,
-					     IKS_RULE_NS, JINGLE_NS,
-					     IKS_RULE_NS, GOOGLE_SESSION_NS,
-					     IKS_RULE_DONE);
-}
-
-/*! \brief Internal configuration function for storing transport information */
-static void store_config_transport(struct jingle_endpoint *endpoint, const char *value)
-{
-	if (!strcasecmp(value, "ice-udp")) {
+/*! \brief Custom handler for groups */
+static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct jingle_endpoint *endpoint = obj;
+
+	if (!strcasecmp(var->name, "callgroup")) {
+		endpoint->callgroup = ast_get_group(var->value);
+	} else if (!strcasecmp(var->name, "pickupgroup")) {
+		endpoint->pickupgroup = ast_get_group(var->value);
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*! \brief Custom handler for connection */
+static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct jingle_endpoint *endpoint = obj;
+
+	/* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
+	 * this will not actually get called, so even if the config turns out to be bogus this is harmless.
+	 */
+	if (!(endpoint->connection = ast_aji_get_client(var->value))) {
+		ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
+		return -1;
+	}
+
+	if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->f, jingle_action_hook, endpoint,
+						   IKS_RULE_TYPE, IKS_PAK_IQ,
+						   IKS_RULE_NS, JINGLE_NS,
+						   IKS_RULE_NS, GOOGLE_SESSION_NS,
+						   IKS_RULE_DONE))) {
+		ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*! \brief Custom handler for transport */
+static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct jingle_endpoint *endpoint = obj;
+
+	if (!strcasecmp(var->value, "ice-udp")) {
 		endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
-	} else if (!strcasecmp(value, "google")) {
+	} else if (!strcasecmp(var->value, "google")) {
 		endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
-	} else if (!strcasecmp(value, "google-v1")) {
+	} else if (!strcasecmp(var->value, "google-v1")) {
 		endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
 	} else {
-		ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", value, endpoint->name);
+		ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
 		endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
 	}
-}
-
-/*! \brief Internal function used to store general configuration information */
-static void store_config_general(struct ast_config *cfg)
-{
-	/* This is purposely left empty in case general options are indeed required in the future */
-}
-
-/*! \brief Internal function used to store endpoint configuration information */
-static void store_config_endpoint(struct ast_config *cfg, const char *category)
-{
-	struct jingle_endpoint *endpoint;
-	struct ast_variable *v;
-
-	ao2_lock(endpoints);
-
-	/* Find the existing endpoint if present and if not, create a new one */
-	if (!(endpoint = ao2_find(endpoints, category, OBJ_KEY | OBJ_NOLOCK))) {
-		if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
-			ao2_unlock(endpoints);
-			return;
-		}
-
-		if (ast_string_field_init(endpoint, 512)) {
-			ao2_ref(endpoint, -1);
-			ao2_unlock(endpoints);
-			return;
-		}
-
-		ast_string_field_set(endpoint, name, category);
-
-		if (!(endpoint->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
-			ao2_ref(endpoint, -1);
-			ao2_unlock(endpoints);
-			return;
-		}
-
-		endpoint->cap = ast_format_cap_alloc_nolock();
-		endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
-
-		ao2_link(endpoints, endpoint);
-	}
-
-	ao2_unlock(endpoints);
-
-	ao2_lock(endpoint);
-
-	endpoint->destroy = 0;
-	endpoint->maxicecandidates = DEFAULT_MAX_ICE_CANDIDATES;
-	endpoint->maxpayloads = DEFAULT_MAX_PAYLOADS;
-
-	for (v = ast_variable_browse(cfg, category); v; v = v->next) {
-		CV_START(v->name, v->value);
-
-		CV_STR("context", endpoint->context);
-		CV_F("callgroup", endpoint->callgroup = ast_get_group(v->value));
-		CV_F("pickupgroup", endpoint->pickupgroup = ast_get_group(v->value));
-		CV_STR("language", endpoint->language);
-		CV_STR("musicclass", endpoint->musicclass);
-		CV_STR("parkinglot", endpoint->parkinglot);
-		CV_STR("accountcode", endpoint->accountcode);
-		CV_F("allow", ast_parse_allow_disallow(&endpoint->prefs, endpoint->cap, v->value, 1));
-		CV_F("disallow", ast_parse_allow_disallow(&endpoint->prefs, endpoint->cap, v->value, 0));
-		CV_F("connection", store_config_connection(endpoint, v->value));
-		CV_F("transport", store_config_transport(endpoint, v->value));
-		CV_UINT("maxicecandidates", endpoint->maxicecandidates);
-		CV_UINT("maxpayloads", endpoint->maxpayloads);
-
-		CV_END;
-	}
-
-	ao2_unlock(endpoint);
-	ao2_ref(endpoint, -1);
-}
-
-/*! \brief Callback function that sets the endpoint to be destroyed */
-static int jingle_endpoint_set_destroy(void *obj, void *arg, int flags)
-{
-	struct jingle_endpoint *endpoint = obj;
-
-	endpoint->destroy = 1;
-
-	return 0;
-}
-
-/*! \brief Callback function that returns true if an endpoint should be destroyed */
-static int jingle_endpoint_remove_destroyed(void *obj, void *arg, int flags)
-{
-	struct jingle_endpoint *endpoint = obj;
-
-	/* If this endpoint is set to be destroyed mark is as such, this will stop incoming sessions from it as
-	 * being accepted if there are outstanding sessions still using it */
-	if (endpoint->destroy) {
-		endpoint->destroyed = 1;
-		return CMP_MATCH;
-	}
-
-	return 0;
-}
-
-/*! \brief Internal function which loads and parses the configuration */
-static int jingle_load_config(int reload)
-{
-	struct ast_config *cfg;
-	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-	char *cat;
-
-	if (!(cfg = ast_config_load(JINGLE_CONFIG, config_flags))) {
-		ast_log(LOG_ERROR, "Could not load Jingle2 configuration file '%s'\n", JINGLE_CONFIG);
-		return -1;
-	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
-		ast_log(LOG_ERROR, "Jingle2 configuration file '%s' invalid\n", JINGLE_CONFIG);
-		return -1;
-	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
-		return 0;
-	}
-
-	ao2_callback(endpoints, OBJ_NODATA | OBJ_MULTIPLE, jingle_endpoint_set_destroy, NULL);
-
-	for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
-		if (!strcasecmp(cat, "general")) {
-			store_config_general(cfg);
-		} else {
-			store_config_endpoint(cfg, cat);
-		}
-	}
-
-	ao2_callback(endpoints, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, jingle_endpoint_remove_destroyed, NULL);
-
-	ast_config_destroy(cfg);
 
 	return 0;
 }
@@ -2429,14 +2420,30 @@
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
+	if (aco_info_init(&cfg_info)) {
+		ast_log(LOG_ERROR, "Unable to intialize configuration for chan_jingle2.\n");
+		goto end;
+	}
+
+	aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
+	aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
+	aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
+	aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
+	aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
+	aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
+	aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
+	aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
+	aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
+	aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
+	aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
+	aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
+			    FLDSET(struct jingle_endpoint, maxicecandidates));
+	aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
+			    FLDSET(struct jingle_endpoint, maxpayloads));
+
 	ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
 
-	if (!(endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
-		ast_log(LOG_ERROR, "Unable to create container for endpoints.\n");
-		goto end;
-	}
-
-	if (jingle_load_config(0)) {
+	if (aco_process_config(&cfg_info, 0)) {
 		ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", JINGLE_CONFIG);
 		goto end;
 	}
@@ -2466,9 +2473,8 @@
 	if (sched) {
 		ast_sched_context_destroy(sched);
 	}
-	if (endpoints) {
-		ao2_ref(endpoints, -1);
-	}
+
+	aco_info_destroy(&cfg_info);
 
 	return AST_MODULE_LOAD_FAILURE;
 }
@@ -2476,7 +2482,7 @@
 /*! \brief Reload module */
 static int reload(void)
 {
-	return jingle_load_config(1);
+	return aco_process_config(&cfg_info, 1);
 }
 
 /*! \brief Unload the jingle channel from Asterisk */
@@ -2485,7 +2491,8 @@
 	ast_channel_unregister(&jingle_tech);
 	ast_rtp_glue_unregister(&jingle_rtp_glue);
 	ast_sched_context_destroy(sched);
-	ao2_ref(endpoints, -1);
+	aco_info_destroy(&cfg_info);
+	ao2_global_obj_release(globals);
 
 	return 0;
 }




More information about the asterisk-commits mailing list