res_pjsip contact: Lock expiration/addition of contacts

Contact expiration can occur in several places:  res_pjsip_registrar,
res_pjsip_registrar_expire, and automatically when anyone calls
ast_sip_location_retrieve_aor_contact.  At the same time, res_pjsip_registrar
may also be attempting to renew or add a contact.  Since none of this was locked
it was possible for one thread to be renewing a contact and another thread to
expire it immediately because it was working off of stale data.  This was the
casue of intermittent registration/inbound/nominal/multiple_contacts test
failures.

Now, the new named lock functionality is used to lock the aor during contact
expire and add operations and res_pjsip_registrar_expire now checks the
expiration with the lock held before deleting the contact.

ASTERISK-25885 #close
Reported-by: Josh Colp

Change-Id: I83d413c46a47796f3ab052ca3b349f21cca47059
This commit is contained in:
George Joseph
2016-04-01 12:30:56 -06:00
committed by Joshua Colp
parent 44fba00ca4
commit a621dd5e96
4 changed files with 143 additions and 17 deletions

View File

@@ -27,6 +27,7 @@
#include "include/res_pjsip_private.h"
#include "asterisk/res_pjsip_cli.h"
#include "asterisk/statsd.h"
#include "asterisk/named_locks.h"
/*! \brief Destructor for AOR */
static void aor_destroy(void *obj)
@@ -168,7 +169,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct
return contact;
}
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor)
{
/* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
char regex[strlen(ast_sorcery_object_get_id(aor)) + 4];
@@ -191,6 +192,24 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si
return contacts;
}
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
{
struct ao2_container *contacts;
struct ast_named_lock *lock;
lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor));
if (!lock) {
return NULL;
}
ao2_wrlock(lock);
contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
ao2_unlock(lock);
ast_named_lock_put(lock);
return contacts;
}
void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor,
struct ast_sip_contact **contact)
{
@@ -274,7 +293,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
}
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent,
struct ast_sip_endpoint *endpoint)
{
@@ -311,6 +330,27 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
return ast_sorcery_create(ast_sip_get_sorcery(), contact);
}
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent,
struct ast_sip_endpoint *endpoint)
{
int res;
struct ast_named_lock *lock;
lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor));
if (!lock) {
return -1;
}
ao2_wrlock(lock);
res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent,
endpoint);
ao2_unlock(lock);
ast_named_lock_put(lock);
return res;
}
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
{
return ast_sorcery_update(ast_sip_get_sorcery(), contact);