]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Add new AOR option "qualify_2xx_only"
authorKent <kent@amtelco.com>
Tue, 3 Dec 2024 14:24:44 +0000 (08:24 -0600)
committerKent <kent@amtelco.com>
Thu, 26 Dec 2024 14:58:10 +0000 (14:58 +0000)
Added a new option "qualify_2xx_only" to the res_pjsip AOR qualify
feature to mark a contact as available only if an OPTIONS request
returns a 2XX response. If the option is not specified or is false,
any response to the OPTIONS request marks the contact as available.

UserNote: The pjsip.conf AOR section now has a "qualify_2xx_only"
option that can be set so that only 2XX responses to OPTIONS requests
used to qualify a contact will mark the contact as available.

configs/samples/pjsip.conf.sample
contrib/ast-db-manage/config/versions/44bd6dd914fa_add_qualify_2xx_only_option.py [new file with mode: 0644]
include/asterisk/res_pjsip.h
res/res_pjsip/location.c
res/res_pjsip/pjsip_config.xml
res/res_pjsip/pjsip_options.c
res/res_pjsip_registrar.c

index 32af1b2d131622c02644d1ad2876051602b14e91..c48f38240c505d8551e456148ed137f7b12e1ffd 100644 (file)
 ;qualify_frequency=0    ; Interval at which to qualify an AoR via OPTIONS requests.
                         ; (default: "0")
 ;qualify_timeout=3.0      ; Qualify timeout in fractional seconds (default: "3.0")
+;qualify_2xx_only=no    ; If true, only qualify AoR if OPTIONS request returns 2XX
+                        ; (default: "no")
 ;authenticate_qualify=no        ; Authenticates a qualify request if needed
                                 ; (default: "no")
 ;outbound_proxy=        ; Proxy through which to send OPTIONS requests, a full SIP URI
diff --git a/contrib/ast-db-manage/config/versions/44bd6dd914fa_add_qualify_2xx_only_option.py b/contrib/ast-db-manage/config/versions/44bd6dd914fa_add_qualify_2xx_only_option.py
new file mode 100644 (file)
index 0000000..bcdc79c
--- /dev/null
@@ -0,0 +1,34 @@
+"""add qualify 2xx only option
+
+Revision ID: 44bd6dd914fa
+Revises: 4f91fc18c979
+Create Date: 2024-12-02 21:08:41.130023
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '44bd6dd914fa'
+down_revision = '4f91fc18c979'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+AST_BOOL_NAME = 'ast_bool_values'
+AST_BOOL_VALUES = [ '0', '1',
+                    'off', 'on',
+                    'false', 'true',
+                    'no', 'yes' ]
+
+def upgrade():
+    ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
+    op.add_column('ps_aors', sa.Column('qualify_2xx_only', ast_bool_values))
+    op.add_column('ps_contacts', sa.Column('qualify_2xx_only', ast_bool_values))
+
+
+def downgrade():
+    if op.get_context().bind.dialect.name == 'mssql':
+        op.drop_constraint('ck_ps_aors_qualify_2xx_only_ast_bool_values', 'ps_aors')
+        op.drop_constraint('ck_ps_contacts_qualify_2xx_only_ast_bool_values', 'ps_contacts')
+    op.drop_column('ps_aors', 'qualify_2xx_only')
+    op.drop_column('ps_contacts', 'qualify_2xx_only')
index cdc71a5f74ec20d047eec0a9cfd5ce5c374d908c..d1061eeb079eeda69f6da94205bb3ee023a3f48f 100644 (file)
@@ -423,6 +423,8 @@ struct ast_sip_contact {
        int via_port;
        /*! If true delete the contact on Asterisk restart/boot */
        int prune_on_boot;
+       /*! If true only authenticate if OPTIONS response is 2XX */
+       int qualify_2xx_only;
 };
 
 /*!
@@ -505,6 +507,8 @@ struct ast_sip_aor {
        char *voicemail_extension;
        /*! Whether to remove unavailable contacts over max_contacts at all or first if remove_existing is enabled */
        unsigned int remove_unavailable;
+       /*! If true only authenticate if OPTIONS response is 2XX */
+       int qualify_2xx_only;
 };
 
 /*!
index a507b8903d43be7dfa35fcb05c1cf7214ccc4242..42934e55645c28c3354c0c7c8613de0ae3b5827c 100644 (file)
@@ -373,6 +373,7 @@ struct ast_sip_contact *ast_sip_location_create_contact(struct ast_sip_aor *aor,
        contact->expiration_time = expiration_time;
        contact->qualify_frequency = aor->qualify_frequency;
        contact->qualify_timeout = aor->qualify_timeout;
+       contact->qualify_2xx_only = aor->qualify_2xx_only;
        contact->authenticate_qualify = aor->authenticate_qualify;
        if (path_info && aor->support_path) {
                ast_string_field_set(contact, path, path_info);
@@ -1394,6 +1395,7 @@ int ast_sip_initialize_sorcery_location(void)
        ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T,
                PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
        ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout));
+       ast_sorcery_object_field_register(sorcery, "contact", "qualify_2xx_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_contact, qualify_2xx_only));
        ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify));
        ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy));
        ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent));
@@ -1410,6 +1412,7 @@ int ast_sip_initialize_sorcery_location(void)
        ast_sorcery_object_field_register(sorcery, "aor", "default_expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, default_expiration));
        ast_sorcery_object_field_register(sorcery, "aor", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_aor, qualify_frequency), 0, 86400);
        ast_sorcery_object_field_register(sorcery, "aor", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_aor, qualify_timeout));
+       ast_sorcery_object_field_register(sorcery, "aor", "qualify_2xx_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, qualify_2xx_only));
        ast_sorcery_object_field_register(sorcery, "aor", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, authenticate_qualify));
        ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
        ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
index 71c73dc2ae0389811a37aec3414d394f2444c76e..127499641c5768013f171234127ef7a74cf4f6f7 100644 (file)
                                                If <literal>0</literal> no timeout. Time in fractional seconds.
                                        </para></description>
                                </configOption>
+                               <configOption name="qualify_2xx_only">
+                                       <synopsis>Only qualify contact if OPTIONS request returns 2XX</synopsis>
+                                       <description>
+                                               <para>If true only mark a contact as available if the qualify OPTIONS
+                                               request receives a 2XX response.
+                                               </para>
+                                       </description>
+                               </configOption>
                                <configOption name="authenticate_qualify">
                                        <synopsis>Authenticates a qualify challenge response if needed</synopsis>
                                        <description>
                                                If <literal>0</literal> no timeout. Time in fractional seconds.
                                        </para></description>
                                </configOption>
+                               <configOption name="qualify_2xx_only">
+                                       <synopsis>Only qualify contact if OPTIONS request returns 2XX</synopsis>
+                                       <description>
+                                               <para>If true only mark a contact as available if the qualify OPTIONS
+                                               request receives a 2XX response.
+                                               </para>
+                                       </description>
+                               </configOption>
                                <configOption name="authenticate_qualify">
                                        <synopsis>Authenticates a qualify challenge response if needed</synopsis>
                                        <description>
index e395ba0d7d9c395c2dbc91d97b7f75a991f69cff..93354b930949ee68a2be0ca1f97b41e5966d4c68 100644 (file)
@@ -180,6 +180,8 @@ struct sip_options_aor {
        unsigned int available;
        /*! \brief Frequency to send OPTIONS requests to AOR contacts. 0 is disabled. */
        unsigned int qualify_frequency;
+       /*! \brief If true only authenticate if OPTIONS response is 2XX */
+       int qualify_2xx_only;
        /*! If true authenticate the qualify challenge response if needed */
        int authenticate_qualify;
        /*! \brief Qualify timeout. 0 is diabled. */
@@ -799,7 +801,12 @@ static void qualify_contact_cb(void *token, pjsip_event *e)
                status = UNAVAILABLE;
                break;
        case PJSIP_EVENT_RX_MSG:
-               status = AVAILABLE;
+               if (contact_callback_data->aor_options->qualify_2xx_only &&
+                       (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
+                       status = UNAVAILABLE;
+               } else {
+                       status = AVAILABLE;
+               }
                break;
        }
 
@@ -1341,6 +1348,7 @@ static void sip_options_apply_aor_configuration(struct sip_options_aor *aor_opti
        }
 
        aor_options->authenticate_qualify = aor->authenticate_qualify;
+       aor_options->qualify_2xx_only = aor->qualify_2xx_only;
        aor_options->qualify_timeout = aor->qualify_timeout;
 
        /*
@@ -2082,6 +2090,7 @@ static int has_qualify_changed (const struct ast_sip_contact *contact, const str
                }
        } else if (contact->qualify_frequency != aor_options->qualify_frequency
                || contact->authenticate_qualify != aor_options->authenticate_qualify
+               || contact->qualify_2xx_only != aor_options->qualify_2xx_only
                || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
                return 1;
        }
@@ -2530,6 +2539,7 @@ static char *cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct
                ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
                ast_cli(a->fd, "  Qualify frequency    : %d sec\n", aor_options->qualify_frequency);
                ast_cli(a->fd, "  Qualify timeout      : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
+               ast_cli(a->fd, "  Qualify 2xx only     : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
                ast_cli(a->fd, "  Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
                ast_cli(a->fd, "\n");
                ao2_ref(aor_options, -1);
@@ -2569,6 +2579,7 @@ static char *cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_c
        ast_cli(a->fd, " * AOR '%s'\n", aor_name);
        ast_cli(a->fd, "  Qualify frequency    : %d sec\n", aor_options->qualify_frequency);
        ast_cli(a->fd, "  Qualify timeout      : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
+       ast_cli(a->fd, "  Qualify 2xx only     : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
        ast_cli(a->fd, "  Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
        ao2_ref(aor_options, -1);
 
@@ -2764,6 +2775,7 @@ int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
        ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
        ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
        ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
+       ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
 
        astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
        ami->count++;
index f2b785bab99b3a9899ed7ca52f8775386f031f93..5318c7462095551dfad233004d55c109834d4edb 100644 (file)
@@ -913,6 +913,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
                        contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
                        contact_update->qualify_frequency = aor->qualify_frequency;
                        contact_update->authenticate_qualify = aor->authenticate_qualify;
+                       contact_update->qualify_2xx_only = aor->qualify_2xx_only;
                        if (path_str) {
                                ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
                        }