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 @@
Full SIP URI of the outbound proxy used to send registrations
+
+ Maximum interval in seconds for which an initial registration may be randomly delayed
+
+ By default, registrations are randomly delayed by a small amount to prevent
+ too many registrations from being made simultaneously.
+ 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.
+
+
Interval in seconds between retries if outbound registration is unsuccessful
@@ -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));