From 31dc28ab095c17894220c33491cafad1b8eadaf0 Mon Sep 17 00:00:00 2001 From: Naveen Albert <asterisk@phreaknet.org> Date: Sat, 12 Mar 2022 18:27:41 +0000 Subject: [PATCH] res_pjsip_outbound_registration: Make max random delay configurable. Currently, PJSIP will randomly wait up to 10 seconds for each outbound registration's initial attempt. The reason for this is to avoid having all outbound registrations attempt to register simultaneously. This can create limitations with the test suite where we need to be able to receive inbound calls potentially within 10 seconds of starting up. For instance, we might register to another server and then try to receive a call through the registration, but if the registration hasn't happened yet, this will fail, and hence this inconsistent behavior can cause tests to fail. Ultimately, this requires a smaller random value because there may be no good reason to wait for up to 10 seconds in these circumstances. To address this, a new config option is introduced which makes this maximum delay configurable. This allows, for instance, this to be set to a very small value in test systems to ensure that registrations happen immediately without an unnecessary delay, and can be used more generally to control how "tight" the initial outbound registrations are. ASTERISK-29965 #close Change-Id: Iab989a8e94323e645f3a21cbb6082287c7b2f3fd --- configs/samples/pjsip.conf.sample | 5 +++++ .../18e0805d367f_max_random_initial_delay.py | 21 +++++++++++++++++++ res/res_pjsip_outbound_registration.c | 17 ++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 contrib/ast-db-manage/config/versions/18e0805d367f_max_random_initial_delay.py diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 0303050d8f..a019708c39 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -1350,6 +1350,11 @@ ; (default: "") ;outbound_proxy= ; Proxy through which to send registrations, a full SIP URI ; must be provided (default: "") +;max_random_initial_delay=10 ; Maximum random delay for initial registrations (default: 10) + ; Generally it is a good idea to space out registrations + ; to not overload the system. If you have a small number + ; of registrations and need them to register more quickly, + ; you can reduce this to a lower value. ;retry_interval=60 ; Interval in seconds between retries if outbound ; registration is unsuccessful (default: "60") ;forbidden_retry_interval=0 ; Interval used when receiving a 403 Forbidden diff --git a/contrib/ast-db-manage/config/versions/18e0805d367f_max_random_initial_delay.py b/contrib/ast-db-manage/config/versions/18e0805d367f_max_random_initial_delay.py new file mode 100644 index 0000000000..343b841463 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/18e0805d367f_max_random_initial_delay.py @@ -0,0 +1,21 @@ +"""max_random_initial_delay + +Revision ID: 18e0805d367f +Revises: 0bee61aa9425 +Create Date: 2022-05-18 17:07:02.626045 + +""" + +# revision identifiers, used by Alembic. +revision = '18e0805d367f' +down_revision = '0bee61aa9425' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_registrations', sa.Column('max_random_initial_delay', sa.Integer)) + +def downgrade(): + op.drop_column('ps_registrations', 'max_random_initial_delay') diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 91cffcb038..20a4761b3f 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -109,6 +109,15 @@ <configOption name="outbound_proxy" default=""> <synopsis>Full SIP URI of the outbound proxy used to send registrations</synopsis> </configOption> + <configOption name="max_random_initial_delay" default="10"> + <synopsis>Maximum interval in seconds for which an initial registration may be randomly delayed</synopsis> + <description> + <para>By default, registrations are randomly delayed by a small amount to prevent + too many registrations from being made simultaneously.</para> + <para>Depending on your system usage, it may be desirable to set this to a smaller + or larger value to have fine grained control over the size of this random delay.</para> + </description> + </configOption> <configOption name="retry_interval" default="60"> <synopsis>Interval in seconds between retries if outbound registration is unsuccessful</synopsis> </configOption> @@ -319,6 +328,8 @@ struct sip_outbound_registration { ); /*! \brief Requested expiration time */ unsigned int expiration; + /*! \brief Maximum random initial delay interval for initial registrations */ + unsigned int max_random_initial_delay; /*! \brief Interval at which retries should occur for temporal responses */ unsigned int retry_interval; /*! \brief Interval at which retries should occur for permanent responses */ @@ -1711,6 +1722,7 @@ static int sip_outbound_registration_perform(void *data) struct sip_outbound_registration_state *state = data; struct sip_outbound_registration *registration = ao2_bump(state->registration); size_t i; + int max_delay; /* Just in case the client state is being reused for this registration, free the auth information */ ast_sip_auth_vector_destroy(&state->client_state->outbound_auths); @@ -1731,10 +1743,12 @@ static int sip_outbound_registration_perform(void *data) state->client_state->support_path = registration->support_path; state->client_state->support_outbound = registration->support_outbound; state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent; + max_delay = registration->max_random_initial_delay; pjsip_regc_update_expires(state->client_state->client, registration->expiration); - schedule_registration(state->client_state, (ast_random() % 10) + 1); + /* n mod 0 is undefined, so don't let that happen */ + schedule_registration(state->client_state, (max_delay ? ast_random() % max_delay : 0) + 1); ao2_ref(registration, -1); ao2_ref(state, -1); @@ -2546,6 +2560,7 @@ static int load_module(void) ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport)); ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy)); 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", "max_random_initial_delay", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_random_initial_delay)); 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)); -- GitLab