mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 07:35:18 +00:00
Merge "res_pjsip_registrar: Improve performance on inbound handling." into 16
This commit is contained in:
@@ -122,25 +122,28 @@ static int registrar_find_contact(void *obj, void *arg, int flags)
|
|||||||
{
|
{
|
||||||
struct ast_sip_contact *contact = obj;
|
struct ast_sip_contact *contact = obj;
|
||||||
const struct registrar_contact_details *details = arg;
|
const struct registrar_contact_details *details = arg;
|
||||||
pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
|
pjsip_uri *contact_uri;
|
||||||
|
|
||||||
|
if (ast_tvzero(contact->expiration_time)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
|
||||||
|
|
||||||
return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
|
return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
|
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
|
||||||
static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
|
static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *pool, struct ao2_container *contacts,
|
||||||
|
struct ast_sip_aor *aor, int permanent, int *added, int *updated, int *deleted)
|
||||||
{
|
{
|
||||||
pjsip_contact_hdr *previous = NULL;
|
pjsip_contact_hdr *previous = NULL;
|
||||||
pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
|
pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
|
||||||
struct registrar_contact_details details = {
|
struct registrar_contact_details details = {
|
||||||
.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
|
.pool = pool,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!details.pool) {
|
for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
|
|
||||||
int expiration = registrar_get_expiration(aor, contact, rdata);
|
int expiration = registrar_get_expiration(aor, contact, rdata);
|
||||||
struct ast_sip_contact *existing;
|
struct ast_sip_contact *existing;
|
||||||
char contact_uri[pjsip_max_url_size];
|
char contact_uri[pjsip_max_url_size];
|
||||||
@@ -148,16 +151,14 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
|
|||||||
if (contact->star) {
|
if (contact->star) {
|
||||||
/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
|
/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
|
||||||
if (expiration != 0 || previous) {
|
if (expiration != 0 || previous) {
|
||||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Count all contacts to delete */
|
/* Count all contacts to delete */
|
||||||
*deleted = ao2_container_count(contacts);
|
*deleted = ao2_container_count(contacts) - permanent;
|
||||||
previous = contact;
|
previous = contact;
|
||||||
continue;
|
continue;
|
||||||
} else if (previous && previous->star) {
|
} else if (previous && previous->star) {
|
||||||
/* If there is a previous contact and it is a '*' this is a deal breaker */
|
/* If there is a previous contact and it is a '*' this is a deal breaker */
|
||||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
previous = contact;
|
previous = contact;
|
||||||
@@ -171,13 +172,11 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
|
|||||||
/* pjsip_uri_print returns -1 if there's not enough room in the buffer */
|
/* pjsip_uri_print returns -1 if there's not enough room in the buffer */
|
||||||
if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
|
if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
|
||||||
/* If the total length of the uri is greater than pjproject can handle, go no further */
|
/* If the total length of the uri is greater than pjproject can handle, go no further */
|
||||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.uri->host.slen >= pj_max_hostname) {
|
if (details.uri->host.slen >= pj_max_hostname) {
|
||||||
/* If the length of the hostname is greater than pjproject can handle, go no further */
|
/* If the length of the hostname is greater than pjproject can handle, go no further */
|
||||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,25 +194,20 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The provided contacts are acceptable, huzzah! */
|
|
||||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Callback function which prunes static contacts */
|
|
||||||
static int registrar_prune_static(void *obj, void *arg, int flags)
|
|
||||||
{
|
|
||||||
struct ast_sip_contact *contact = obj;
|
|
||||||
|
|
||||||
return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Internal function used to delete a contact 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;
|
||||||
const char *aor_name = arg;
|
const char *aor_name = arg;
|
||||||
|
|
||||||
|
/* Permanent contacts can't be deleted */
|
||||||
|
if (ast_tvzero(contact->expiration_time)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ast_sip_location_delete_contact(contact);
|
ast_sip_location_delete_contact(contact);
|
||||||
if (!ast_strlen_zero(aor_name)) {
|
if (!ast_strlen_zero(aor_name)) {
|
||||||
ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
|
ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
|
||||||
@@ -270,7 +264,7 @@ static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*path_str = ast_str_create(64);
|
*path_str = ast_str_create(64);
|
||||||
if (!path_str) {
|
if (!*path_str) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,7 +436,8 @@ static int vec_contact_add(void *obj, void *arg, int flags)
|
|||||||
*
|
*
|
||||||
* \return Nothing
|
* \return Nothing
|
||||||
*/
|
*/
|
||||||
static void remove_excess_contacts(struct ao2_container *contacts, unsigned int to_remove)
|
static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts,
|
||||||
|
unsigned int to_remove)
|
||||||
{
|
{
|
||||||
struct excess_contact_vector contact_vec;
|
struct excess_contact_vector contact_vec;
|
||||||
|
|
||||||
@@ -482,11 +477,28 @@ static void remove_excess_contacts(struct ao2_container *contacts, unsigned int
|
|||||||
contact->uri,
|
contact->uri,
|
||||||
contact->aor,
|
contact->aor,
|
||||||
contact->user_agent);
|
contact->user_agent);
|
||||||
|
|
||||||
|
ao2_unlink(response_contacts, contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_VECTOR_FREE(&contact_vec);
|
AST_VECTOR_FREE(&contact_vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Callback function which adds non-permanent contacts to a container */
|
||||||
|
static int registrar_add_non_permanent(void *obj, void *arg, int flags)
|
||||||
|
{
|
||||||
|
struct ast_sip_contact *contact = obj;
|
||||||
|
struct ao2_container *container = arg;
|
||||||
|
|
||||||
|
if (ast_tvzero(contact->expiration_time)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -506,8 +518,10 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
int added = 0;
|
int added = 0;
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
|
int permanent = 0;
|
||||||
int contact_count;
|
int contact_count;
|
||||||
pjsip_contact_hdr *contact_hdr = NULL;
|
struct ao2_container *existing_contacts = NULL;
|
||||||
|
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;
|
||||||
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
|
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
|
||||||
@@ -523,15 +537,28 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
char *call_id = NULL;
|
char *call_id = NULL;
|
||||||
size_t alloc_size;
|
size_t alloc_size;
|
||||||
|
|
||||||
/* So we don't count static contacts against max_contacts we prune them out from the container */
|
/* We create a single pool and use it throughout this function where we need one */
|
||||||
ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
|
details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
|
||||||
|
"Contact Comparison", 1024, 256);
|
||||||
|
if (!details.pool) {
|
||||||
|
response->code = 500;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
|
/* If there are any permanent contacts configured on the AOR we need to take them
|
||||||
|
* into account when counting contacts.
|
||||||
|
*/
|
||||||
|
if (aor->permanent_contacts) {
|
||||||
|
permanent = ao2_container_count(aor->permanent_contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
|
||||||
/* The provided Contact headers do not conform to the specification */
|
/* The provided Contact headers do not conform to the specification */
|
||||||
ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
|
ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
|
||||||
ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
|
ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
|
||||||
ast_sorcery_object_get_id(endpoint));
|
ast_sorcery_object_get_id(endpoint));
|
||||||
response->code = 400;
|
response->code = 400;
|
||||||
|
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,15 +567,29 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
|
ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
|
||||||
ast_sorcery_object_get_id(endpoint));
|
ast_sorcery_object_get_id(endpoint));
|
||||||
response->code = 420;
|
response->code = 420;
|
||||||
|
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aor->remove_existing) {
|
if (aor->remove_existing) {
|
||||||
/* Cumulative number of contacts affected by this registration */
|
/* Cumulative number of contacts affected by this registration */
|
||||||
contact_count = MAX(updated + added - deleted, 0);
|
contact_count = MAX(updated + added - deleted, 0);
|
||||||
|
|
||||||
|
/* We need to keep track of only existing contacts so we can later
|
||||||
|
* remove them if need be.
|
||||||
|
*/
|
||||||
|
existing_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
|
||||||
|
NULL, ast_sorcery_object_id_compare);
|
||||||
|
if (!existing_contacts) {
|
||||||
|
response->code = 500;
|
||||||
|
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
|
||||||
} else {
|
} else {
|
||||||
/* Total contacts after this registration */
|
/* Total contacts after this registration */
|
||||||
contact_count = ao2_container_count(contacts) + added - deleted;
|
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 */
|
||||||
@@ -556,13 +597,8 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
|
ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
|
||||||
ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
|
ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
|
||||||
response->code = 403;
|
response->code = 403;
|
||||||
return;
|
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
|
||||||
}
|
ao2_cleanup(existing_contacts);
|
||||||
|
|
||||||
details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
|
|
||||||
"Contact Comparison", 256, 256);
|
|
||||||
if (!details.pool) {
|
|
||||||
response->code = 500;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,7 +631,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate each provided Contact header and add, update, or delete */
|
/* Iterate each provided Contact header and add, update, or delete */
|
||||||
while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
|
for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) {
|
||||||
int expiration;
|
int expiration;
|
||||||
char contact_uri[pjsip_max_url_size];
|
char contact_uri[pjsip_max_url_size];
|
||||||
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
|
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
|
||||||
@@ -604,6 +640,13 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
/* A star means to unregister everything, so do so for the possible contacts */
|
/* A star means to unregister everything, so do so for the possible contacts */
|
||||||
ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
|
ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
|
||||||
registrar_delete_contact, (void *)aor_name);
|
registrar_delete_contact, (void *)aor_name);
|
||||||
|
/* If we are keeping track of existing contacts for removal then, well, there is
|
||||||
|
* absolutely nothing left so no need to try to remove any.
|
||||||
|
*/
|
||||||
|
if (existing_contacts) {
|
||||||
|
ao2_ref(existing_contacts, -1);
|
||||||
|
existing_contacts = NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,6 +660,14 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
|
pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
|
||||||
|
|
||||||
contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
|
contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
|
||||||
|
|
||||||
|
/* If a contact was returned and we need to keep track of existing contacts then it
|
||||||
|
* should be removed.
|
||||||
|
*/
|
||||||
|
if (contact && existing_contacts) {
|
||||||
|
ao2_unlink(existing_contacts, contact);
|
||||||
|
}
|
||||||
|
|
||||||
if (!contact) {
|
if (!contact) {
|
||||||
int prune_on_boot;
|
int prune_on_boot;
|
||||||
|
|
||||||
@@ -672,6 +723,8 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
aor_name,
|
aor_name,
|
||||||
expiration,
|
expiration,
|
||||||
user_agent);
|
user_agent);
|
||||||
|
|
||||||
|
ao2_link(contacts, contact);
|
||||||
} else if (expiration) {
|
} else if (expiration) {
|
||||||
struct ast_sip_contact *contact_update;
|
struct ast_sip_contact *contact_update;
|
||||||
|
|
||||||
@@ -712,6 +765,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
aor_name,
|
aor_name,
|
||||||
expiration,
|
expiration,
|
||||||
contact_update->user_agent);
|
contact_update->user_agent);
|
||||||
|
ao2_link(contacts, contact_update);
|
||||||
ao2_cleanup(contact_update);
|
ao2_cleanup(contact_update);
|
||||||
} else {
|
} else {
|
||||||
if (contact->prune_on_boot) {
|
if (contact->prune_on_boot) {
|
||||||
@@ -749,24 +803,20 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
* that have not been updated/added/deleted as a result of this
|
* that have not been updated/added/deleted as a result of this
|
||||||
* REGISTER do so.
|
* REGISTER do so.
|
||||||
*
|
*
|
||||||
* The contacts container currently holds the existing contacts that
|
* The existing contacts container holds all contacts that were not
|
||||||
* were not affected by this REGISTER.
|
* involved in this REGISTER.
|
||||||
|
* The contacts container holds the current contacts of the AOR.
|
||||||
*/
|
*/
|
||||||
if (aor->remove_existing) {
|
if (aor->remove_existing && existing_contacts) {
|
||||||
/* Total contacts after this registration */
|
/* Total contacts after this registration */
|
||||||
contact_count = ao2_container_count(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 expire the soonest */
|
||||||
remove_excess_contacts(contacts, contact_count - aor->max_contacts);
|
remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts);
|
||||||
}
|
}
|
||||||
|
ao2_ref(existing_contacts, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-retrieve contacts. Caller will clean up the original container. */
|
|
||||||
contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
|
|
||||||
if (!contacts) {
|
|
||||||
response->code = 500;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
response_contact = ao2_callback(contacts, 0, NULL, NULL);
|
response_contact = ao2_callback(contacts, 0, NULL, NULL);
|
||||||
|
|
||||||
/* Send a response containing all of the contacts (including static) that are present on this AOR */
|
/* Send a response containing all of the contacts (including static) that are present on this AOR */
|
||||||
@@ -782,7 +832,6 @@ static void register_aor_core(pjsip_rx_data *rdata,
|
|||||||
registrar_add_date_header(tdata);
|
registrar_add_date_header(tdata);
|
||||||
|
|
||||||
ao2_callback(contacts, 0, registrar_add_contact, tdata);
|
ao2_callback(contacts, 0, registrar_add_contact, tdata);
|
||||||
ao2_cleanup(contacts);
|
|
||||||
|
|
||||||
if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
|
if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
|
||||||
expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
|
expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
|
||||||
|
Reference in New Issue
Block a user