summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
Diffstat (limited to 'res')
-rw-r--r--res/res_pjsip/location.c44
-rw-r--r--res/res_pjsip_outbound_publish.c32
-rw-r--r--res/res_pjsip_registrar.c55
-rw-r--r--res/res_pjsip_registrar_expire.c18
4 files changed, 132 insertions, 17 deletions
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 735b18f46..3413708e9 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -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)
@@ -173,7 +174,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];
@@ -196,6 +197,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)
{
@@ -279,7 +298,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)
{
@@ -316,6 +335,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);
diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c
index c16ced311..74b06c2ef 100644
--- a/res/res_pjsip_outbound_publish.c
+++ b/res/res_pjsip_outbound_publish.c
@@ -87,6 +87,13 @@
<configOption name="max_auth_attempts" default="5">
<synopsis>Maximum number of authentication attempts before stopping the publication.</synopsis>
</configOption>
+ <configOption name="transport">
+ <synopsis>Transport used for outbound publish</synopsis>
+ <description>
+ <note><para>A <replaceable>transport</replaceable> configured in
+ <literal>pjsip.conf</literal>. As with other <literal>res_pjsip</literal> modules, this will use the first available transport of the appropriate type if unconfigured.</para></note>
+ </description>
+ </configOption>
<configOption name="type">
<synopsis>Must be of type 'outbound-publish'.</synopsis>
</configOption>
@@ -117,6 +124,8 @@ struct ast_sip_outbound_publish {
AST_STRING_FIELD(from_uri);
/*! \brief URI for the To header */
AST_STRING_FIELD(to_uri);
+ /*! \brief Explicit transport to use for publish */
+ AST_STRING_FIELD(transport);
/*! \brief Outbound proxy to use */
AST_STRING_FIELD(outbound_proxy);
/*! \brief The event type to publish */
@@ -150,6 +159,8 @@ struct ast_sip_outbound_publish_client {
unsigned int destroy;
/*! \brief Outbound publish information */
struct ast_sip_outbound_publish *publish;
+ /*! \brief The name of the transport to be used for the publish */
+ char *transport_name;
};
/*! \brief Outbound publish state information (persists for lifetime of a publish) */
@@ -331,6 +342,12 @@ static int send_unpublish_task(void *data)
pjsip_tx_data *tdata;
if (pjsip_publishc_unpublish(client->client, &tdata) == PJ_SUCCESS) {
+ if (!ast_strlen_zero(client->transport_name)) {
+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+ ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector);
+ pjsip_tx_data_set_transport(tdata, &selector);
+ }
+
pjsip_publishc_send(client->client, tdata);
}
@@ -566,6 +583,12 @@ static int sip_publish_client_service_queue(void *data)
goto fatal;
}
+ if (!ast_strlen_zero(client->transport_name)) {
+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+ ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector);
+ pjsip_tx_data_set_transport(tdata, &selector);
+ }
+
status = pjsip_publishc_send(client->client, tdata);
if (status == PJ_EBUSY) {
/* We attempted to send the message but something else got there first */
@@ -647,6 +670,7 @@ static void sip_outbound_publish_client_destroy(void *obj)
ao2_cleanup(client->datastores);
ao2_cleanup(client->publish);
+ ast_free(client->transport_name);
/* if unloading the module and all objects have been unpublished
send the signal to finish unloading */
@@ -869,6 +893,12 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param)
if (param->code == 401 || param->code == 407) {
if (!ast_sip_create_request_with_auth(&publish->outbound_auths,
param->rdata, pjsip_rdata_get_tsx(param->rdata), &tdata)) {
+ if (!ast_strlen_zero(client->transport_name)) {
+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
+ ast_sip_set_tpselector_from_transport_name(client->transport_name, &selector);
+ pjsip_tx_data_set_transport(tdata, &selector);
+ }
+
pjsip_publishc_send(client->client, tdata);
}
client->auth_attempts++;
@@ -1028,6 +1058,7 @@ static struct ast_sip_outbound_publish_state *sip_outbound_publish_state_alloc(
state->client->timer.user_data = state->client;
state->client->timer.cb = sip_outbound_publish_timer_cb;
+ state->client->transport_name = ast_strdup(publish->transport);
state->client->publish = ao2_bump(publish);
strcpy(state->id, id);
@@ -1121,6 +1152,7 @@ static int load_module(void)
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, outbound_proxy));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, expiration));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "max_auth_attempts", "5", OPT_UINT_T, 0, FLDSET(struct ast_sip_outbound_publish, max_auth_attempts));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, transport));
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "outbound-publish", "outbound_auth", "", outbound_auth_handler, NULL, NULL, 0, 0);
ast_sorcery_reload_object(ast_sip_get_sorcery(), "outbound-publish");
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index fb2b9daba..4a42102dc 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -32,6 +32,7 @@
#include "asterisk/test.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/manager.h"
+#include "asterisk/named_locks.h"
#include "res_pjsip/include/res_pjsip_private.h"
/*** DOCUMENTATION
@@ -412,27 +413,21 @@ static int registrar_validate_path(struct rx_task_data *task_data, struct ast_st
return -1;
}
-static int rx_task(void *data)
+static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *contacts,
+ const char *aor_name)
{
static const pj_str_t USER_AGENT = { "User-Agent", 10 };
- RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
- RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-
int added = 0, updated = 0, deleted = 0;
pjsip_contact_hdr *contact_hdr = NULL;
struct registrar_contact_details details = { 0, };
pjsip_tx_data *tdata;
- const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
struct ast_sip_contact *response_contact;
char *user_agent = NULL;
pjsip_user_agent_hdr *user_agent_hdr;
pjsip_expires_hdr *expires_hdr;
- /* Retrieve the current contacts, we'll need to know whether to update or not */
- contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
-
/* So we don't count static contacts against max_contacts we prune them out from the container */
ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
@@ -503,7 +498,7 @@ static int rx_task(void *data)
continue;
}
- if (ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
+ if (ast_sip_location_add_contact_nolock(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
user_agent, task_data->endpoint)) {
ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
@@ -545,7 +540,7 @@ static int rx_task(void *data)
if (ast_sip_location_update_contact(contact_update)) {
ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
contact->uri, expiration);
- ast_sorcery_delete(ast_sip_get_sorcery(), contact);
+ ast_sip_location_delete_contact(contact);
continue;
}
ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
@@ -584,15 +579,14 @@ static int rx_task(void *data)
ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
}
- /* Update the contacts as things will probably have changed */
- ao2_cleanup(contacts);
-
- contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
+ /* Re-retrieve contacts. Caller will clean up the original container. */
+ contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor);
response_contact = ao2_callback(contacts, 0, NULL, NULL);
/* Send a response containing all of the contacts (including static) that are present on this AOR */
if (ast_sip_create_response(task_data->rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
ao2_cleanup(response_contact);
+ ao2_cleanup(contacts);
return PJ_TRUE;
}
ao2_cleanup(response_contact);
@@ -601,6 +595,7 @@ static int rx_task(void *data)
registrar_add_date_header(tdata);
ao2_callback(contacts, 0, registrar_add_contact, tdata);
+ ao2_cleanup(contacts);
if ((expires_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(task_data->aor, NULL, task_data->rdata));
@@ -612,6 +607,38 @@ static int rx_task(void *data)
return PJ_TRUE;
}
+static int rx_task(void *data)
+{
+ int res;
+ struct rx_task_data *task_data = data;
+ struct ao2_container *contacts = NULL;
+ struct ast_named_lock *lock;
+ const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
+
+ lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", aor_name);
+ if (!lock) {
+ ao2_cleanup(task_data);
+ return PJ_TRUE;
+ }
+
+ ao2_wrlock(lock);
+ contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor);
+ if (!contacts) {
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
+ ao2_cleanup(task_data);
+ return PJ_TRUE;
+ }
+
+ res = rx_task_core(task_data, contacts, aor_name);
+ ao2_cleanup(contacts);
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
+ ao2_cleanup(task_data);
+
+ return res;
+}
+
static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
{
RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c
index 97f2ca1c0..0fddbda91 100644
--- a/res/res_pjsip_registrar_expire.c
+++ b/res/res_pjsip_registrar_expire.c
@@ -30,6 +30,7 @@
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
+#include "asterisk/named_locks.h"
/*! \brief Thread keeping things alive */
static pthread_t check_thread = AST_PTHREADT_NULL;
@@ -41,8 +42,23 @@ static unsigned int check_interval;
static int expire_contact(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
+ struct ast_named_lock *lock;
- ast_sorcery_delete(ast_sip_get_sorcery(), contact);
+ lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", contact->aor);
+ if (!lock) {
+ return 0;
+ }
+
+ /*
+ * We need to check the expiration again with the aor lock held
+ * in case another thread is attempting to renew the contact.
+ */
+ ao2_wrlock(lock);
+ if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
+ ast_sip_location_delete_contact(contact);
+ }
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
return 0;
}