[svn-commits] file: branch file/pjsip-outbound-publish r420047 - /team/file/pjsip-outbound-...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Tue Aug 5 12:16:32 CDT 2014
Author: file
Date: Tue Aug 5 12:16:28 2014
New Revision: 420047
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=420047
Log:
Ensure that the publish configuration remains valid for the lifetime that the callback may be called.
Modified:
team/file/pjsip-outbound-publish/res/res_pjsip_outbound_publish.c
Modified: team/file/pjsip-outbound-publish/res/res_pjsip_outbound_publish.c
URL: http://svnview.digium.com/svn/asterisk/team/file/pjsip-outbound-publish/res/res_pjsip_outbound_publish.c?view=diff&rev=420047&r1=420046&r2=420047
==============================================================================
--- team/file/pjsip-outbound-publish/res/res_pjsip_outbound_publish.c (original)
+++ team/file/pjsip-outbound-publish/res/res_pjsip_outbound_publish.c Tue Aug 5 12:16:28 2014
@@ -121,10 +121,8 @@
struct sip_outbound_publish_message *sending;
/*! \brief Publish client has been fully started and event type informed */
unsigned int started;
-};
-
-/*! \brief Configuration information for publish client */
-struct sip_outbound_publish_configuration {
+ /*! \brief Publish client should be destroyed */
+ unsigned int destroy;
};
/*! \brief Outbound publish information */
@@ -156,6 +154,9 @@
AST_RWLIST_HEAD_STATIC(publisher_handlers, ast_sip_event_publisher_handler);
+/*! \brief Container of currently active publish clients */
+static AO2_GLOBAL_OBJ_STATIC(active);
+
static void sub_add_handler(struct ast_sip_event_publisher_handler *handler)
{
AST_RWLIST_INSERT_TAIL(&publisher_handlers, handler, next);
@@ -231,6 +232,21 @@
struct ast_sip_outbound_publish_client *state = data;
cancel_publish_refresh(state);
+ ao2_ref(state, -1);
+
+ return 0;
+}
+
+/*! \brief Task for sending an unpublish */
+static int send_unpublish_task(void *data)
+{
+ struct ast_sip_outbound_publish_client *state = data;
+ pjsip_tx_data *tdata;
+
+ if (pjsip_publishc_unpublish(state->client, &tdata) == PJ_SUCCESS) {
+ pjsip_publishc_send(state->client, tdata);
+ }
+
ao2_ref(state, -1);
return 0;
@@ -441,7 +457,7 @@
pjsip_tx_data *tdata;
pj_status_t status;
- if (client->sending || !(message = AST_LIST_FIRST(&client->queue))) {
+ if (client->destroy || client->sending || !(message = AST_LIST_FIRST(&client->queue))) {
return 0;
}
@@ -528,14 +544,7 @@
struct ast_sip_outbound_publish_client *state = obj;
struct sip_outbound_publish_message *message;
- if (state->client) {
- pjsip_tx_data *tdata;
-
- if (pjsip_publishc_unpublish(state->client, &tdata) == PJ_SUCCESS) {
- pjsip_publishc_send(state->client, tdata);
- }
- pjsip_publishc_destroy(state->client);
- }
+ /* You might be tempted to think "the publish client isn't being destroyed" but it actually is - just elsewhere */
while ((message = AST_LIST_REMOVE_HEAD(&state->queue, entry))) {
ast_free(message);
@@ -589,8 +598,9 @@
if (publish->state->client) {
return 0;
} else if (!publish->state->client &&
- pjsip_publishc_create(ast_sip_get_pjsip_endpoint(), &opt, publish, sip_outbound_publish_callback,
+ pjsip_publishc_create(ast_sip_get_pjsip_endpoint(), &opt, ao2_bump(publish), sip_outbound_publish_callback,
&publish->state->client) != PJ_SUCCESS) {
+ ao2_ref(publish, -1);
return -1;
}
@@ -602,6 +612,7 @@
if (!(route = pjsip_parse_hdr(pjsip_publishc_get_pool(publish->state->client), &ROUTE_HNAME,
(char*)publish->outbound_proxy, strlen(publish->outbound_proxy), NULL))) {
+ pjsip_publishc_destroy(publish->state->client);
return -1;
}
pj_list_insert_nodes_before(&route_set, route);
@@ -625,6 +636,7 @@
if (!pool) {
ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound publish '%s'\n",
ast_sorcery_object_get_id(publish));
+ pjsip_publishc_destroy(publish->state->client);
return -1;
}
@@ -654,8 +666,10 @@
}
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+ pjsip_publishc_destroy(publish->state->client);
return -1;
} else if (status != PJ_SUCCESS) {
+ pjsip_publishc_destroy(publish->state->client);
return -1;
}
@@ -665,11 +679,22 @@
/*! \brief Callback function for publish client responses */
static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param)
{
- struct ast_sip_outbound_publish *publish = param->token;
+ RAII_VAR(struct ast_sip_outbound_publish *, publish, ao2_bump(param->token), ao2_cleanup);
SCOPED_AO2LOCK(lock, publish->state);
+ pjsip_tx_data *tdata;
+
+ if (publish->state->destroy) {
+ if (publish->state->sending &&
+ pjsip_publishc_unpublish(publish->state->client, &tdata) == PJ_SUCCESS) {
+ pjsip_publishc_send(publish->state->client, tdata);
+ }
+ /* Once the destroy is called this callback will not get called any longer, so drop the publish ref */
+ pjsip_publishc_destroy(publish->state->client);
+ ao2_ref(publish, -1);
+ return;
+ }
if (param->code == 401 || param->code == 407) {
- pjsip_tx_data *tdata;
if (!ast_sip_create_request_with_auth(&publish->outbound_auths,
param->rdata, pjsip_rdata_get_tsx(param->rdata), &tdata)) {
pjsip_publishc_send(publish->state->client, tdata);
@@ -680,7 +705,7 @@
pjsip_publishc_destroy(publish->state->client);
publish->state->client = NULL;
- ast_log(LOG_ERROR, "Reached maximum number of PUBLISH authentication attempts on '%s'\n",
+ ast_log(LOG_ERROR, "Reached maximum number of PUBLISH authentication attempts on outbound publish '%s'\n",
ast_sorcery_object_get_id(publish));
goto end;
@@ -866,6 +891,72 @@
return ast_sip_auth_vector_init(&publish->outbound_auths, var->value);
}
+/*! \brief Helper function which prunes old publish clients */
+static void prune_publish_clients(const char *object_type)
+{
+ struct ao2_container *old, *current;
+
+ old = ao2_global_obj_ref(active);
+ if (old) {
+ struct ao2_iterator i;
+ struct ast_sip_outbound_publish *existing;
+
+ i = ao2_iterator_init(old, 0);
+ for (; (existing = ao2_iterator_next(&i)); ao2_ref(existing, -1)) {
+ struct ast_sip_outbound_publish *created;
+
+ created = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "outbound-publish",
+ ast_sorcery_object_get_id(existing));
+ if (created) {
+ if (created->state == existing->state) {
+ ao2_ref(created, -1);
+ continue;
+ }
+ ao2_ref(created, -1);
+ }
+
+ ao2_lock(existing->state);
+
+ /* If this publish client is currently publishing stop and terminate any refresh timer */
+ if (existing->state->started) {
+ struct ast_sip_event_publisher_handler *handler = find_publisher_handler_for_event_name(existing->event);
+
+ if (handler) {
+ handler->stop_publishing(existing->state);
+ }
+
+ if (ast_sip_push_task(NULL, cancel_refresh_timer_task, ao2_bump(existing->state))) {
+ ast_log(LOG_WARNING, "Could not stop refresh timer on outbound publish '%s'\n",
+ ast_sorcery_object_get_id(existing));
+ ao2_ref(existing->state, -1);
+ }
+ }
+
+ /* If nothing is being sent right now send the unpublish - the destroy will happen in the subsequent callback */
+ if (!existing->state->sending) {
+ if (ast_sip_push_task(NULL, send_unpublish_task, ao2_bump(existing->state))) {
+ ast_log(LOG_WARNING, "Could not send unpublish message on outbound publish '%s'\n",
+ ast_sorcery_object_get_id(existing));
+ ao2_ref(existing->state, -1);
+ }
+ }
+
+ existing->state->destroy = 1;
+ ao2_unlock(existing->state);
+ }
+ ao2_iterator_destroy(&i);
+
+ ao2_ref(old, -1);
+ }
+
+ current = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "outbound-publish", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+ ao2_global_obj_replace_unref(active, current);
+}
+
+static struct ast_sorcery_observer outbound_publish_observer = {
+ .loaded = prune_publish_clients,
+};
+
static int load_module(void)
{
ast_sorcery_apply_default(ast_sip_get_sorcery(), "outbound-publish", "config", "pjsip.conf,criteria=type=outbound-publish");
@@ -874,6 +965,8 @@
sip_outbound_publish_apply)) {
return AST_MODULE_LOAD_DECLINE;
}
+
+ ast_sorcery_observer_add(ast_sip_get_sorcery(), "outbound-publish", &outbound_publish_observer);
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "outbound-publish", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_outbound_publish, server_uri));
@@ -897,7 +990,8 @@
static int reload_module(void)
{
- ast_sorcery_reload_object(ast_sip_get_sorcery(), "publish");
+ ast_sorcery_reload_object(ast_sip_get_sorcery(), "outbound-publish");
+
AST_RWLIST_RDLOCK(&publisher_handlers);
sip_outbound_publish_synchronize(NULL);
AST_RWLIST_UNLOCK(&publisher_handlers);
More information about the svn-commits
mailing list