diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index a0ec653584..c3e2864ace 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -1558,6 +1558,28 @@ const char *ast_sorcery_object_get_extended(const void *object, const char *name */ int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value); +/*! + * \brief Get whether an object contains dynamic contents or not + * + * \param object Pointer to a sorcery object + * + * \since 19 + * \since 18.3.0 + * \since 16.17.0 + */ +unsigned int ast_sorcery_object_has_dynamic_contents(const void *object); + +/*! + * \brief Set the dynamic contents flag on a sorcery object + * + * \param object Pointer to a sorcery object + * + * \since 19 + * \since 18.3.0 + * \since 16.17.0 + */ +void ast_sorcery_object_set_has_dynamic_contents(const void *object); + /*! * \brief ao2 object comparator based on sorcery id. */ diff --git a/main/sorcery.c b/main/sorcery.c index 0ada81e3f7..ad10aeeeff 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -139,6 +139,9 @@ struct ast_sorcery_object { /*! \brief Time that the object was created */ struct timeval created; + + /*! \brief Whether this object has dynamic contents or not */ + unsigned int has_dynamic_contents:1; }; /*! \brief Structure for registered object type */ @@ -2366,6 +2369,20 @@ int ast_sorcery_object_set_extended(const void *object, const char *name, const return 0; } +unsigned int ast_sorcery_object_has_dynamic_contents(const void *object) +{ + const struct ast_sorcery_object_details *details = object; + + return details->object->has_dynamic_contents; +} + +void ast_sorcery_object_set_has_dynamic_contents(const void *object) +{ + const struct ast_sorcery_object_details *details = object; + + details->object->has_dynamic_contents = 1; +} + int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks) { RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c index a2aa934446..d8de26112c 100644 --- a/res/res_pjsip_endpoint_identifier_ip.c +++ b/res/res_pjsip_endpoint_identifier_ip.c @@ -515,6 +515,9 @@ static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj) return 0; } + /* Hosts can produce dynamic content, so mark the identify as such */ + ast_sorcery_object_set_has_dynamic_contents(obj); + /* Resolve the match addresses now */ i = ao2_iterator_init(identify->hosts, 0); while ((current_string = ao2_iterator_next(&i))) { diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c index 67679a2280..dfe7a351ed 100644 --- a/res/res_sorcery_config.c +++ b/res/res_sorcery_config.c @@ -65,6 +65,9 @@ struct sorcery_config { /*! \brief Configuration is invalid in some way, force reload */ unsigned int configuration_invalid:1; + /*! \brief Configuration contains at least one object with dynamic contents */ + unsigned int has_dynamic_contents:1; + /*! \brief Filename of the configuration file */ char filename[]; }; @@ -313,12 +316,13 @@ static int sorcery_is_configuration_met(const struct ast_sorcery *sorcery, const static void sorcery_config_internal_load(void *data, const struct ast_sorcery *sorcery, const char *type, unsigned int reload) { struct sorcery_config *config = data; - struct ast_flags flags = { reload && !config->configuration_invalid ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + struct ast_flags flags = { reload && !config->configuration_invalid && !config->has_dynamic_contents ? CONFIG_FLAG_FILEUNCHANGED : 0 }; struct ast_config *cfg = ast_config_load2(config->filename, config->uuid, flags); struct ast_category *category = NULL; RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup); const char *id = NULL; unsigned int buckets = 0; + unsigned int has_dynamic_contents = 0; if (!cfg) { ast_log(LOG_ERROR, "Unable to load config file '%s'\n", config->filename); @@ -430,9 +434,15 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s ast_log(LOG_NOTICE, "Retaining existing configuration for object of type '%s' with id '%s'\n", type, id); } + /* We store the dynamic contents state until the end in case this reload or load + * gets rolled back. + */ + has_dynamic_contents |= ast_sorcery_object_has_dynamic_contents(obj); + ao2_link(objects, obj); } + config->has_dynamic_contents = has_dynamic_contents; ao2_global_obj_replace_unref(config->objects, objects); ast_config_destroy(cfg); }