diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index 61a21c253d8c21bac456ba2112af60fffe6b703d..38383c5c2b59d422a44d9a0963c34687425926e3 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -23,6 +23,7 @@ #include "asterisk/res_pjsip.h" #include "include/res_pjsip_private.h" +#include "asterisk/pbx.h" #include "asterisk/sorcery.h" #include "asterisk/taskprocessor.h" #include "asterisk/ast_version.h" @@ -131,6 +132,46 @@ static void *global_alloc(const char *name) return cfg; } +/* + * There is ever only one global section, so we can use a single global + * value here to track the regcontext through reloads. + */ +static char *previous_regcontext = NULL; + +static int check_regcontext(const struct global_config *cfg) +{ + char *current = NULL; + + if (previous_regcontext && !strcmp(previous_regcontext, cfg->regcontext)) { + /* Nothing changed so nothing to do */ + return 0; + } + + if (!ast_strlen_zero(cfg->regcontext)) { + current = ast_strdup(cfg->regcontext); + if (!current) { + return -1; + } + + if (ast_sip_persistent_endpoint_add_to_regcontext(cfg->regcontext)) { + ast_free(current); + return -1; + } + } + + if (!ast_strlen_zero(previous_regcontext)) { + ast_context_destroy_by_name(previous_regcontext, "PJSIP"); + ast_free(previous_regcontext); + previous_regcontext = NULL; + } + + if (current) { + previous_regcontext = current; + } + + return 0; +} + static int global_apply(const struct ast_sorcery *sorcery, void *obj) { struct global_config *cfg = obj; @@ -154,6 +195,10 @@ static int global_apply(const struct ast_sorcery *sorcery, void *obj) ast_sip_add_global_request_header("User-Agent", cfg->useragent, 1); ast_sip_add_global_response_header("Server", cfg->useragent, 1); + if (check_regcontext(cfg)) { + return -1; + } + ao2_t_global_obj_replace_unref(global_cfg, cfg, "Applying global settings"); return 0; } @@ -515,11 +560,17 @@ int ast_sip_destroy_sorcery_global(void) ast_sorcery_instance_observer_remove(sorcery, &observer_callbacks_global); + if (previous_regcontext) { + ast_context_destroy_by_name(previous_regcontext, "PJSIP"); + ast_free(previous_regcontext); + } + ao2_t_global_obj_release(global_cfg, "Module is unloading"); return 0; } + int ast_sip_initialize_sorcery_global(void) { struct ast_sorcery *sorcery = ast_sip_get_sorcery(); diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index 2fd6d314c79ba23d3cb35c7390756e0565ffb07e..7af5b27bb8ecd8a0af97354e11359eb15b3182f4 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -398,4 +398,14 @@ int ast_sip_initialize_transport_management(void); */ void ast_sip_destroy_transport_management(void); +/*! + * \internal + * \brief Add online persistent endpoints to the given regcontext + * + * \param regcontext The context to add endpoints to + * + * \retval -1 on error, 0 on success + */ +int ast_sip_persistent_endpoint_add_to_regcontext(const char *regcontext); + #endif /* RES_PJSIP_PRIVATE_H_ */ diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index d88024a80b074a23cfbf92b3e0f7c22cad6ee4de..e6ac8ecfad965db9aea22df5835556e89ab655bd 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1128,6 +1128,39 @@ static void persistent_endpoint_destroy(void *obj) ast_endpoint_shutdown(persistent->endpoint); } +static int add_to_regcontext(void *obj, void *arg, int flags) +{ + struct sip_persistent_endpoint *persistent = obj; + const char *regcontext = arg; + + if (ast_endpoint_get_state(persistent->endpoint) == AST_ENDPOINT_ONLINE) { + if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource( + persistent->endpoint), 1, NULL)) { + ast_add_extension(regcontext, 1, ast_endpoint_get_resource(persistent->endpoint), 1, NULL, NULL, + "Noop", ast_strdup(ast_endpoint_get_resource(persistent->endpoint)), ast_free_ptr, "PJSIP"); + } + } + + return 0; +} + +int ast_sip_persistent_endpoint_add_to_regcontext(const char *regcontext) +{ + if (ast_strlen_zero(regcontext)) { + return 0; + } + + /* Make sure the regcontext exists */ + if (!ast_context_find_or_create(NULL, NULL, regcontext, "PJSIP")) { + ast_log(LOG_ERROR, "Failed to create regcontext '%s'\n", regcontext); + return -1; + } + + /* Add any online endpoints */ + ao2_callback(persistent_endpoints, OBJ_NODATA, add_to_regcontext, (void *)regcontext); + return 0; +} + int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state) { struct sip_persistent_endpoint *persistent; @@ -1154,7 +1187,7 @@ int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast if (!ast_strlen_zero(regcontext)) { if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(persistent->endpoint), 1, NULL)) { ast_add_extension(regcontext, 1, ast_endpoint_get_resource(persistent->endpoint), 1, NULL, NULL, - "Noop", ast_strdup(ast_endpoint_get_resource(persistent->endpoint)), ast_free_ptr, "SIP"); + "Noop", ast_strdup(ast_endpoint_get_resource(persistent->endpoint)), ast_free_ptr, "PJSIP"); } }