<html>
<head>
<base href="https://wiki.asterisk.org/wiki">
<link rel="stylesheet" href="/wiki/s/en/2176/25/9/_/styles/combined.css?spaceKey=AST&forWysiwyg=true" type="text/css">
</head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://wiki.asterisk.org/wiki/display/AST/Using+the+Configuration+Framework">Using the Configuration Framework</a></h2>
<h4>Page <b>added</b> by <a href="https://wiki.asterisk.org/wiki/display/~mjordan">Matt Jordan</a>
</h4>
<br/>
<div class="notificationGreySide">
<h1><a name="UsingtheConfigurationFramework-Overview"></a>Overview</h1>
<p>This wiki page describes using parts of the new Configuration Framework introduced in <a href="/wiki/display/AST/Asterisk+11+Documentation" title="Asterisk 11 Documentation">Asterisk 11</a>, and the motivation behind its creation.</p>
<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>All source code in this article is for demonstration purposes only.</td></tr></table></div>
<div>
<ul>
<li><a href='#UsingtheConfigurationFramework-Overview'>Overview</a></li>
<li><a href='#UsingtheConfigurationFramework-ConfigurationLoadingOverview'>Configuration Loading Overview</a></li>
<li><a href='#UsingtheConfigurationFramework-TraditionalConfigurationLoadinginAsterisk'>Traditional Configuration Loading in Asterisk</a></li>
<ul>
<li><a href='#UsingtheConfigurationFramework-ABasicConfiguration'>A Basic Configuration</a></li>
<li><a href='#UsingtheConfigurationFramework-mymoduleResourceManagement'>my_module Resource Management</a></li>
<li><a href='#UsingtheConfigurationFramework-AProblemConfiguration'>A Problem Configuration</a></li>
<li><a href='#UsingtheConfigurationFramework-AnotherProblemThreadingduringReloads'>Another Problem - Threading during Reloads</a></li>
</ul>
<li><a href='#UsingtheConfigurationFramework-Introducing%3AtheConfigurationFramework'>Introducing: the Configuration Framework</a></li>
<ul>
<li><a href='#UsingtheConfigurationFramework-mymoduleusingtheConfigurationFramework'>my_module using the Configuration Framework</a></li>
<li><a href='#UsingtheConfigurationFramework-Completemymodule'>Complete my_module</a></li>
</ul>
<li><a href='#UsingtheConfigurationFramework-Conclusions'>Conclusions</a></li>
</ul></div>
<h1><a name="UsingtheConfigurationFramework-ConfigurationLoadingOverview"></a>Configuration Loading Overview</h1>
<p><a href="/wiki/display/AST/Types+of+Asterisk+Modules" title="Types of Asterisk Modules">Modules</a> in Asterisk - be they applications, functions, channel drivers, supplementary resources, etc. - are responsible for managing their own resources and responding to operations initiated by the Asterisk core. During module load and reload operations, a large part of this responsibility consists of loading and parsing the module's configuration information from an Asterisk compatible configuration file or, optionally, an <a href="/wiki/display/AST/Realtime+Database+Configuration" title="Realtime Database Configuration">Asterisk Realtime Architecture (ARA) backend</a>.</p>
<p>The act of loading and parsing configuration information from either source typically involves doing the following operations:</p>
<ol>
        <li>Load the information from the backing storage into an <tt>ast_config</tt> configuration object.</li>
        <li>If the configuration supports global values, set each global variable's value by either retrieving individual values one at a time or by browsing all supported values.</li>
        <li>If the configuration supports multiple in-memory objects (users, endpoints, mailboxes, etc.), browse each item that configures the in-memory object and create the object in the module. This may also entail disposing of the current in-memory object and replacing it with the new information.</li>
</ol>
<p>As we'll see, while performing these operations there are some common pitfalls that many modules in Asterisk fall into.</p>
<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>We'll disregard configuration information retrieved from an Asterisk Realtime Architecture (ARA) backend, and instead assume that the configuration information is read from static Asterisk configuration files. ARA is complex enough to deserve its own set of pages.</td></tr></table></div>
<h1><a name="UsingtheConfigurationFramework-TraditionalConfigurationLoadinginAsterisk"></a>Traditional Configuration Loading in Asterisk</h1>
<h2><a name="UsingtheConfigurationFramework-ABasicConfiguration"></a>A Basic Configuration</h2>
<p>Let's assume that we want to configure a module <tt>my_module</tt> from the configuration file <tt>my_module.conf</tt>. We need to populate three variables in <tt>my_module</tt>, which are global values in the module:</p>
<ul>
        <li><tt>foobar</tt> - a Boolean value, whose default value should be "true".</li>
        <li><tt>foo</tt> - an integer value ranging between <tt>-32</tt> and <tt>32</tt>.</li>
        <li><tt>bar</tt> - some string value that we know should not exceed 64 characters.</li>
</ul>
<p>Our configuration file <tt>my_module.conf</tt> may look something like this:</p>
<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedHeader panelHeader" style="border-bottom-width: 1px;"><b>my_module.conf</b></div><div class="preformattedContent panelContent">
<pre>[general]
foobar = True
foo = 1
bar = Some string value
</pre>
</div></div>
<p>So that's fairly straight forward. How would we consume it in a module in Asterisk?</p>
<h2><a name="UsingtheConfigurationFramework-mymoduleResourceManagement"></a>my_module Resource Management</h2>
<p>A <tt>my_module</tt> that uses these values may look something like the following. We'll start with the basic structure, and then explore the actual loading and parsing of the configuration.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>my_module</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision: XXXXXX $")
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/config_options.h"
/*! \brief An integer value, ranging from -32 to 32 */
static int global_foo;
/*! \brief Some string value */
static char global_bar[64];
/*! \brief A boolean value */
static int global_foobar;
#define DEFAULT_FOOBAR 1
#define MIN_FOO -32
#define MAX_FOO 32
/*! \internal \brief Log the current module values */
static void log_module_values(void)
{
/* Assume that something will call this function */
ast_verb(0, "Module values: foo=%d; bar=%s; foobar=%d\n,
global_foo,
global_bar,
global_foobar);
}
/*! \internal \brief reload handler
* \retval AST_MODULE_LOAD_SUCCESS on success
* \retval AST_MODULE_LOAD_DECLINE on failure
*/
static int reload_module(void)
{
if (load_configuration(1)) {
return AST_MODULE_LOAD_DECLINE;
}
return AST_MODULE_LOAD_SUCCESS;
}
/*! \internal \brief load handler
* \retval AST_MODULE_LOAD_SUCCESS on success
* \retval AST_MODULE_LOAD_DECLINE on failure
*/
static int load_module(void)
{
if (load_configuration(0)) {
return AST_MODULE_LOAD_DECLINE;
}
return AST_MODULE_LOAD_SUCCESS;
}
/*! \internal \brief unload handler */
static int unload_module(void)
{
/* If there was memory to reclaim, we'd do it here */
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "my_module",
.load = load_module,
.unload = unload_module,
.reload = reload_module,
.load_pri = AST_MODPRI_DEFAULT,
);</pre>
</div></div>
<p>That's fairly simple. So, what do we have?</p>
<ul>
        <li>Three variables - <tt>foo</tt>, <tt>bar</tt>, and <tt>foobar</tt> that correspond to the values in our configuration file <tt>my_module.conf</tt>.</li>
        <li>A default value defined for <tt>foobar</tt> and range values defined for <tt>foo</tt>.</li>
        <li>A function <tt>log_module_values</tt> that uses the three values by logging them to the Asterisk logging subsystem.</li>
        <li>Handlers for each of the module operations that can be initiated by the Asterisk core, <tt>load</tt>, <tt>reload</tt>, and <tt>unload</tt>.</li>
        <li>The <tt>load</tt> and <tt>reload</tt> handlers defer their work to a function that we haven't defined yet - <tt>load_configuration</tt>.</li>
</ul>
<p>So, let's see what <tt>load_configuration</tt> might look like.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>my_module - load_configuration</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*!
* \internal \brief Load the configuration information
* \param reload If non-zero, this is a reload operation; otherwise, it is an initial module load
* \retval 0 on success
* \retval non-zero on error
*/
static int load_configuration(int reload)
{
struct ast_config *cfg;
char *cat = NULL;
struct ast_variable *var;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
int res = 0;
cfg = ast_config_load("my_module.conf", config_flags);
if (!cfg) {
ast_log(AST_LOG_WARNING, "Config file my_module.conf failed to load\n");
return 1;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(AST_LOG_WARNING, "Config file my_module.conf is invalid\n");
return 1;
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
}
/* Set the default values */
global_foobar = DEFAULT_FOOBAR;
/* We could theoretically use ast_variable_retrieve, but since
that can traverse all of the variables in a category on each call,
its often better to just traverse the variables in a context
in a single pass. */
while ((cat = ast_category_browse(cfg, cat))) {
/* Our config file only has a general section for now */
if (strcasecmp(cat, "general")) {
continue;
}
var = ast_variable_browse(cfg, cat);
while (var) {
if (!strcasecmp(var->name, "foo")) {
int foo_temp;
if (sscanf(var->value, "%30d", &foo_temp) != 1) {
ast_log(AST_LOG_WARNING, "Failed to parse foo value [%s]\n", var->value);
res = 1;
goto cleanup;
}
if (foo_temp < MIN_FOO || foo_temp > MAX_FOO) {
ast_log(AST_LOG_WARNING, "Invalid value %d for foo: must be between %d and %d\n",
foo_temp, MIN_FOO, MAX_FOO);
res = 1;
goto cleanup;
}
global_foo = foo_temp;
} else if (!strcasecmp(var->name, "bar")) {
ast_copy_string(global_bar, var->value, sizeof(global_bar));
} else if (!strcasecmp(var->name, "foobar")) {
foobar = ast_true(var->value) ? 1 : 0;
} else {
ast_log(AST_LOG_WARNING, "Unknown configuration key %s\n", var->name);
}
var = var->next;
}
}
cleanup:
ast_config_destroy(cfg);
return res;
}</pre>
</div></div>
<p>The function <tt>load_configuration</tt> boils down to two operations:</p>
<ol>
        <li><b>Load the Asterisk configuration file</b> <tt><b>my_module.conf</b></tt>. Whether or not we're reloading makes a difference here - if we're reloading, the configuration subsystem will let us know that nothing in the configuration file has changed if the file has not been modified, which means we don't have to go through the mechanics of changing the values in the module. Once we know we have a good configuration object - and that we have to load the values due to a change - we proceed to the next step.</li>
        <li><b>Load the configuration values into memory</b>. This consists of iterating over each context in the configuration file, and, for each context, the variables in that context. Since we only have one context <tt>[general]</tt> in the configuration file, if we encounter a context with any other name, we skip it. Note that the business logic for each of the variables is embedded in this section of code. This includes setting the default value of <tt>foobar</tt>, as well as making sure that <tt>foo</tt> is a valid integer value and within the accepted ranges. If anything would result in an invalid module configuration, we bail by jumping to the cleanup label, disposing of the configuration and returning an error.</li>
</ol>
<p>While this looks pretty good, there are a few problems with it that a bad configuration can exploit. Worse, even 'normal' operations can cause problems! Let's see how.</p>
<h2><a name="UsingtheConfigurationFramework-AProblemConfiguration"></a>A Problem Configuration</h2>
<p>First, let's assume that our module is loaded and running with the configuration in the previous section. A system administrator updates the configuration file <tt>my_module.conf</tt> with the following values:</p>
<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedHeader panelHeader" style="border-bottom-width: 1px;"><b>A Bad my_module.conf</b></div><div class="preformattedContent panelContent">
<pre>[general]
foobar = False
foo = Oh snap I'm not an integer
bar = I'm a new string value
</pre>
</div></div>
<p>Since <tt>foo</tt> is a string and not an integer, the <tt>load_configuration</tt> function will fail and cause the module reload operation to be declined. Ideally, if that happens, none of the values in the module should change - we don't want operations currently using the module to start having weird behavior just because an administrator entered some invalid data. What would the actual state of the module be?</p>
<p>Well, since the variables will most likely be parsed in the order that they appear in the <tt>[general]</tt> section, the first variable parsed will be <tt>foobar</tt>. Its value will be changed from <tt>1</tt> to <tt>0</tt>. So far so good. Unfortunately, the next variable parsed is <tt>foo</tt>, and it most definitely is not an integer. The call to <tt>sscanf</tt> will fail, causing the configuration loading to stop. This results in the module having half of the configuration loaded into memory, while the other half has been left untouched:</p>
<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedHeader panelHeader" style="border-bottom-width: 1px;"><b>Resulting Values in the Module after the Failed Load</b></div><div class="preformattedContent panelContent">
<pre>foobar = False
foo = 1
bar = Some string value
</pre>
</div></div>
<p>Yikes.</p>
<p>There are of course some things we could do to alleviate this.</p>
<ol>
        <li>We could decide to try and restore the state of the variables in <tt>my_module</tt> if an error is detected.</li>
        <li>We could parse the configuration values into a temporary object, and only set the values of the module once all of the application level logic has been passed.</li>
</ol>
<p>Both of these approaches naturally tend to lead towards storing the configuration values in a struct, as opposed to individual variables. Unfortunately, there are some other problems that even this approach won't completely solve.</p>
<h2><a name="UsingtheConfigurationFramework-AnotherProblemThreadingduringReloads"></a>Another Problem - Threading during Reloads</h2>
<p>Remember that both the <b>CLI</b> and <b>AMI</b> can initiate a reload - and those happen on a different thread of execution than the thread executing the dialplan! In fact, there is a very good chance that any reload operation will happen on a different thread than whatever thread executes the logic in your module.</p>
<p>So, what happens if someone calls <tt>log_module_values</tt> while a reload is happening? The answer is "that depends" - but you can bet that it won't be pretty. You may get the values before the reload, after the reload, or some combination thereof. Worse, you can run into all sorts of strange (and difficult to debug) problems if the <tt>ast_copy_string</tt> of <tt>bar</tt> occurs at the same time as <tt>ast_verb</tt>, as both items will be attempting to modify/read the contents of the array at the same time.</p>
<p>In more complex modules where the configuration information is stored on the heap, this can lead to all sorts of strange problems - items that get removed from a configuration will no longer exist, pointers will point to NULL (if you're lucky, garbage if you're not), and general mayhem can ensue. Not pretty.</p>
<p>We could, of course, put some locking in to help. What would that look like?</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>my_module with Locking</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*! \brief An integer value, ranging from -32 to 32 */
static int global_foo;
/*! \brief Some string value */
static char global_bar[64];
/*! \brief A boolean value */
static int global_foobar;
AST_MUTEX_DEFINE_STATIC(config_lock);
#define DEFAULT_FOOBAR 1
#define MIN_FOO -32
#define MAX_FOO 32
/*! \internal \brief Log the current module values */
static void log_module_values(void)
{
/* Assume that something will call this function */
ast_mutex_lock(&config_lock);
ast_verb(0, "Module values: foo=%d; bar=%s; foobar=%d\n,
global_foo,
global_bar,
global_foobar);
ast_mutex_unlock(&config_lock);
}
/*!
* \internal \brief Load the configuration information
* \param reload If non-zero, this is a reload operation; otherwise, it is an initial module load
* \retval 0 on success
* \retval non-zero on error
*/
static int load_configuration(int reload)
{
struct ast_config *cfg;
char *cat = NULL;
struct ast_variable *var;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
int res = 0;
cfg = ast_config_load("my_module.conf", config_flags);
if (!cfg) {
ast_log(AST_LOG_WARNING, "Config file my_module.conf failed to load\n");
return 1;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(AST_LOG_WARNING, "Config file my_module.conf is invalid\n");
return 1;
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
}
/* *** LOCK ADDED *** */
ast_config_lock(&config_lock);
/* Set the default values */
global_foobar = DEFAULT_FOOBAR;
/* We could theoretically use ast_variable_retrieve, but since
that can traverse all of the variables in a category on each call,
its often better to just traverse the variables in a context
in a single pass. */
while ((cat = ast_category_browse(cfg, cat))) {
/* Our config file only has a general section for now */
if (strcasecmp(cat, "general")) {
continue;
}
var = ast_variable_browse(cfg, cat);
while (var) {
if (!strcasecmp(var->name, "foo")) {
int foo_temp;
if (sscanf(var->value, "%30d", &foo_temp) != 1) {
ast_log(AST_LOG_WARNING, "Failed to parse foo value [%s]\n", var->value);
res = 1;
goto cleanup;
}
if (foo_temp < MIN_FOO || foo_temp > MAX_FOO) {
ast_log(AST_LOG_WARNING, "Invalid value %d for foo: must be between %d and %d\n",
foo_temp, MIN_FOO, MAX_FOO);
res = 1;
goto cleanup;
}
global_foo = foo_temp;
} else if (!strcasecmp(var->name, "bar")) {
ast_copy_string(global_bar, var->value, sizeof(global_bar));
} else if (!strcasecmp(var->name, "foobar")) {
foobar = ast_true(var->value) ? 1 : 0;
} else {
ast_log(AST_LOG_WARNING, "Unknown configuration key %s\n", var->name);
}
var = var->next;
}
}
cleanup:
/* *** UNLOCK ADDED *** */
ast_config_unlock(&config_lock);
ast_config_destroy(cfg);
return res;
}
/* ... module callback handlers ... */</pre>
</div></div>
<p>So, that's a little bit better, and now we can guarantee that a reload won't mess with <tt>log_module_values</tt>. That's nice, but now we have to put a lock around every access to <tt>foo</tt>, <tt>bar</tt>, and <tt>foobar</tt>. That can get tricky - and expensive - very quickly. And it doesn't solve the previous problem of inconsistent module state when an off nominal reload occurs.</p>
<p>This also ends up being a lot for a developer to keep straight. If only there was an API that helped us with all of this...</p>
<h1><a name="UsingtheConfigurationFramework-Introducing%3AtheConfigurationFramework"></a>Introducing: the Configuration Framework</h1>
<p>The examples above illustrate why we looked at writing a new layer of abstraction on top of Asterisk's configuration file loading and parsing. While the existing mechanisms provided a consistent way of loading a configuration file into memory, they didn't provide a way of mapping that configuration information to an in-memory representation of that data suitable for consumption by any module. Worse, rampant concurrency problems and off nominal code path handling have caused headaches for system administrators and developers alike.</p>
<p>So, we set off with the following goals:</p>
<ol>
        <li>Create a consistent mechanism for parsing configuration information into a module.</li>
        <li>Provide a thread-safe mechanism for loading configuration information into memory.</li>
        <li>Prevent errors in configuration from creating inconsistent state in a module.</li>
        <li>Allow operations currently 'in-flight' to finish with the configuration information they started with.</li>
</ol>
<p>The Configuration Framework in Asterisk 11 provides meets these goals, although things are going to appear a little different. The module developer has to do a little more work initially in setting up the in-memory objects and providing mappings for those values back to an Asterisk configuration file. The very flexible nature of Asterisk configuration files - and how modules interpret those files - also meant that the Configuration Framework had to be flexible. So we'll take this slow.</p>
<h2><a name="UsingtheConfigurationFramework-mymoduleusingtheConfigurationFramework"></a>my_module using the Configuration Framework</h2>
<p>All configuration information is stored in a reference counted object using Asterisk's <tt>astobj2</tt> API. That object can be replaced in a thread-safe manner with a new configuration information object, as we'll see later. Since the object is reference counted, as long as a consumer of the configuration information holds a reference to that object, it will continue to use the configuration information it started with, even if the configuration information is reloaded.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>my_module's In-Memory Configuration Object</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">#define DEFAULT_FOOBAR "True"
#define MIN_FOO -32
#define MAX_FOO 32
/*! \brief The global options available for this module
* \note This replaces the individual static variables that were previously present
*/
struct global_options {
int foo; /*< Some integer value between -32 and 32 */
char bar[64]; /*< Some string value */
int foobar:1; /*< Some boolean value */
};
/*! \brief All configuration objects for this module
* \note If we had more than just a single set of global options, we would have
* other items in this struct
*/
struct module_config {
struct global_options *general; /*< Our global settings */
}
/*! \brief A container that holds our global module configuration */
static AO2_GLOBAL_OBJ_STATIC(module_configs);
/*! \brief A mapping of the module_config struct's general settings to the context
* in the configuration file that will populate its values */
static struct aco_type general_option {
.type = ACO_GLOBAL,
.item_offset = offsetof(struct module_config, general),
.category = "^general$",
.category_type = ACO_WHITELIST,
};</pre>
</div></div>
<p>So, that looks different! Let's run down what we have.</p>
<ol>
        <li>Our global configuration information is now stored in struct <tt>global_options</tt>. That struct has <tt>foo</tt>, <tt>bar</tt>, and <tt>foobar</tt> members that correspond to the static variables we previously had defined.</li>
        <li>The global configuration information is stored in another struct, <tt>module_config</tt>. It has a pointer to an instance of struct <tt>global_options</tt>. If we had more information other than global information (such as users or endpoints), we might have more items in this struct.</li>
        <li><tt>AO2_GLOBAL_OBJ_STATIC</tt> is a new macro that creates a special struct that can hold a single item. It also gives us a lock on the object, providing the Configuration Framework a way to safely access, replace, and remove the information stored inside of it.</li>
        <li><tt>aco_type</tt> is the first instance of a special type of object that the Configuration Framework provides. It gives us a way to map our general configuration information - stored in <tt>module_config</tt>'s <tt>general</tt> pointer - to a context in the Asterisk configuration file. This defines for the Configuration Framework how information is extracted from the configuration file. Looking at each individual field in the struct:
        <ul>
                <li><tt>.type = ACO_GLOBAL</tt>. Two types are allowed here - either <tt>ACO_GLOBAL</tt> or <tt>ACO_ITEM</tt>. <tt>ACO_GLOBAL</tt> implies that global information should be extracted and populated one time out of a configuration file, <tt>ACO_ITEM</tt> implies that the information should be extracted multiple times into multiple items.</li>
                <li><tt>item_offset = offsetof(struct module_config, general)</tt>. This uses the <tt>offsetof</tt> keyword to map the configuration information that will be extracted into the appropriate object - in this case, the object pointed to by the <tt>general</tt> field in the <tt>module_config</tt> struct.</li>
                <li><tt>category = "^general$"</tt>. A regular expression matching the category to parse out. In this case, <tt>"^general$"</tt> will match the context with a string name of 'general'.</li>
                <li><tt>category_type = ACO_WHITELIST</tt>. This means that only contexts that match the regular expression specified by the <tt>category</tt> will be processed. Alternatively, this option can be specified as a blacklist using <tt>ACO_BLACKLIST</tt>.</li>
        </ul>
        </li>
</ol>
<p>So now we have a mapping of our module configuration, and the in-memory representation of the global settings stored in context <tt>[general]</tt> to an object that will process that mapping for us. So what's next?</p>
<p>Well, as we mentioned previously, the configuration objects are going to be <tt>ao2</tt> objects, using the <tt>astobj2</tt> API. Let's define the constructor and destructor functions for the <tt>module_config</tt> <tt>ao2</tt> object.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>module_config Constructor/Destructor</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">static void *module_config_alloc(void);
static void module_config_destructor(void *obj);
/*! \internal \brief Create a module_config object */
static void *module_config_alloc(void)
{
        struct module_config *cfg;
        if (!(cfg = ao2_alloc(sizeof(*cfg), module_config_destructor))) {
                return NULL;
        }
        if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), NULL))) {
                ao2_ref(cfg, -1);
                return NULL;
        }
        return cfg;
}
/*! \internal \brief Dispose of a module_config object */
static void module_config_destructor(void *obj)
{
        struct module_config *cfg = obj;
        ao2_cleanup(cfg->general);
}</pre>
</div></div>
<p>Note that as part of creating the <tt>module_config</tt> object, we also create the general settings object. Because we want the lifetime of the general settings to be tied to the lifetime of the <tt>module_config</tt> object, we explicitly handle its destruction in <tt>module_config_destructor</tt>, rather than pass a destructor function to <tt>ao2_alloc</tt> when we create it.</p>
<p>Now, we can associate our general configuration mapping object <tt>general_option</tt> with a configuration file that will provide the data.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>Tying the Mapping Object to a Config File</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*! \brief A configuration file that will be processed for the module */
static struct aco_file module_conf = {
        .filename = "my_module.conf", /*!< The name of the config file */
        .types = ACO_TYPES(&general_option), /*!< The mapping object types to be processed */
};
CONFIG_INFO_STANDARD(cfg_info, module_configs, module_config_alloc,
        .files = ACO_FILES(&module_conf),
);
static struct aco_type *general_options[] = ACO_TYPES(&general_option);</pre>
</div></div>
<p>That isn't a lot of code, but what is there does a lot of powerful stuff. Let's go down the list:</p>
<ol>
        <li><tt>aco_file</tt> defines a mapping of a configuration file to the mapping types that should be applied to that file. The Configuration Framework will consume the <tt>aco_file</tt> objects and process each file passed to it, populate the in-memory objects based on the mappings that are associated with that file.</li>
        <li>We notify the Configuration Framework of our top level objects using the CONFIG_INFO_STANDARD macro. This:
        <ul>
                <li>Defines a handle <tt>cfg_info</tt> to access the Configuration Framework.</li>
                <li>Associates the special <tt>module_configs</tt> container with the constructor, <tt>module_config_alloc</tt>, that will put the module configuration object into the container.</li>
                <li>Specifies the files to process when the configuration for the module is loaded/reloaded. In this case, this happens to be the file specified by the <tt>module_conf</tt> object.</li>
        </ul>
        </li>
        <li>Finally, we have <tt>general_options</tt>, which is a special array that will be used when we register items to extract. We'll see this in use later.</li>
</ol>
<p>We're finally ready to start doing some loading! But wait... where's the application level logic for our various variables? And how do we extract them from the Configuration Framework?</p>
<p>Rather than have a separate function that provides the application logic with the parsing, we instead tell the Configuration Framework how to extract each configuration value out of the configuration file, and what logic we want applied to it. We do all of this when we first load the module, as shown below.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>Loading my_module Using the Configuration Framework</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*! \internal \brief load handler
* \retval AST_MODULE_LOAD_SUCCESS on success
* \retval AST_MODULE_LOAD_DECLINE on failure
*/
static int load_module(void)
{
if (aco_config_init(&cfg_info)) {
goto load_error;
}
aco_option_register(&cfg_info, "foo", /* Extract configuration item "foo" */
ACO_EXACT, /* Match the exact configuration item name */
global_options, /* Use the global_options array to find the object to populate */
NULL, /* Don't supply a default value */
OPT_INT_T, /* Interpret the value as an integer */
PARSE_IN_RANGE, /* Accept values in a range */
FLDSET(struct global_options, foo), /* Store the value in member foo of a global_options struct */
MIN_FOO, /* Use MIN_FOO as the minimum value of the allowed range */
MAX_FOO); /* Use MAX_FOO as the maximum value of the allowed range */
aco_option_register(&cfg_info, "bar", /* Extract configuration item "bar" */
ACO_EXACT, /* Match the exact configuration item name */
global_options, /* Use the global_options array to find the object to populate */
NULL, /* Don't supply a default value */
OPT_CHAR_ARRAY_T, /* Interpret the value as a character array */
0, /* No interpretation flags are needed */
CHARFLDSET(struct global_options, bar)); /* Store the value in member bar of a global_options struct */
aco_option_register(&cfg_info, "foobar", /* Extract configuration item "foobar" */
ACO_EXACT, /* Match the exact configuration item name */
global_options, /* Use the global_options array to find the object to populate */
DEFAULT_FOOBAR, /* Supply default value DEFAULT_FOOBAR */
OPT_BOOL_T, /* Interpret the value as a boolean */
1, /* Use ast_true to set the value of foobar */
FLDSET(struct global_options, foobar)); /* Store the value in member foobar of a global_options struct */
if (aco_process_config(&cfg_info, 0)) {
goto load_error;
}
return AST_MODULE_LOAD_SUCCESS;
load_error:
aco_info_destroy(&cfg_info);
return AST_MODULE_LOAD_DECLINE;
}</pre>
</div></div>
<p>Recall that <tt>foo</tt> has to be an integer between <tt>-32</tt> and <tt>32</tt>, and that <tt>foobar</tt> should be a boolean value with a default value of <tt>1</tt>. Using the Configuration Framework, we've specified how we want those parameters to be extracted in <tt>aco_option_register</tt>. Once we've registered the configuration items to be extracted, all of the configuration parsing and loading into the in-memory objects is handled by <tt>aco_process_config</tt>. Once <tt>aco_process_config</tt> is finished, the <tt>module_configs</tt> <tt>ao2</tt> container will have an instance of <tt>module_config</tt> inside of it populated with the configuration information from the configuration file <tt>my_module.conf</tt>.</p>
<p>Now how would we use our in-memory object? And what about reloads?</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>Reloads and Using the Configuration Information</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*! \internal \brief Log the current module values */
static void log_module_values(void)
{
RAII_VAR(struct module_config *, cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
if (!cfg || !cfg->globals) {
ast_log(LOG_ERROR, "Rut roh - something blew away our configuration!);
return;
}
/* Assume that something will call this function */
ast_verb(0, "Module values: foo=%d; bar=%s; foobar=%d\n,
cfg->globals->foo,
cfg->globals->bar,
cfg->globals->foobar);
}
/*! \internal \brief reload handler
* \retval AST_MODULE_LOAD_SUCCESS on success
* \retval AST_MODULE_LOAD_DECLINE on failure
*/
static int reload_module(void)
{
if (aco_process_config(&cfg_info, 1)) {
return AST_MODULE_LOAD_DECLINE;
}
return 0;
}</pre>
</div></div>
<p>Let's take those in reverse order.</p>
<ol>
        <li>So, reloads are much easier, and thread-safe to boot. All we have to do is call <tt>aco_process_config</tt> and tell it (in the second parameter) that we're performing a reload. This will reload the module's configuration and - if it succeeds - safely swap out the config in the <tt>module_configs</tt> object. If it fails, the previous configuration is left alone so that any operations currently using the module can finish up without having bad data lying around.</li>
        <li>Using the configuration information is a bit trickier, but not by much. We use a new macro <tt>RAII_VAR</tt> to safely get the <tt>module_config</tt> instance out of the <tt>module_configs</tt> object. Once we have the <tt>module_config</tt> object, we should (because we're practicing defensive coding, and we should always be careful) check whether or not we got valid data. If we did, we're free to use the values in our function. Plus, since <tt>module_config</tt> is reference counted, we 'own' that instance for as long as we want it. If a reload happens while we're logging out the current configuration values, its not a problem - our instance won't be changed and won't be disposed of until we leave the scope of <tt>log_module_values</tt>.</li>
</ol>
<p>Note that due to some careful use of <tt>C</tt> extensions, the <tt>RAII_VAR</tt> macro sets up the clean-up of the reference counted objects for us, so that when execution leaves the scope of the <tt>log_module_values</tt> function, the object's references are all cleaned up properly! That makes it much easier to simply return out of the function if an off nominal condition is detected, or if the function has multiple exit points.</p>
<p>The <tt>unload</tt> handler is shown below with the complete <tt>my_module</tt> source code.</p>
<h2><a name="UsingtheConfigurationFramework-Completemymodule"></a>Complete my_module</h2>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;"><b>my_module.c</b></div><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision: XXXXXX $")
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/config_options.h"
#define DEFAULT_FOOBAR "True"
#define MIN_FOO -32
#define MAX_FOO 32
/*! \brief The global options available for this module
* \note This replaces the individual static variables that were previously present
*/
struct global_options {
int foo; /*< Some integer value between -32 and 32 */
char bar[64]; /*< Some string value */
int foobar:1; /*< Some boolean value */
};
/*! \brief All configuration objects for this module
* \note If we had more than just a single set of global options, we would have
* other items in this struct
*/
struct module_config {
struct global_options *general; /*< Our global settings */
}
/*! \brief A container that holds our global module configuration */
static AO2_GLOBAL_OBJ_STATIC(module_configs);
/*! \brief A mapping of the module_config struct's general settings to the context
* in the configuration file that will populate its values */
static struct aco_type general_option {
.type = ACO_GLOBAL,
.item_offset = offsetof(struct module_config, general),
.category = "^general$",
.category_type = ACO_WHITELIST,
};
static void *module_config_alloc(void);
static void module_config_destructor(void *obj);
/*! \brief A configuration file that will be processed for the module */
static struct aco_file module_conf = {
        .filename = "my_module.conf", /*!< The name of the config file */
        .types = ACO_TYPES(&general_option), /*!< The mapping object types to be processed */
};
CONFIG_INFO_STANDARD(cfg_info, module_configs, module_config_alloc,
        .files = ACO_FILES(&module_conf),
);
static struct aco_type *general_options[] = ACO_TYPES(&general_option);
/*! \internal \brief Create a module_config object */
static void *module_config_alloc(void)
{
        struct module_config *cfg;
        if (!(cfg = ao2_alloc(sizeof(*cfg), module_config_destructor))) {
                return NULL;
        }
        if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), NULL))) {
                ao2_ref(cfg, -1);
                return NULL;
        }
        return cfg;
}
/*! \internal \brief Dispose of a module_config object */
static void module_config_destructor(void *obj)
{
        struct module_config *cfg = obj;
        ao2_cleanup(cfg->general);
}
/*! \internal \brief Log the current module values */
static void log_module_values(void)
{
RAII_VAR(struct module_config *, cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
if (!cfg || !cfg->globals) {
ast_log(LOG_ERROR, "Rut roh - something blew away our configuration!);
return;
}
/* Assume that something will call this function */
ast_verb(0, "Module values: foo=%d; bar=%s; foobar=%d\n,
cfg->globals->foo,
cfg->globals->bar,
cfg->globals->foobar);
}
/*! \internal \brief load handler
* \retval AST_MODULE_LOAD_SUCCESS on success
* \retval AST_MODULE_LOAD_DECLINE on failure
*/
static int load_module(void)
{
if (aco_config_init(&cfg_info)) {
goto load_error;
}
aco_option_register(&cfg_info, "foo", /* Extract configuration item "foo" */
ACO_EXACT, /* Match the exact configuration item name */
global_options, /* Use the global_options array to find the object to populate */
NULL, /* Don't supply a default value */
OPT_INT_T, /* Interpret the value as an integer */
PARSE_IN_RANGE, /* Accept values in a range */
FLDSET(struct global_options, foo), /* Store the value in member foo of a global_options struct */
MIN_FOO, /* Use MIN_FOO as the minimum value of the allowed range */
MAX_FOO); /* Use MAX_FOO as the maximum value of the allowed range */
aco_option_register(&cfg_info, "bar", /* Extract configuration item "bar" */
ACO_EXACT, /* Match the exact configuration item name */
global_options, /* Use the global_options array to find the object to populate */
NULL, /* Don't supply a default value */
OPT_CHAR_ARRAY_T, /* Interpret the value as a character array */
0, /* No interpretation flags are needed */
CHARFLDSET(struct global_options, bar)); /* Store the value in member bar of a global_options struct */
aco_option_register(&cfg_info, "foobar", /* Extract configuration item "foobar" */
ACO_EXACT, /* Match the exact configuration item name */
global_options, /* Use the global_options array to find the object to populate */
DEFAULT_FOOBAR, /* Supply default value DEFAULT_FOOBAR */
OPT_BOOL_T, /* Interpret the value as a boolean */
1, /* Use ast_true to set the value of foobar */
FLDSET(struct global_options, foobar)); /* Store the value in member foobar of a global_options struct */
if (aco_process_config(&cfg_info, 0)) {
goto load_error;
}
return AST_MODULE_LOAD_SUCCESS;
load_error:
aco_info_destroy(&cfg_info);
return AST_MODULE_LOAD_DECLINE;
}
/*! \internal \brief reload handler
* \retval AST_MODULE_LOAD_SUCCESS on success
* \retval AST_MODULE_LOAD_DECLINE on failure
*/
static int reload_module(void)
{
if (aco_process_config(&cfg_info, 1)) {
return AST_MODULE_LOAD_DECLINE;
}
return 0;
}
/*! \internal \brief unload handler */
static int unload_module(void)
{
aco_info_destroy(&cfg_info);
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "my_module",
.load = load_module,
.unload = unload_module,
.reload = reload_module,
.load_pri = AST_MODPRI_DEFAULT,
);</pre>
</div></div>
<h1><a name="UsingtheConfigurationFramework-Conclusions"></a>Conclusions</h1>
<p>And... that's it! Using the Configuration Framework, we've successfully solved the threading problems that were present in the previous <tt>my_module</tt> implementation, as well as prevented errors that can occur when a configuration file has erroneous data. As always, there's no free lunch - there's a bit more work to be done in setting up the mappings between the in-memory objects and their representation in the configuration file - but taken all together, the benefits the Configuration Framework provides are enormous.</p>
<p>There's a lot more to the Configuration Framework than what is described here. The framework lets you:</p>
<ul>
        <li>Define items using a wide variety of types, including several Asterisk specific types (such as stringfields).</li>
        <li>Define callbacks for individual configuration items that allow you to apply custom application logic when the item is parsed.</li>
        <li>Define callbacks for different stages of configuration parsing.</li>
        <li>Populate multiple types of objects from different sections in a configuration file.</li>
        <li>Handle multiple configuration files for a single module.</li>
</ul>
<p>And much, much more. The <tt>app_skel</tt> application has been rewritten for Asterisk 11 and demonstrates some of the more complex capabilities that the Configuration Framework provides. Some modules were also migrated over to using the new framework, and new modules in Asterisk 11 - such as <tt>chan_motif</tt> - also make use of it for their configuration management.</p>
<p>Going forward, we hope that all new modules in Asterisk make use of the new framework to minimize the race conditions and other bugs that can occur when loading configuration information.</p>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;" class="grey">
<a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=AST">Stop watching space</a>
<span style="padding: 0px 5px;">|</span>
<a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action">Change email notification preferences</a>
</div>
<a href="https://wiki.asterisk.org/wiki/display/AST/Using+the+Configuration+Framework">View Online</a>
|
<a href="https://wiki.asterisk.org/wiki/display/AST/Using+the+Configuration+Framework?showComments=true&showCommentArea=true#addcomment">Add Comment</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>