[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