res_pjsip: Handle reloading when permanent contacts exist and qualify is configured.
This change fixes a problem where permanent contacts being qualified were not being updated. This was caused by the permanent contacts getting a uuid and not a known identifier, causing an inability to look them up when updating in the qualify code. A bug also existed where the new configuration may not be available immediately when updating qualifies. (closes issue ASTERISK-23514) Reported by: Richard Mudgett Review: https://reviewboard.asterisk.org/r/3448/ ........ Merged revisions 412551 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@412552 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
c76608f24b
commit
1a9ff2fffb
|
@ -2258,6 +2258,18 @@ static void remove_request_headers(pjsip_endpoint *endpt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \internal
|
||||||
|
* \brief Reload configuration within a PJSIP thread
|
||||||
|
*/
|
||||||
|
static int reload_configuration_task(void *obj)
|
||||||
|
{
|
||||||
|
ast_res_pjsip_reload_configuration();
|
||||||
|
ast_res_pjsip_init_options_handling(1);
|
||||||
|
ast_sip_initialize_dns();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int load_module(void)
|
static int load_module(void)
|
||||||
{
|
{
|
||||||
/* The third parameter is just copied from
|
/* The third parameter is just copied from
|
||||||
|
@ -2409,11 +2421,11 @@ static int load_module(void)
|
||||||
|
|
||||||
static int reload_module(void)
|
static int reload_module(void)
|
||||||
{
|
{
|
||||||
if (ast_res_pjsip_reload_configuration()) {
|
if (ast_sip_push_task(NULL, reload_configuration_task, NULL)) {
|
||||||
return AST_MODULE_LOAD_DECLINE;
|
ast_log(LOG_WARNING, "Failed to reload PJSIP\n");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
ast_res_pjsip_init_options_handling(1);
|
|
||||||
ast_sip_initialize_dns();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,25 +255,66 @@ static int permanent_contact_validate(void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags)
|
||||||
|
{
|
||||||
|
const struct ast_sip_contact *object_left = obj_left;
|
||||||
|
const struct ast_sip_contact *object_right = obj_right;
|
||||||
|
const char *right_key = obj_right;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
switch (flags & OBJ_SEARCH_MASK) {
|
||||||
|
case OBJ_SEARCH_OBJECT:
|
||||||
|
right_key = ast_sorcery_object_get_id(object_right);
|
||||||
|
/* Fall through */
|
||||||
|
case OBJ_SEARCH_KEY:
|
||||||
|
cmp = strcmp(ast_sorcery_object_get_id(object_left), right_key);
|
||||||
|
break;
|
||||||
|
case OBJ_SEARCH_PARTIAL_KEY:
|
||||||
|
/*
|
||||||
|
* We could also use a partial key struct containing a length
|
||||||
|
* so strlen() does not get called for every comparison instead.
|
||||||
|
*/
|
||||||
|
cmp = strncmp(ast_sorcery_object_get_id(object_left), right_key, strlen(right_key));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Sort can only work on something with a full or partial key. */
|
||||||
|
ast_assert(0);
|
||||||
|
cmp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cmp;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Custom handler for permanent URIs */
|
/*! \brief Custom handler for permanent URIs */
|
||||||
static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||||
{
|
{
|
||||||
struct ast_sip_aor *aor = obj;
|
struct ast_sip_aor *aor = obj;
|
||||||
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
|
const char *aor_id = ast_sorcery_object_get_id(aor);
|
||||||
|
struct ast_sip_contact *contact;
|
||||||
|
char contact_id[strlen(aor_id) + strlen(var->value) + 2 + 1];
|
||||||
|
|
||||||
if (ast_sip_push_task_synchronous(NULL, permanent_contact_validate, (char*)var->value)) {
|
if (ast_sip_push_task_synchronous(NULL, permanent_contact_validate, (char *) var->value)) {
|
||||||
ast_log(LOG_ERROR, "Permanent URI on aor '%s' with contact '%s' failed to parse\n",
|
ast_log(LOG_ERROR, "Permanent URI on aor '%s' with contact '%s' failed to parse\n",
|
||||||
ast_sorcery_object_get_id(aor), var->value);
|
aor_id, var->value);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!aor->permanent_contacts && !(aor->permanent_contacts = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) ||
|
if (!aor->permanent_contacts) {
|
||||||
!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", NULL))) {
|
aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
|
||||||
return -1;
|
AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
|
||||||
|
if (!aor->permanent_contacts) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, var->value);
|
||||||
|
contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id);
|
||||||
|
if (!contact) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
ast_string_field_set(contact, uri, var->value);
|
ast_string_field_set(contact, uri, var->value);
|
||||||
ao2_link(aor->permanent_contacts, contact);
|
ao2_link(aor->permanent_contacts, contact);
|
||||||
|
ao2_ref(contact, -1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1812,11 +1812,7 @@ void ast_res_pjsip_destroy_configuration(void)
|
||||||
ast_sorcery_unref(sip_sorcery);
|
ast_sorcery_unref(sip_sorcery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
int ast_res_pjsip_reload_configuration(void)
|
||||||
* \internal
|
|
||||||
* \brief Reload configuration within a PJSIP thread
|
|
||||||
*/
|
|
||||||
static int reload_configuration_task(void *obj)
|
|
||||||
{
|
{
|
||||||
if (sip_sorcery) {
|
if (sip_sorcery) {
|
||||||
ast_sorcery_reload(sip_sorcery);
|
ast_sorcery_reload(sip_sorcery);
|
||||||
|
@ -1824,15 +1820,6 @@ static int reload_configuration_task(void *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_res_pjsip_reload_configuration(void)
|
|
||||||
{
|
|
||||||
if (ast_sip_push_task(NULL, reload_configuration_task, NULL)) {
|
|
||||||
ast_log(LOG_WARNING, "Failed to reload PJSIP configuration\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription)
|
static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription)
|
||||||
{
|
{
|
||||||
ast_string_field_free_memory(&subscription->mwi);
|
ast_string_field_free_memory(&subscription->mwi);
|
||||||
|
|
|
@ -403,14 +403,15 @@ static void schedule_qualify(struct ast_sip_contact *contact)
|
||||||
*/
|
*/
|
||||||
static void unschedule_qualify(struct ast_sip_contact *contact)
|
static void unschedule_qualify(struct ast_sip_contact *contact)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct sched_data *, data, ao2_find(
|
struct sched_data *data;
|
||||||
sched_qualifies, contact, OBJ_UNLINK), ao2_cleanup);
|
|
||||||
|
|
||||||
|
data = ao2_find(sched_qualifies, contact, OBJ_UNLINK | OBJ_SEARCH_KEY);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_SCHED_DEL_UNREF(sched, data->id, ao2_cleanup(data));
|
AST_SCHED_DEL_UNREF(sched, data->id, ao2_cleanup(data));
|
||||||
|
ao2_ref(data, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -778,17 +779,60 @@ static struct ast_cli_entry cli_options[] = {
|
||||||
|
|
||||||
static int sched_qualifies_hash_fn(const void *obj, int flags)
|
static int sched_qualifies_hash_fn(const void *obj, int flags)
|
||||||
{
|
{
|
||||||
const struct sched_data *data = obj;
|
const struct sched_data *object;
|
||||||
|
const struct ast_sip_contact *key;
|
||||||
|
|
||||||
return ast_str_hash(ast_sorcery_object_get_id(data->contact));
|
switch (flags & OBJ_SEARCH_MASK) {
|
||||||
|
case OBJ_SEARCH_KEY:
|
||||||
|
key = obj;
|
||||||
|
break;
|
||||||
|
case OBJ_SEARCH_OBJECT:
|
||||||
|
object = obj;
|
||||||
|
key = object->contact;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Hash can only work on something with a full key. */
|
||||||
|
ast_assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ast_str_hash(ast_sorcery_object_get_id(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sched_qualifies_cmp_fn(void *obj, void *arg, int flags)
|
static int sched_qualifies_cmp_fn(void *obj, void *arg, int flags)
|
||||||
{
|
{
|
||||||
struct sched_data *data = obj;
|
const struct sched_data *object_left = obj;
|
||||||
|
const struct sched_data *object_right = arg;
|
||||||
|
struct ast_sip_contact *right_key = arg;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
return !strcmp(ast_sorcery_object_get_id(data->contact),
|
switch (flags & OBJ_SEARCH_MASK) {
|
||||||
ast_sorcery_object_get_id(arg));
|
case OBJ_SEARCH_OBJECT:
|
||||||
|
right_key = object_right->contact;
|
||||||
|
/* Fall through */
|
||||||
|
case OBJ_SEARCH_KEY:
|
||||||
|
cmp = strcmp(ast_sorcery_object_get_id(object_left->contact),
|
||||||
|
ast_sorcery_object_get_id(right_key));
|
||||||
|
break;
|
||||||
|
case OBJ_SEARCH_PARTIAL_KEY:
|
||||||
|
/* Not supported by container. */
|
||||||
|
ast_assert(0);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* What arg points to is specific to this traversal callback
|
||||||
|
* and has no special meaning to astobj2.
|
||||||
|
*/
|
||||||
|
cmp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cmp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* At this point the traversal callback is identical to a sorted
|
||||||
|
* container.
|
||||||
|
*/
|
||||||
|
return CMP_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_sip_initialize_sorcery_qualify(void)
|
int ast_sip_initialize_sorcery_qualify(void)
|
||||||
|
@ -884,7 +928,6 @@ int ast_res_pjsip_init_options_handling(int reload)
|
||||||
if (!(sched_qualifies = ao2_t_container_alloc(
|
if (!(sched_qualifies = ao2_t_container_alloc(
|
||||||
QUALIFIED_BUCKETS, sched_qualifies_hash_fn, sched_qualifies_cmp_fn,
|
QUALIFIED_BUCKETS, sched_qualifies_hash_fn, sched_qualifies_cmp_fn,
|
||||||
"Create container for scheduled qualifies"))) {
|
"Create container for scheduled qualifies"))) {
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ static int registrar_prune_static(void *obj, void *arg, int flags)
|
||||||
return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
|
return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Internal function used to delete all contacts from an AOR */
|
/*! \brief Internal function used to delete a contact from an AOR */
|
||||||
static int registrar_delete_contact(void *obj, void *arg, int flags)
|
static int registrar_delete_contact(void *obj, void *arg, int flags)
|
||||||
{
|
{
|
||||||
struct ast_sip_contact *contact = obj;
|
struct ast_sip_contact *contact = obj;
|
||||||
|
|
Loading…
Reference in New Issue