pjsip/config_global: regcontext context not created
authorKevin Harwell <kharwell@digium.com>
Tue, 15 Jan 2019 23:20:30 +0000 (17:20 -0600)
committerKevin Harwell <kharwell@digium.com>
Tue, 29 Jan 2019 17:33:36 +0000 (11:33 -0600)
The context specified by 'regcontext' was not being created, so when Asterisk
attempted to later dynamically add an extension it would fail. This patch now
creates the context if a 'regcontext' is specified.

ASTERISK-28238

Change-Id: I0f36cf4ab0a93ff4b1cc5548d617ecfd45e09265

res/res_pjsip/config_global.c
res/res_pjsip/include/res_pjsip_private.h
res/res_pjsip/pjsip_configuration.c

index 61a21c2..38383c5 100644 (file)
@@ -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();
index 2fd6d31..7af5b27 100644 (file)
@@ -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_ */
index d88024a..e6ac8ec 100644 (file)
@@ -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");
                        }
                }