mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-13 00:04:53 +00:00
res_pjsip_registrar: Remove unavailable contacts if exceeds max_contacts
The behavior of max_contacts and remove_existing are connected. If remove_existing is enabled, the soonest expiring contacts are removed. This may occur when there is an unavailable contact. Similarly, when remove_existing is not enabled, registrations from good endpoints are rejected in favor of retaining unavailable contacts. This commit adds a new AOR option remove_unavailable, and the effect of this setting will depend on remove_existing. If remove_existing is set to no, we will still remove unavailable contacts when they exceed max_contacts, if there are any. If remove_existing is set to yes, we will prioritize the removal of unavailable contacts before those that are expiring soonest. ASTERISK-29525 Change-Id: Ia2711b08f2b4d1177411b1be23e970d7fdff5784
This commit is contained in:
committed by
Friendly Automation
parent
0aac38c0ac
commit
47cb177baf
@@ -1109,6 +1109,16 @@
|
|||||||
; contact created by rewrite_contact that the device is
|
; contact created by rewrite_contact that the device is
|
||||||
; refreshing.
|
; refreshing.
|
||||||
; (default: "no")
|
; (default: "no")
|
||||||
|
;remove_unavailable=no ; If remove_existing is disabled, will allow a registration
|
||||||
|
; to succeed by removing only unavailable contacts when
|
||||||
|
; max_contacts is exceeded. This will reject a registration
|
||||||
|
; that exceeds max_contacts if no unavailable contacts are
|
||||||
|
; present to remove. If remove_existing is enabled, will
|
||||||
|
; prioritize removal of unavailable contacts before removing
|
||||||
|
; expiring soonest. This tames the behavior of remove_existing
|
||||||
|
; to only remove an available contact if an unavailable one is
|
||||||
|
; not present.
|
||||||
|
; (default: "no")
|
||||||
;type= ; Must be of type aor (default: "")
|
;type= ; Must be of type aor (default: "")
|
||||||
;qualify_frequency=0 ; Interval at which to qualify an AoR via OPTIONS requests.
|
;qualify_frequency=0 ; Interval at which to qualify an AoR via OPTIONS requests.
|
||||||
; (default: "0")
|
; (default: "0")
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
"""pjsip create remove_unavailable
|
||||||
|
|
||||||
|
Revision ID: f56d79a9f337
|
||||||
|
Revises: c20d6e3992f4
|
||||||
|
Create Date: 2021-07-28 02:09:11.082061
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f56d79a9f337'
|
||||||
|
down_revision = 'c20d6e3992f4'
|
||||||
|
|
||||||
|
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('remove_unavailable', ast_bool_values))
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('ps_aors', 'remove_unavailable')
|
||||||
|
pass
|
||||||
|
|
7
doc/CHANGES-staging/res_pjsip_registrar.txt
Normal file
7
doc/CHANGES-staging/res_pjsip_registrar.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Subject: res_pjsip_registrar
|
||||||
|
|
||||||
|
Adds new PJSIP AOR option remove_unavailable to either
|
||||||
|
remove unavailable contacts when a REGISTER exceeds
|
||||||
|
max_contacts when remove_existing is disabled, or
|
||||||
|
prioritize unavailable contacts over other existing
|
||||||
|
contacts when remove_existing is enabled.
|
@@ -389,6 +389,8 @@ struct ast_sip_aor {
|
|||||||
double qualify_timeout;
|
double qualify_timeout;
|
||||||
/*! Voicemail extension to set in Message-Account */
|
/*! Voicemail extension to set in Message-Account */
|
||||||
char *voicemail_extension;
|
char *voicemail_extension;
|
||||||
|
/*! Whether to remove unavailable contacts over max_contacts at all or first if remove_existing is enabled */
|
||||||
|
unsigned int remove_unavailable;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -1997,8 +1997,9 @@
|
|||||||
TLS. Unfortunately, refreshing a registration may register a
|
TLS. Unfortunately, refreshing a registration may register a
|
||||||
different contact address and exceed
|
different contact address and exceed
|
||||||
<replaceable>max_contacts</replaceable>. The
|
<replaceable>max_contacts</replaceable>. The
|
||||||
<replaceable>remove_existing</replaceable> option can help by
|
<replaceable>remove_existing</replaceable> and
|
||||||
removing the soonest to expire contact(s) over
|
<replaceable>remove_unavailable</replaceable> options can help by
|
||||||
|
removing either the soonest to expire or unavailable contact(s) over
|
||||||
<replaceable>max_contacts</replaceable> which is likely the
|
<replaceable>max_contacts</replaceable> which is likely the
|
||||||
old <replaceable>rewrite_contact</replaceable> contact source
|
old <replaceable>rewrite_contact</replaceable> contact source
|
||||||
address being refreshed.
|
address being refreshed.
|
||||||
@@ -2041,6 +2042,26 @@
|
|||||||
</para></note>
|
</para></note>
|
||||||
</description>
|
</description>
|
||||||
</configOption>
|
</configOption>
|
||||||
|
<configOption name="remove_unavailable" default="no">
|
||||||
|
<synopsis>Determines whether new contacts should replace unavailable ones.</synopsis>
|
||||||
|
<description><para>
|
||||||
|
The effect of this setting depends on the setting of
|
||||||
|
<replaceable>remove_existing</replaceable>.</para>
|
||||||
|
<para>If <replaceable>remove_existing</replaceable> is set to
|
||||||
|
<literal>no</literal> (default), setting remove_unavailable to
|
||||||
|
<literal>yes</literal> will remove only unavailable contacts that exceed
|
||||||
|
<replaceable>max_contacts</replaceable> to allow an incoming
|
||||||
|
REGISTER to complete sucessfully.</para>
|
||||||
|
<para>If <replaceable>remove_existing</replaceable> is set to
|
||||||
|
<literal>yes</literal>, setting remove_unavailable to
|
||||||
|
<literal>yes</literal> will prioritize unavailable contacts for removal
|
||||||
|
instead of just removing the contact that expires the soonest.</para>
|
||||||
|
<note><para>See <replaceable>remove_existing</replaceable> and
|
||||||
|
<replaceable>max_contacts</replaceable> for further information about how
|
||||||
|
these 3 settings interact.
|
||||||
|
</para></note>
|
||||||
|
</description>
|
||||||
|
</configOption>
|
||||||
<configOption name="type">
|
<configOption name="type">
|
||||||
<synopsis>Must be of type 'aor'.</synopsis>
|
<synopsis>Must be of type 'aor'.</synopsis>
|
||||||
</configOption>
|
</configOption>
|
||||||
@@ -2444,6 +2465,9 @@
|
|||||||
<parameter name="RemoveExisting">
|
<parameter name="RemoveExisting">
|
||||||
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para>
|
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="RemoveUnavailable">
|
||||||
|
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_unavailable']/synopsis/node())"/></para>
|
||||||
|
</parameter>
|
||||||
<parameter name="Mailboxes">
|
<parameter name="Mailboxes">
|
||||||
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para>
|
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para>
|
||||||
</parameter>
|
</parameter>
|
||||||
@@ -2904,6 +2928,9 @@
|
|||||||
<parameter name="RemoveExisting">
|
<parameter name="RemoveExisting">
|
||||||
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para>
|
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="RemoveUnavailable">
|
||||||
|
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_unavailable']/synopsis/node())"/></para>
|
||||||
|
</parameter>
|
||||||
<parameter name="Mailboxes">
|
<parameter name="Mailboxes">
|
||||||
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para>
|
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
@@ -1410,6 +1410,7 @@ int ast_sip_initialize_sorcery_location(void)
|
|||||||
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", "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", "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));
|
ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
|
||||||
|
ast_sorcery_object_field_register(sorcery, "aor", "remove_unavailable", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_unavailable));
|
||||||
ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0);
|
ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0);
|
||||||
ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
|
ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
|
||||||
ast_sorcery_object_field_register_custom(sorcery, "aor", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0);
|
ast_sorcery_object_field_register_custom(sorcery, "aor", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0);
|
||||||
|
@@ -204,6 +204,7 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *po
|
|||||||
enum contact_delete_type {
|
enum contact_delete_type {
|
||||||
CONTACT_DELETE_ERROR,
|
CONTACT_DELETE_ERROR,
|
||||||
CONTACT_DELETE_EXISTING,
|
CONTACT_DELETE_EXISTING,
|
||||||
|
CONTACT_DELETE_UNAVAILABLE,
|
||||||
CONTACT_DELETE_EXPIRE,
|
CONTACT_DELETE_EXPIRE,
|
||||||
CONTACT_DELETE_REQUEST,
|
CONTACT_DELETE_REQUEST,
|
||||||
CONTACT_DELETE_SHUTDOWN,
|
CONTACT_DELETE_SHUTDOWN,
|
||||||
@@ -448,6 +449,9 @@ static int registrar_contact_delete(enum contact_delete_type type, pjsip_transpo
|
|||||||
case CONTACT_DELETE_EXISTING:
|
case CONTACT_DELETE_EXISTING:
|
||||||
reason = "remove existing";
|
reason = "remove existing";
|
||||||
break;
|
break;
|
||||||
|
case CONTACT_DELETE_UNAVAILABLE:
|
||||||
|
reason = "remove unavailable";
|
||||||
|
break;
|
||||||
case CONTACT_DELETE_EXPIRE:
|
case CONTACT_DELETE_EXPIRE:
|
||||||
reason = "expiration";
|
reason = "expiration";
|
||||||
break;
|
break;
|
||||||
@@ -483,7 +487,48 @@ static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact
|
|||||||
struct ast_sip_contact *right_contact = right;
|
struct ast_sip_contact *right_contact = right;
|
||||||
|
|
||||||
/* Sort from soonest to expire to last to expire */
|
/* Sort from soonest to expire to last to expire */
|
||||||
return ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
|
int time_sorted = ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
|
||||||
|
|
||||||
|
struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(left_contact->aor);
|
||||||
|
struct ast_sip_contact_status *left_status;
|
||||||
|
struct ast_sip_contact_status *right_status;
|
||||||
|
int remove_unavailable = 0;
|
||||||
|
int left_unreachable;
|
||||||
|
int right_unreachable;
|
||||||
|
|
||||||
|
if (aor) {
|
||||||
|
remove_unavailable = aor->remove_unavailable;
|
||||||
|
ao2_ref(aor, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!remove_unavailable) {
|
||||||
|
return time_sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get contact status if available */
|
||||||
|
left_status = ast_sip_get_contact_status(left_contact);
|
||||||
|
if (!left_status) {
|
||||||
|
return time_sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
right_status = ast_sip_get_contact_status(right_contact);
|
||||||
|
if (!right_status) {
|
||||||
|
ao2_ref(left_status, -1);
|
||||||
|
return time_sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
left_unreachable = (left_status->status == UNAVAILABLE);
|
||||||
|
right_unreachable = (right_status->status == UNAVAILABLE);
|
||||||
|
ao2_ref(left_status, -1);
|
||||||
|
ao2_ref(right_status, -1);
|
||||||
|
if (left_unreachable != right_unreachable) {
|
||||||
|
/* Set unavailable contact to top of vector */
|
||||||
|
if (left_unreachable) return -1;
|
||||||
|
if (right_unreachable) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either both available or both unavailable */
|
||||||
|
return time_sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vec_contact_add(void *obj, void *arg, int flags)
|
static int vec_contact_add(void *obj, void *arg, int flags)
|
||||||
@@ -512,7 +557,7 @@ static int vec_contact_add(void *obj, void *arg, int flags)
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \internal
|
* \internal
|
||||||
* \brief Remove excess existing contacts that expire the soonest.
|
* \brief Remove excess existing contacts that are unavailable or expire soonest.
|
||||||
* \since 13.18.0
|
* \since 13.18.0
|
||||||
*
|
*
|
||||||
* \param contacts Container of unmodified contacts that could remove.
|
* \param contacts Container of unmodified contacts that could remove.
|
||||||
@@ -521,7 +566,7 @@ static int vec_contact_add(void *obj, void *arg, int flags)
|
|||||||
* \return Nothing
|
* \return Nothing
|
||||||
*/
|
*/
|
||||||
static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts,
|
static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts,
|
||||||
unsigned int to_remove)
|
unsigned int to_remove, unsigned int remove_existing)
|
||||||
{
|
{
|
||||||
struct excess_contact_vector contact_vec;
|
struct excess_contact_vector contact_vec;
|
||||||
|
|
||||||
@@ -545,13 +590,17 @@ static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_co
|
|||||||
ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
|
ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
|
||||||
to_remove = AST_VECTOR_SIZE(&contact_vec);
|
to_remove = AST_VECTOR_SIZE(&contact_vec);
|
||||||
|
|
||||||
/* Remove the excess contacts that expire the soonest */
|
/* Remove the excess contacts that are unavailable or expire the soonest */
|
||||||
while (to_remove--) {
|
while (to_remove--) {
|
||||||
struct ast_sip_contact *contact;
|
struct ast_sip_contact *contact;
|
||||||
|
|
||||||
contact = AST_VECTOR_GET(&contact_vec, to_remove);
|
contact = AST_VECTOR_GET(&contact_vec, to_remove);
|
||||||
|
|
||||||
registrar_contact_delete(CONTACT_DELETE_EXISTING, NULL, contact, contact->aor);
|
if (!remove_existing) {
|
||||||
|
registrar_contact_delete(CONTACT_DELETE_UNAVAILABLE, NULL, contact, contact->aor);
|
||||||
|
} else {
|
||||||
|
registrar_contact_delete(CONTACT_DELETE_EXISTING, NULL, contact, contact->aor);
|
||||||
|
}
|
||||||
|
|
||||||
ao2_unlink(response_contacts, contact);
|
ao2_unlink(response_contacts, contact);
|
||||||
}
|
}
|
||||||
@@ -574,6 +623,29 @@ static int registrar_add_non_permanent(void *obj, void *arg, int flags)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Internal callback function which adds any contact which is unreachable */
|
||||||
|
static int registrar_add_unreachable(void *obj, void *arg, int flags)
|
||||||
|
{
|
||||||
|
struct ast_sip_contact *contact = obj;
|
||||||
|
struct ao2_container *container = arg;
|
||||||
|
struct ast_sip_contact_status *status;
|
||||||
|
int unreachable;
|
||||||
|
|
||||||
|
status = ast_sip_get_contact_status(contact);
|
||||||
|
if (!status) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable = (status->status == UNAVAILABLE);
|
||||||
|
ao2_ref(status, -1);
|
||||||
|
|
||||||
|
if (unreachable) {
|
||||||
|
ao2_link(container, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct aor_core_response {
|
struct aor_core_response {
|
||||||
/*! Tx data to use for statefull response. NULL for stateless response. */
|
/*! Tx data to use for statefull response. NULL for stateless response. */
|
||||||
pjsip_tx_data *tdata;
|
pjsip_tx_data *tdata;
|
||||||
@@ -596,6 +668,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
int permanent = 0;
|
int permanent = 0;
|
||||||
int contact_count;
|
int contact_count;
|
||||||
struct ao2_container *existing_contacts = NULL;
|
struct ao2_container *existing_contacts = NULL;
|
||||||
|
struct ao2_container *unavail_contacts = NULL;
|
||||||
pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
|
pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
|
||||||
struct registrar_contact_details details = { 0, };
|
struct registrar_contact_details details = { 0, };
|
||||||
pjsip_tx_data *tdata;
|
pjsip_tx_data *tdata;
|
||||||
@@ -666,6 +739,33 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
/* Total contacts after this registration */
|
/* Total contacts after this registration */
|
||||||
contact_count = ao2_container_count(contacts) - permanent + added - deleted;
|
contact_count = ao2_container_count(contacts) - permanent + added - deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contact_count > aor->max_contacts && aor->remove_unavailable) {
|
||||||
|
/* Get unavailable contact total */
|
||||||
|
int unavail_count = 0;
|
||||||
|
|
||||||
|
unavail_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
|
||||||
|
NULL, ast_sorcery_object_id_compare);
|
||||||
|
if (!unavail_contacts) {
|
||||||
|
response->code = 500;
|
||||||
|
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ao2_callback(contacts, OBJ_NODATA, registrar_add_unreachable, unavail_contacts);
|
||||||
|
if (unavail_contacts) {
|
||||||
|
unavail_count = ao2_container_count(unavail_contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to see if removing unavailable contacts will help */
|
||||||
|
if (contact_count - unavail_count <= aor->max_contacts) {
|
||||||
|
/* Remove any unavailable contacts */
|
||||||
|
remove_excess_contacts(unavail_contacts, contacts, contact_count - aor->max_contacts, aor->remove_existing);
|
||||||
|
ao2_cleanup(unavail_contacts);
|
||||||
|
/* We're only here if !aor->remove_existing so this count is correct */
|
||||||
|
contact_count = ao2_container_count(contacts) - permanent + added - deleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (contact_count > aor->max_contacts) {
|
if (contact_count > aor->max_contacts) {
|
||||||
/* Enforce the maximum number of contacts */
|
/* Enforce the maximum number of contacts */
|
||||||
ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
|
ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
|
||||||
@@ -867,8 +967,9 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
/* Total contacts after this registration */
|
/* Total contacts after this registration */
|
||||||
contact_count = ao2_container_count(existing_contacts) + updated + added;
|
contact_count = ao2_container_count(existing_contacts) + updated + added;
|
||||||
if (contact_count > aor->max_contacts) {
|
if (contact_count > aor->max_contacts) {
|
||||||
/* Remove excess existing contacts that expire the soonest */
|
/* Remove excess existing contacts that are unavailable or expire soonest */
|
||||||
remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts);
|
remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts,
|
||||||
|
aor->remove_existing);
|
||||||
}
|
}
|
||||||
ao2_ref(existing_contacts, -1);
|
ao2_ref(existing_contacts, -1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user