<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/9514">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, but someone else must approve; Approved for Submit
  Kevin Harwell: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_sorcery_config: Allow configuration section to be used based on name.<br><br>A problem I've seen countless times is a global or system section<br>for PJSIP not getting applied. This is inevitably the result of<br>the "type=" line missing. This change alleviates that problem.<br><br>The ability to specify an explicit section name has been<br>added to res_sorcery_config. If the configured section<br>name matches this and there are no unknown things configured<br>the section is taken as being for the given type.<br><br>Both the PJSIP "global" and "system" types now support this<br>so you can just name your section "global" or "system" and it<br>will be matched and used, even without a "type=" line.<br><br>ASTERISK-27972<br><br>Change-Id: Ie22723663c1ddd24f869af8c9b4c1b59e2476893<br>---<br>M res/res_pjsip.c<br>M res/res_pjsip/config_global.c<br>M res/res_pjsip/config_system.c<br>M res/res_sorcery_config.c<br>4 files changed, 100 insertions(+), 11 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index c440454..e087564 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -1661,7 +1661,7 @@</span><br><span>                                    </description></span><br><span>                                 </configOption></span><br><span>                                <configOption name="type"></span><br><span style="color: hsl(0, 100%, 40%);">-                                      <synopsis>Must be of type 'system'.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>Must be of type 'system' UNLESS the object name is 'system'.</synopsis></span><br><span>                                </configOption></span><br><span>                        </configObject></span><br><span>                        <configObject name="global"></span><br><span>@@ -1708,7 +1708,7 @@</span><br><span>                                         twice the unidentified_request_period are pruned.</synopsis></span><br><span>                           </configOption></span><br><span>                                <configOption name="type"></span><br><span style="color: hsl(0, 100%, 40%);">-                                      <synopsis>Must be of type 'global'.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>Must be of type 'global' UNLESS the object name is 'global'.</synopsis></span><br><span>                                </configOption></span><br><span>                                <configOption name="user_agent" default="Asterisk &lt;Asterisk Version&gt;"></span><br><span>                                       <synopsis>Value used in User-Agent header for SIP requests and Server header for SIP responses.</synopsis></span><br><span>diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c</span><br><span>index fc1227d..2a80312 100644</span><br><span>--- a/res/res_pjsip/config_global.c</span><br><span>+++ b/res/res_pjsip/config_global.c</span><br><span>@@ -491,7 +491,7 @@</span><br><span>        snprintf(default_useragent, sizeof(default_useragent), "%s %s",</span><br><span>            DEFAULT_USERAGENT_PREFIX, ast_get_version());</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global");</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global,single_object=yes,explicit_name=global");</span><br><span> </span><br><span>  if (ast_sorcery_object_register(sorcery, "global", global_alloc, NULL, global_apply)) {</span><br><span>            return -1;</span><br><span>diff --git a/res/res_pjsip/config_system.c b/res/res_pjsip/config_system.c</span><br><span>index 65e4e2c..2ff0a65 100644</span><br><span>--- a/res/res_pjsip/config_system.c</span><br><span>+++ b/res/res_pjsip/config_system.c</span><br><span>@@ -175,7 +175,7 @@</span><br><span>            return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system,single_object=yes,explicit_name=system");</span><br><span> </span><br><span>   if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {</span><br><span>           ast_log(LOG_ERROR, "Failed to register with sorcery (is res_sorcery_config loaded?)\n");</span><br><span>diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c</span><br><span>index b02000e..a458d91 100644</span><br><span>--- a/res/res_sorcery_config.c</span><br><span>+++ b/res/res_sorcery_config.c</span><br><span>@@ -52,12 +52,18 @@</span><br><span>        /*! \brief Any specific variable criteria for considering a defined category for this object */</span><br><span>      struct ast_variable *criteria;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    /*! \brief An explicit name for the configuration section, with it there can be only one */</span><br><span style="color: hsl(120, 100%, 40%);">+   char *explicit_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       /*! \brief Number of buckets to use for objects */</span><br><span>   unsigned int buckets;</span><br><span> </span><br><span>    /*! \brief Enable file level integrity instead of object level */</span><br><span>    unsigned int file_integrity:1;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    /*! \brief Enable enforcement of a single configuration object of this type */</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int single_object:1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      /*! \brief Filename of the configuration file */</span><br><span>     char filename[];</span><br><span> };</span><br><span>@@ -115,6 +121,7 @@</span><br><span>         ao2_global_obj_release(config->objects);</span><br><span>  ast_rwlock_destroy(&config->objects.lock);</span><br><span>    ast_variables_destroy(config->criteria);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_free(config->explicit_name);</span><br><span> }</span><br><span> </span><br><span> static int sorcery_config_fields_cmp(void *obj, void *arg, int flags)</span><br><span>@@ -239,12 +246,66 @@</span><br><span>        ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, &params);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */</span><br><span style="color: hsl(0, 100%, 40%);">-static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Internal function which determines if a category matches based on explicit name */</span><br><span style="color: hsl(120, 100%, 40%);">+static int sorcery_is_explicit_name_met(const struct ast_sorcery *sorcery, const char *type,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_category *category, struct sorcery_config *config)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sorcery_object_type *object_type;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_variable *field;</span><br><span style="color: hsl(120, 100%, 40%);">+   int met = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_strlen_zero(config->explicit_name) || strcmp(ast_category_get_name(category), config->explicit_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   object_type = ast_sorcery_get_object_type(sorcery, type);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!object_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We iterate the configured fields to see if we don't know any, if we don't then</span><br><span style="color: hsl(120, 100%, 40%);">+      * this is likely not for the given type and we skip it. If it actually is then criteria</span><br><span style="color: hsl(120, 100%, 40%);">+       * may pick it up in which case it would just get rejected as an invalid configuration later.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   for (field = ast_category_first(category); field; field = field->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ast_sorcery_is_object_field_registered(object_type, field->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   met = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ao2_ref(object_type, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return met;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Internal function which determines if a category matches based on criteria */</span><br><span style="color: hsl(120, 100%, 40%);">+static int sorcery_is_criteria_met(struct ast_category *category, struct sorcery_config *config)</span><br><span> {</span><br><span>    RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- return (!criteria || (!ast_sorcery_changeset_create(objset, criteria, &diff) && !diff)) ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!config->criteria) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return (!ast_sorcery_changeset_create(ast_category_first(category), config->criteria, &diff) && !diff) ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */</span><br><span style="color: hsl(120, 100%, 40%);">+static int sorcery_is_configuration_met(const struct ast_sorcery *sorcery, const char *type,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_category *category, struct sorcery_config *config)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!config->criteria && ast_strlen_zero(config->explicit_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Nothing is configured to allow specific matching, so accept it! */</span><br><span style="color: hsl(120, 100%, 40%);">+         return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (sorcery_is_explicit_name_met(sorcery, type, category, config)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (sorcery_is_criteria_met(category, config)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Nothing explicitly matched so reject */</span><br><span style="color: hsl(120, 100%, 40%);">+            return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> }</span><br><span> </span><br><span> static void sorcery_config_internal_load(void *data, const struct ast_sorcery *sorcery, const char *type, unsigned int reload)</span><br><span>@@ -271,8 +332,8 @@</span><br><span>   if (!config->buckets) {</span><br><span>           while ((category = ast_category_browse_filtered(cfg, NULL, category, NULL))) {</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                      /* If given criteria has not been met skip the category, it is not applicable */</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (!sorcery_is_criteria_met(ast_category_first(category), config->criteria)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* If given configuration has not been met skip the category, it is not applicable */</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!sorcery_is_configuration_met(sorcery, type, category, config)) {</span><br><span>                                continue;</span><br><span>                    }</span><br><span> </span><br><span>@@ -294,6 +355,16 @@</span><br><span>                 buckets = config->buckets;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* For single object configurations there can only ever be one bucket, if there's more than the single</span><br><span style="color: hsl(120, 100%, 40%);">+     * object requirement has been violated.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (config->single_object && buckets > 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Config file '%s' could not be loaded; configuration contains more than one object of type '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      config->filename, type);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_config_destroy(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ast_debug(2, "Using bucket size of '%d' for objects of type '%s' from '%s'\n",</span><br><span>             buckets, type, config->filename);</span><br><span> </span><br><span>@@ -310,8 +381,8 @@</span><br><span>               RAII_VAR(void *, obj, NULL, ao2_cleanup);</span><br><span>            id = ast_category_get_name(category);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-               /* If given criteria has not been met skip the category, it is not applicable */</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!sorcery_is_criteria_met(ast_category_first(category), config->criteria)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* If given configurationhas not been met skip the category, it is not applicable */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!sorcery_is_configuration_met(sorcery, type, category, config)) {</span><br><span>                        continue;</span><br><span>            }</span><br><span> </span><br><span>@@ -420,6 +491,24 @@</span><br><span>                                 ao2_ref(config, -1);</span><br><span>                                 return NULL;</span><br><span>                         }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (!strcasecmp(name, "explicit_name")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_free(config->explicit_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                   config->explicit_name = ast_strdup(value);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (ast_strlen_zero(config->explicit_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* This is fatal since it could stop a configuration section from getting applied */</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_log(LOG_ERROR, "Could not create explicit name entry of '%s' for configuration file '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    value, filename);</span><br><span style="color: hsl(120, 100%, 40%);">+                             ao2_ref(config, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (!strcasecmp(name, "single_object")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (ast_strlen_zero(value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_log(LOG_ERROR, "Could not set single object value for configuration file '%s' as the value is empty\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                 filename);</span><br><span style="color: hsl(120, 100%, 40%);">+                            ao2_ref(config, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  }</span><br><span style="color: hsl(120, 100%, 40%);">+                     config->single_object = ast_true(value);</span><br><span>          } else {</span><br><span>                     ast_log(LOG_ERROR, "Unsupported option '%s' used for configuration file '%s'\n", name, filename);</span><br><span>          }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9514">change 9514</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/9514"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 13 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ie22723663c1ddd24f869af8c9b4c1b59e2476893 </div>
<div style="display:none"> Gerrit-Change-Number: 9514 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>