diff --git a/CHANGES b/CHANGES index 6d1d8598cd34ade4a35bc1ba81b68e3e58bd31b5..da58f2995a53fb24dd21828a7e30270482dc7706 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,11 @@ --- Functionality changes from Asterisk 13.24.0 to Asterisk 13.25.0 ---------- ------------------------------------------------------------------------------ +res_pjsip +------------------ + * Added "send_contact_status_on_update_registration" global configuration option + to enable sending AMI ContactStatus event when a device refreshes its registration. + Features ------------------ * Before Asterisk 12, when using the automon or automixmon features defined diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 56e7849d757c8c46ade03225f5fd15138577b721..a04ce05a05843fa7013443a808d341b305aec8d1 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -1107,6 +1107,11 @@ ; from incoming SIP URI user fields are always truncated at the ; first semicolon. +;send_contact_status_on_update_registration=yes ; Enable sending AMI ContactStatus + ; event when a device refreshes its registration + ; (default: "yes") + + ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl ;==========================ACL SECTION OPTIONS========================= ;[acl] diff --git a/contrib/ast-db-manage/config/versions/0838f8db6a61_pjsip_add_send_contact_status_on_update_.py b/contrib/ast-db-manage/config/versions/0838f8db6a61_pjsip_add_send_contact_status_on_update_.py new file mode 100644 index 0000000000000000000000000000000000000000..2d31291be7591cb6661a727db51327d6142c9c40 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/0838f8db6a61_pjsip_add_send_contact_status_on_update_.py @@ -0,0 +1,39 @@ +"""pjsip add send_contact_status_on_update_registration + +Revision ID: 0838f8db6a61 +Revises: 1ac563b350a8 +Create Date: 2018-12-18 14:45:07.811415 + +""" + +# revision identifiers, used by Alembic. +revision = '0838f8db6a61' +down_revision = '1ac563b350a8' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +AST_BOOL_NAME = 'ast_bool_values' +# We'll just ignore the n/y and f/t abbreviations as Asterisk does not write +# those aliases. +AST_BOOL_VALUES = [ '0', '1', + 'off', 'on', + 'false', 'true', + 'no', 'yes' ] + + +def upgrade(): + ############################# Enums ############################## + + # ast_bool_values has already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False) + + op.add_column('ps_globals', sa.Column('send_contact_status_on_update_registration', ast_bool_values)) + + +def downgrade(): + if op.get_context().bind.dialect.name == 'mssql': + op.drop_constraint('ck_ps_globals_send_contact_status_on_update_registration_ast_bool_values', 'ps_globals') + op.drop_column('ps_globals', 'send_contact_status_on_update_registration') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 902cfe88a7f8f910367e931d05595dd2367a788b..7854df793f888b15390a4113a443205aa6101808 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -2793,6 +2793,15 @@ unsigned int ast_sip_get_use_callerid_contact(void); */ unsigned int ast_sip_get_ignore_uri_user_options(void); +/*! + * \brief Retrieve the global setting 'send_contact_status_on_update_registration'. + * \since 13.25.0 + * + * \retval non zero if need to send AMI ContactStatus event when a contact is updated. + */ +unsigned int ast_sip_get_send_contact_status_on_update_registration(void); + + /*! * \brief Truncate the URI user field options string if enabled. * \since 13.12.0 diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 76ef59e581221fb5a4c953906d5bb8ca8444c30a..812c291d60bb0084fc7ca66801f5d68e2c93a212 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1841,6 +1841,9 @@ generated Contact headers.</para> </description> </configOption> + <configOption name="send_contact_status_on_update_registration" default="yes"> + <synopsis>Enable sending AMI ContactStatus event when a device refreshes its registration.</synopsis> + </configOption> </configObject> </configFile> </configInfo> diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index a02cacdde764996d2a78d74fb1ba0912089d72d2..5b52574c2d9d128f68eb3ba06fbd542050ca0af4 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -49,6 +49,7 @@ #define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0 #define DEFAULT_IGNORE_URI_USER_OPTIONS 0 #define DEFAULT_USE_CALLERID_CONTACT 0 +#define DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION 1 /*! * \brief Cached global config object @@ -106,6 +107,8 @@ struct global_config { unsigned int ignore_uri_user_options; /*! Nonzero if CALLERID(num) is to be used as the default contact username instead of default_from_user */ unsigned int use_callerid_contact; + /*! Nonzero if need to send AMI ContactStatus event when a contact is updated */ + unsigned int send_contact_status_on_update_registration; }; static void global_destructor(void *obj) @@ -420,6 +423,21 @@ unsigned int ast_sip_get_use_callerid_contact(void) return use_callerid_contact; } +unsigned int ast_sip_get_send_contact_status_on_update_registration(void) +{ + unsigned int send_contact_status_on_update_registration; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION; + } + + send_contact_status_on_update_registration = cfg->send_contact_status_on_update_registration; + ao2_ref(cfg, -1); + return send_contact_status_on_update_registration; +} + /*! * \internal * \brief Observer to set default global object if none exist. @@ -574,6 +592,9 @@ int ast_sip_initialize_sorcery_global(void) ast_sorcery_object_field_register(sorcery, "global", "use_callerid_contact", DEFAULT_USE_CALLERID_CONTACT ? "yes" : "no", OPT_YESNO_T, 1, FLDSET(struct global_config, use_callerid_contact)); + ast_sorcery_object_field_register(sorcery, "global", "send_contact_status_on_update_registration", + DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION ? "yes" : "no", + OPT_YESNO_T, 1, FLDSET(struct global_config, send_contact_status_on_update_registration)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index f253dce6001bce46de789d52a729869429e813fc..81e83045415a9b07626189c642828000e9d32354 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -2228,42 +2228,45 @@ static int sip_options_contact_update_task(void *obj) /*! \brief Observer callback invoked on contact update */ static void contact_observer_updated(const void *obj) { - struct sip_options_contact_observer_task_data *task_data; + struct ast_sip_contact *contact = (struct ast_sip_contact *) obj; + struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY); - task_data = ast_malloc(sizeof(*task_data)); - if (!task_data) { - return; - } - - task_data->contact = (struct ast_sip_contact *) obj; - task_data->aor_options = ao2_find(sip_options_aors, task_data->contact->aor, - OBJ_SEARCH_KEY); - - if (has_qualify_changed(task_data->contact, task_data->aor_options)) { + if (has_qualify_changed(contact, aor_options)) { struct ast_sip_aor *aor; aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", - task_data->contact->aor); + contact->aor); if (aor) { ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n", - task_data->contact->aor); + contact->aor); ast_sip_push_task_wait_serializer(management_serializer, sip_options_aor_observer_modified_task, aor); ao2_ref(aor, -1); } } - if (!task_data->aor_options) { - ast_free(task_data); - return; - } + if (aor_options && ast_sip_get_send_contact_status_on_update_registration()) { + struct sip_options_contact_observer_task_data *task_data; - ao2_ref(task_data->contact, +1); - if (ast_sip_push_task(task_data->aor_options->serializer, - sip_options_contact_update_task, task_data)) { - ao2_ref(task_data->contact, -1); - ao2_ref(task_data->aor_options, -1); - ast_free(task_data); + task_data = ast_malloc(sizeof(*task_data)); + if (!task_data) { + ao2_ref(aor_options, -1); + return; + } + + task_data->contact = (struct ast_sip_contact *) contact; + /* task_data takes ownership of aor_options and will take care of releasing the ref */ + task_data->aor_options = aor_options; + + ao2_ref(task_data->contact, +1); + if (ast_sip_push_task(task_data->aor_options->serializer, + sip_options_contact_update_task, task_data)) { + ao2_ref(task_data->contact, -1); + ao2_ref(task_data->aor_options, -1); + ast_free(task_data); + } + } else { + ao2_cleanup(aor_options); } }