res_sorcery_config: Allow configuration section to be used based on name.

A problem I've seen countless times is a global or system section
for PJSIP not getting applied. This is inevitably the result of
the "type=" line missing. This change alleviates that problem.

The ability to specify an explicit section name has been
added to res_sorcery_config. If the configured section
name matches this and there are no unknown things configured
the section is taken as being for the given type.

Both the PJSIP "global" and "system" types now support this
so you can just name your section "global" or "system" and it
will be matched and used, even without a "type=" line.

ASTERISK-27972

Change-Id: Ie22723663c1ddd24f869af8c9b4c1b59e2476893
16.0
Joshua Colp 7 years ago
parent 5f01f73f51
commit 59323121f3

@ -1714,7 +1714,7 @@
</description>
</configOption>
<configOption name="type">
<synopsis>Must be of type 'system'.</synopsis>
<synopsis>Must be of type 'system' UNLESS the object name is 'system'.</synopsis>
</configOption>
</configObject>
<configObject name="global">
@ -1761,7 +1761,7 @@
twice the unidentified_request_period are pruned.</synopsis>
</configOption>
<configOption name="type">
<synopsis>Must be of type 'global'.</synopsis>
<synopsis>Must be of type 'global' UNLESS the object name is 'global'.</synopsis>
</configOption>
<configOption name="user_agent" default="Asterisk &lt;Asterisk Version&gt;">
<synopsis>Value used in User-Agent header for SIP requests and Server header for SIP responses.</synopsis>

@ -491,7 +491,7 @@ int ast_sip_initialize_sorcery_global(void)
snprintf(default_useragent, sizeof(default_useragent), "%s %s",
DEFAULT_USERAGENT_PREFIX, ast_get_version());
ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global");
ast_sorcery_apply_default(sorcery, "global", "config", "pjsip.conf,criteria=type=global,single_object=yes,explicit_name=global");
if (ast_sorcery_object_register(sorcery, "global", global_alloc, NULL, global_apply)) {
return -1;

@ -175,7 +175,7 @@ int ast_sip_initialize_system(void)
return -1;
}
ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system");
ast_sorcery_apply_default(system_sorcery, "system", "config", "pjsip.conf,criteria=type=system,single_object=yes,explicit_name=system");
if (ast_sorcery_object_register_no_reload(system_sorcery, "system", system_alloc, NULL, system_apply)) {
ast_log(LOG_ERROR, "Failed to register with sorcery (is res_sorcery_config loaded?)\n");

@ -50,12 +50,18 @@ struct sorcery_config {
/*! \brief Any specific variable criteria for considering a defined category for this object */
struct ast_variable *criteria;
/*! \brief An explicit name for the configuration section, with it there can be only one */
char *explicit_name;
/*! \brief Number of buckets to use for objects */
unsigned int buckets;
/*! \brief Enable file level integrity instead of object level */
unsigned int file_integrity:1;
/*! \brief Enable enforcement of a single configuration object of this type */
unsigned int single_object:1;
/*! \brief Filename of the configuration file */
char filename[];
};
@ -113,6 +119,7 @@ static void sorcery_config_destructor(void *obj)
ao2_global_obj_release(config->objects);
ast_rwlock_destroy(&config->objects.lock);
ast_variables_destroy(config->criteria);
ast_free(config->explicit_name);
}
static int sorcery_config_fields_cmp(void *obj, void *arg, int flags)
@ -237,12 +244,66 @@ static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, vo
ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, &params);
}
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
/*! \brief Internal function which determines if a category matches based on explicit name */
static int sorcery_is_explicit_name_met(const struct ast_sorcery *sorcery, const char *type,
struct ast_category *category, struct sorcery_config *config)
{
struct ast_sorcery_object_type *object_type;
struct ast_variable *field;
int met = 1;
if (ast_strlen_zero(config->explicit_name) || strcmp(ast_category_get_name(category), config->explicit_name)) {
return 0;
}
object_type = ast_sorcery_get_object_type(sorcery, type);
if (!object_type) {
return 0;
}
/* We iterate the configured fields to see if we don't know any, if we don't then
* this is likely not for the given type and we skip it. If it actually is then criteria
* may pick it up in which case it would just get rejected as an invalid configuration later.
*/
for (field = ast_category_first(category); field; field = field->next) {
if (!ast_sorcery_is_object_field_registered(object_type, field->name)) {
met = 0;
break;
}
}
ao2_ref(object_type, -1);
return met;
}
/*! \brief Internal function which determines if a category matches based on criteria */
static int sorcery_is_criteria_met(struct ast_category *category, struct sorcery_config *config)
{
RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
return (!criteria || (!ast_sorcery_changeset_create(objset, criteria, &diff) && !diff)) ? 1 : 0;
if (!config->criteria) {
return 0;
}
return (!ast_sorcery_changeset_create(ast_category_first(category), config->criteria, &diff) && !diff) ? 1 : 0;
}
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
static int sorcery_is_configuration_met(const struct ast_sorcery *sorcery, const char *type,
struct ast_category *category, struct sorcery_config *config)
{
if (!config->criteria && ast_strlen_zero(config->explicit_name)) {
/* Nothing is configured to allow specific matching, so accept it! */
return 1;
} else if (sorcery_is_explicit_name_met(sorcery, type, category, config)) {
return 1;
} else if (sorcery_is_criteria_met(category, config)) {
return 1;
} else {
/* Nothing explicitly matched so reject */
return 0;
}
}
static void sorcery_config_internal_load(void *data, const struct ast_sorcery *sorcery, const char *type, unsigned int reload)
@ -269,8 +330,8 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s
if (!config->buckets) {
while ((category = ast_category_browse_filtered(cfg, NULL, category, NULL))) {
/* If given criteria has not been met skip the category, it is not applicable */
if (!sorcery_is_criteria_met(ast_category_first(category), config->criteria)) {
/* If given configuration has not been met skip the category, it is not applicable */
if (!sorcery_is_configuration_met(sorcery, type, category, config)) {
continue;
}
@ -292,6 +353,16 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s
buckets = config->buckets;
}
/* For single object configurations there can only ever be one bucket, if there's more than the single
* object requirement has been violated.
*/
if (config->single_object && buckets > 1) {
ast_log(LOG_ERROR, "Config file '%s' could not be loaded; configuration contains more than one object of type '%s'\n",
config->filename, type);
ast_config_destroy(cfg);
return;
}
ast_debug(2, "Using bucket size of '%d' for objects of type '%s' from '%s'\n",
buckets, type, config->filename);
@ -308,8 +379,8 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s
RAII_VAR(void *, obj, NULL, ao2_cleanup);
id = ast_category_get_name(category);
/* If given criteria has not been met skip the category, it is not applicable */
if (!sorcery_is_criteria_met(ast_category_first(category), config->criteria)) {
/* If given configurationhas not been met skip the category, it is not applicable */
if (!sorcery_is_configuration_met(sorcery, type, category, config)) {
continue;
}
@ -418,6 +489,24 @@ static void *sorcery_config_open(const char *data)
ao2_ref(config, -1);
return NULL;
}
} else if (!strcasecmp(name, "explicit_name")) {
ast_free(config->explicit_name);
config->explicit_name = ast_strdup(value);
if (ast_strlen_zero(config->explicit_name)) {
/* This is fatal since it could stop a configuration section from getting applied */
ast_log(LOG_ERROR, "Could not create explicit name entry of '%s' for configuration file '%s'\n",
value, filename);
ao2_ref(config, -1);
return NULL;
}
} else if (!strcasecmp(name, "single_object")) {
if (ast_strlen_zero(value)) {
ast_log(LOG_ERROR, "Could not set single object value for configuration file '%s' as the value is empty\n",
filename);
ao2_ref(config, -1);
return NULL;
}
config->single_object = ast_true(value);
} else {
ast_log(LOG_ERROR, "Unsupported option '%s' used for configuration file '%s'\n", name, filename);
}

Loading…
Cancel
Save