From 691c0e0b317834f9d3321186126d733b391f59aa Mon Sep 17 00:00:00 2001 From: Kevin Harwell <kharwell@digium.com> Date: Wed, 21 Oct 2015 12:22:19 -0500 Subject: [PATCH] res_pjsip_outbound_registration: registration stops due to fatal 4xx response During outbound registration it is possible to receive a fatal (any permanent/ non-temporary 4xx, 5xx, 6xx) response from the registrar that is simply due to a problem with the registrar itself. Upon receiving the failure response Asterisk terminates outbound registration for the given endpoint. This patch adds an option, 'fatal_retry_interval', that when set continues outbound registration at the given interval up to 'max_retries' upon receiving a fatal response. ASTERISK-25485 #close Change-Id: Ibc2c7b47164ac89cc803433c0bbe7063bfa143a2 --- CHANGES | 7 +++++ configs/samples/pjsip.conf.sample | 8 +++++ ...8ce1e718f05_add_fatal_response_interval.py | 22 ++++++++++++++ res/res_pjsip_outbound_registration.c | 29 +++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py diff --git a/CHANGES b/CHANGES index 88743cc7b5..f3e3771c93 100644 --- a/CHANGES +++ b/CHANGES @@ -162,6 +162,13 @@ res_pjsip will be used instead. The new SIP resolver provides NAPTR support, improved SRV support, and AAAA record support. +res_pjsip_outbound_registration +------------------------------- +* A new 'fatal_retry_interval' option has been added to outbound registration. + When set (default is zero), and upon receiving a failure response to an + outbound registration, registration is retried at the given interval up to + 'max_retries'. + CEL Backends ------------------ diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 06befb4e43..9302fb2619 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -931,6 +931,14 @@ ; registration is unsuccessful (default: "60") ;forbidden_retry_interval=0 ; Interval used when receiving a 403 Forbidden ; response (default: "0") +;fatal_retry_interval=0 ; Interval used when receiving a fatal response. + ; (default: "0") A fatal response is any permanent + ; failure (non-temporary 4xx, 5xx, 6xx) response + ; received from the registrar. NOTE - if also set + ; the 'forbidden_retry_interval' takes precedence + ; over this one when a 403 is received. Also, if + ; 'auth_rejection_permanent' equals 'yes' a 401 and + ; 407 become subject to this retry interval. ;server_uri= ; SIP URI of the server to register against (default: "") ;transport= ; Transport used for outbound authentication (default: "") ;type= ; Must be of type registration (default: "") diff --git a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py new file mode 100644 index 0000000000..8c499aee8c --- /dev/null +++ b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py @@ -0,0 +1,22 @@ +"""add fatal_response_interval + +Revision ID: 28ce1e718f05 +Revises: 154177371065 +Create Date: 2015-10-20 17:57:45.560585 + +""" + +# revision identifiers, used by Alembic. +revision = '28ce1e718f05' +down_revision = '154177371065' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_registrations', sa.Column('fatal_retry_interval', sa.Integer)) + + +def downgrade(): + op.drop_column('ps_registrations', 'fatal_retry_interval') diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 6bdba56242..038cc0b200 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -100,6 +100,21 @@ buggy registrars. </para></description> </configOption> + <configOption name="fatal_retry_interval" default="0"> + <synopsis>Interval used when receiving a Fatal response.</synopsis> + <description><para> + If a fatal response is received, chan_pjsip will wait + <replaceable>fatal_retry_interval</replaceable> seconds before + attempting registration again. If 0 is specified, chan_pjsip will not + retry after receiving a fatal (non-temporary 4xx, 5xx, 6xx) response. + Setting this to a non-zero value may go against a "SHOULD NOT" in RFC3261, + but can be used to work around buggy registrars.</para> + <note><para>if also set the <replaceable>forbidden_retry_interval</replaceable> + takes precedence over this one when a 403 is received. + Also, if <replaceable>auth_rejection_permanent</replaceable> equals 'yes' then + a 401 and 407 become subject to this retry interval.</para></note> + </description> + </configOption> <configOption name="server_uri"> <synopsis>SIP URI of the server to register against</synopsis> <description><para> @@ -277,6 +292,8 @@ struct sip_outbound_registration { unsigned int retry_interval; /*! \brief Interval at which retries should occur for permanent responses */ unsigned int forbidden_retry_interval; + /*! \brief Interval at which retries should occur for all permanent responses */ + unsigned int fatal_retry_interval; /*! \brief Treat authentication challenges that we cannot handle as permanent failures */ unsigned int auth_rejection_permanent; /*! \brief Maximum number of retries permitted */ @@ -312,6 +329,8 @@ struct sip_outbound_registration_client_state { unsigned int retry_interval; /*! \brief Interval at which retries should occur for permanent responses */ unsigned int forbidden_retry_interval; + /*! \brief Interval at which retries should occur for all permanent responses */ + unsigned int fatal_retry_interval; /*! \brief Treat authentication challenges that we cannot handle as permanent failures */ unsigned int auth_rejection_permanent; /*! \brief Determines whether SIP Path support should be advertised */ @@ -799,6 +818,14 @@ static int handle_registration_response(void *data) schedule_registration(response->client_state, response->client_state->forbidden_retry_interval); ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", server_uri, client_uri, response->client_state->forbidden_retry_interval); + } else if (response->client_state->fatal_retry_interval + && response->client_state->retries < response->client_state->max_retries) { + /* Some kind of fatal failure response received, so retry according to configured interval */ + response->client_state->status = SIP_REGISTRATION_REJECTED_TEMPORARY; + response->client_state->retries++; + schedule_registration(response->client_state, response->client_state->fatal_retry_interval); + ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", + response->code, server_uri, client_uri, response->client_state->fatal_retry_interval); } else { /* Finally if there's no hope of registering give up */ response->client_state->status = SIP_REGISTRATION_REJECTED_PERMANENT; @@ -1186,6 +1213,7 @@ static int sip_outbound_registration_perform(void *data) } state->client_state->retry_interval = registration->retry_interval; state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval; + state->client_state->fatal_retry_interval = registration->fatal_retry_interval; state->client_state->max_retries = registration->max_retries; state->client_state->retries = 0; state->client_state->support_path = registration->support_path; @@ -1909,6 +1937,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "forbidden_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, forbidden_retry_interval)); + ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "fatal_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, fatal_retry_interval)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent)); ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0); -- GitLab