pjsip: Add option global/regcontext
authorDaniel Journo <dan@keshercommunications.com>
Sun, 10 Jan 2016 22:22:12 +0000 (22:22 +0000)
committerDaniel Journo <dan@keshercommunications.com>
Wed, 13 Jan 2016 17:42:20 +0000 (11:42 -0600)
Added new global option (regcontext) to pjsip. When set, Asterisk will
dynamically create and destroy a NoOp priority 1 extension
for a given endpoint who registers or unregisters with us.

ASTERISK-25670 #close
Reported-by: Daniel Journo

Change-Id: Ib1530c5b45340625805c057f8ff1fb240a43ea62

CHANGES
configs/samples/pjsip.conf.sample
contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py [new file with mode: 0644]
include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/config_global.c
res/res_pjsip/pjsip_configuration.c

diff --git a/CHANGES b/CHANGES
index 6885c51..93ecf94 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -205,6 +205,13 @@ Queue
 --- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------
 ------------------------------------------------------------------------------
 
+res_pjsip
+------------------
+
+ * Added new global option (regcontext) to pjsip. When set, Asterisk will
+   dynamically create and destroy a NoOp priority 1 extension
+   for a given endpoint who registers or unregisters with us.
+
 res_pjsip_history
 ------------------
  * A new module, res_pjsip_history, has been added that provides SIP history
index c8d7cc9..363ef85 100644 (file)
                             ; startup that qualifies should be attempted on all
                             ; contacts.  If greater than the qualify_frequency
                             ; for an aor, qualify_frequency will be used instead.
+; If regcontext is specified, Asterisk will dynamically create and destroy a
+; NoOp priority 1 extension for a given endpoint who registers or unregisters
+; with us. The extension added is the name of the endpoint.
+;regcontext=sipregistrations
 
 ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl
 ;==========================ACL SECTION OPTIONS=========================
diff --git a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py
new file mode 100644 (file)
index 0000000..78accc3
--- /dev/null
@@ -0,0 +1,20 @@
+"""add regcontext to pjsip
+
+Revision ID: 136885b81223
+Revises: 2d078ec071b7
+Create Date: 2016-01-11 22:32:45.470522
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '136885b81223'
+down_revision = '2d078ec071b7'
+
+from alembic import op
+import sqlalchemy as sa
+
+def upgrade():
+    op.add_column('ps_globals', sa.Column('regcontext', sa.String(80)))
+
+def downgrade():
+    op.drop_column('ps_globals', 'regcontext')
index 0c82732..1ff361f 100644 (file)
@@ -2029,6 +2029,17 @@ void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement);
 char *ast_sip_get_debug(void);
 
 /*!
+ * \brief Retrieve the global regcontext setting.
+ *
+ * \since 13.8.0
+ *
+ * \note returned string needs to be de-allocated by caller.
+ *
+ * \retval the global regcontext setting
+ */
+char *ast_sip_get_regcontext(void);
+
+/*!
  * \brief Retrieve the global endpoint_identifier_order setting.
  *
  * Specifies the order by which endpoint identifiers should be regarded.
index 90be734..b3c6773 100644 (file)
                                <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>
                                </configOption>
+                               <configOption name="regcontext" default="">
+                                        <synopsis>When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given
+                                       peer who registers or unregisters with us.</synopsis>
+                                </configOption>
                                <configOption name="default_outbound_endpoint" default="default_outbound_endpoint">
                                        <synopsis>Endpoint to use when sending an outbound request to a URI without a specified endpoint.</synopsis>
                                </configOption>
index ef706f0..3d88ffc 100644 (file)
@@ -35,6 +35,7 @@
 #define DEFAULT_ENDPOINT_IDENTIFIER_ORDER "ip,username,anonymous"
 #define DEFAULT_MAX_INITIAL_QUALIFY_TIME 0
 #define DEFAULT_FROM_USER "asterisk"
+#define DEFAULT_REGCONTEXT ""
 
 static char default_useragent[256];
 
@@ -42,6 +43,7 @@ struct global_config {
        SORCERY_OBJECT(details);
        AST_DECLARE_STRING_FIELDS(
                AST_STRING_FIELD(useragent);
+               AST_STRING_FIELD(regcontext);
                AST_STRING_FIELD(default_outbound_endpoint);
                /*! Debug logging yes|no|host */
                AST_STRING_FIELD(debug);
@@ -137,6 +139,23 @@ char *ast_sip_get_debug(void)
        return res;
 }
 
+char *ast_sip_get_regcontext(void)
+{
+        char *res;
+        struct global_config *cfg;
+
+        cfg = get_global_cfg();
+        if (!cfg) {
+                return ast_strdup(DEFAULT_REGCONTEXT);
+        }
+
+        res = ast_strdup(cfg->regcontext);
+        ao2_ref(cfg, -1);
+
+        return res;
+}
+
+
 char *ast_sip_get_endpoint_identifier_order(void)
 {
        char *res;
@@ -310,6 +329,9 @@ int ast_sip_initialize_sorcery_global(void)
                OPT_UINT_T, 0, FLDSET(struct global_config, max_initial_qualify_time));
        ast_sorcery_object_field_register(sorcery, "global", "default_from_user", DEFAULT_FROM_USER,
                OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user));
+       ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT,
+                OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext));
+
 
        if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) {
                return -1;
index 926bf37..4afa950 100644 (file)
@@ -21,6 +21,7 @@
 #include "asterisk/callerid.h"
 #include "asterisk/test.h"
 #include "asterisk/statsd.h"
+#include "asterisk/pbx.h"
 
 /*! \brief Number of buckets for persistent endpoint information */
 #define PERSISTENT_BUCKETS 53
@@ -68,6 +69,7 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
        struct ao2_iterator i;
        struct ast_sip_contact *contact;
        enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
+       char *regcontext;
 
        if (status) {
                char rtt[32];
@@ -116,16 +118,37 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
                return 0;
        }
 
+       regcontext = ast_sip_get_regcontext();
+
        if (state == AST_ENDPOINT_ONLINE) {
                ast_endpoint_set_state(endpoint, AST_ENDPOINT_ONLINE);
                blob = ast_json_pack("{s: s}", "peer_status", "Reachable");
+
+               if (!ast_strlen_zero(regcontext)) {
+                       if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL)) {
+                               ast_add_extension(regcontext, 1, ast_endpoint_get_resource(endpoint), 1, NULL, NULL,
+                                       "Noop", ast_strdup(ast_endpoint_get_resource(endpoint)), ast_free_ptr, "SIP");
+                       }
+               }
+
                ast_verb(1, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint));
        } else {
                ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE);
                blob = ast_json_pack("{s: s}", "peer_status", "Unreachable");
+
+               if (!ast_strlen_zero(regcontext)) {
+                       struct pbx_find_info q = { .stacklen = 0 };
+
+                       if (pbx_find_extension(NULL, NULL, &q, regcontext, ast_endpoint_get_resource(endpoint), 1, NULL, "", E_MATCH)) {
+                               ast_context_remove_extension(regcontext, ast_endpoint_get_resource(endpoint), 1, NULL);
+                       }
+               }
+
                ast_verb(1, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint));
        }
 
+       ast_free(regcontext);
+
        ast_endpoint_blob_publish(endpoint, ast_endpoint_state_type(), blob);
        ast_json_unref(blob);
        ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint));