diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_pjsip/location.c | 44 | ||||
-rw-r--r-- | res/res_pjsip_outbound_publish.c | 32 | ||||
-rw-r--r-- | res/res_pjsip_registrar.c | 55 | ||||
-rw-r--r-- | res/res_pjsip_registrar_expire.c | 18 |
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; } |