diff --git a/CHANGES b/CHANGES index 6885c512ad..93ecf94c19 100644 --- 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 diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index c8d7cc90e9..363ef8557e 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -896,6 +896,10 @@ ; 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 index 0000000000..78accc3229 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py @@ -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') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 0c82732833..1ff361f546 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2028,6 +2028,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. * diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 90be734e67..b3c6773b48 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1282,6 +1282,10 @@ Value used in User-Agent header for SIP requests and Server header for SIP responses. + + When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given + peer who registers or unregisters with us. + Endpoint to use when sending an outbound request to a URI without a specified endpoint. diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index ef706f0b35..3d88ffc2a9 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -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; diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 926bf3793c..4afa9507d1 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -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));