[Asterisk-code-review] res pjsip exten state: Create PUBLISH messages. (asterisk[master])

Anonymous Coward asteriskteam at digium.com
Tue May 3 06:10:53 CDT 2016


Anonymous Coward #1000019 has submitted this change and it was merged.

Change subject: res_pjsip_exten_state: Create PUBLISH messages.
......................................................................


res_pjsip_exten_state: Create PUBLISH messages.

Create PUBLISH messages to update a third party when an extension state
changes because of either a device or presence state change.

A configuration example:

[exten-state-publisher]
type=outbound-publish
server_uri=sip:instance1 at 172.16.10.2
event=presence
; Optional regex for context filtering, if specified only extension state
; for contexts matching the regex will cause a PUBLISH to be sent.
@context=^users
; Optional regex for extension filtering, if specified only extension
; state for extensions matching the regex will cause a PUBLISH to be sent.
@exten=^[0-9]*
; Required body type for the PUBLISH message.
;
; Supported values are:
; application/pidf+xml
; application/xpidf+xml
; application/cpim-pidf+xml
; application/dialog-info+xml (Planned support but not yet)
@body=application/pidf+xml

The '@' extended variables are used because the implementation can't
extend the outbound publish type as it is provided by the outbound publish
module.  That means you either have to use extended variables, or
implement some sort of custom extended variable thing in the outbound
publish module.  Another option would be to refactor that stuff to have an
option which specifies the use of an alternate implementation's
configuration and then have that passed to the implementation.  JColp
opted for the extended variables method originally.

ASTERISK-25972 #close

Change-Id: Ic0dab4022f5cf59302129483ed38398764ee3cca
---
M include/asterisk/res_pjsip_outbound_publish.h
M res/res_pjsip_exten_state.c
M res/res_pjsip_outbound_publish.c
3 files changed, 215 insertions(+), 1 deletion(-)

Approvals:
  Anonymous Coward #1000019: Verified
  Joshua Colp: Looks good to me, approved
  Matthew Fredrickson: Looks good to me, but someone else must approve



diff --git a/include/asterisk/res_pjsip_outbound_publish.h b/include/asterisk/res_pjsip_outbound_publish.h
index debec94..b2038f5 100644
--- a/include/asterisk/res_pjsip_outbound_publish.h
+++ b/include/asterisk/res_pjsip_outbound_publish.h
@@ -93,6 +93,28 @@
 struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name);
 
 /*!
+ * \brief Get the From URI the client will use.
+ * \since 14.0.0
+ *
+ * \param client The publication client to get the From URI
+ *
+ * \retval From-uri on success
+ * \retval Empty-string on failure
+ */
+const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_client *client);
+
+/*!
+ * \brief Get the To URI the client will use.
+ * \since 14.0.0
+ *
+ * \param client The publication client to get the To URI
+ *
+ * \retval From-uri on success
+ * \retval Empty-string on failure
+ */
+const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_client *client);
+
+/*!
  * \brief Alternative for ast_datastore_alloc()
  *
  * There are two major differences between this and ast_datastore_alloc()
diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c
index 6b4e758..76a88a2 100644
--- a/res/res_pjsip_exten_state.c
+++ b/res/res_pjsip_exten_state.c
@@ -56,6 +56,9 @@
  */
 static struct ao2_container *publishers;
 
+/*! Serializer for outbound extension state publishing. */
+static struct ast_taskprocessor *publish_exten_state_serializer;
+
 /*!
  * \brief A subscription for extension state
  *
@@ -542,6 +545,142 @@
 			       exten_state_sub->last_exten_state));
 }
 
+struct exten_state_pub_data {
+	/*! Publishers needing state update */
+	AST_VECTOR(name, struct exten_state_publisher *) pubs;
+	/*! Body generator state data */
+	struct ast_sip_exten_state_data exten_state_data;
+};
+
+static void exten_state_pub_data_destroy(struct exten_state_pub_data *doomed)
+{
+	if (!doomed) {
+		return;
+	}
+
+	ast_free((void *) doomed->exten_state_data.exten);
+	ast_free(doomed->exten_state_data.presence_subtype);
+	ast_free(doomed->exten_state_data.presence_message);
+	ao2_cleanup(doomed->exten_state_data.device_state_info);
+
+	AST_VECTOR_CALLBACK_VOID(&doomed->pubs, ao2_ref, -1);
+	AST_VECTOR_FREE(&doomed->pubs);
+
+	ast_free(doomed);
+}
+
+static struct exten_state_pub_data *exten_state_pub_data_alloc(const char *exten, struct ast_state_cb_info *info)
+{
+	struct exten_state_pub_data *pub_data;
+
+	pub_data = ast_calloc(1, sizeof(*pub_data));
+	if (!pub_data) {
+		return NULL;
+	}
+
+	if (AST_VECTOR_INIT(&pub_data->pubs, ao2_container_count(publishers))) {
+		exten_state_pub_data_destroy(pub_data);
+		return NULL;
+	}
+
+	/* Save off currently known information for the body generators. */
+	pub_data->exten_state_data.exten = ast_strdup(exten);
+	pub_data->exten_state_data.exten_state = info->exten_state;
+	pub_data->exten_state_data.presence_state = info->presence_state;
+	pub_data->exten_state_data.presence_subtype = ast_strdup(info->presence_subtype);
+	pub_data->exten_state_data.presence_message = ast_strdup(info->presence_message);
+	pub_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info);
+	if (!pub_data->exten_state_data.exten
+		|| !pub_data->exten_state_data.presence_subtype
+		|| !pub_data->exten_state_data.presence_message) {
+		exten_state_pub_data_destroy(pub_data);
+		return NULL;
+	}
+	return pub_data;
+}
+
+/*!
+ * \internal
+ * \brief Create exten state PUBLISH messages under PJSIP thread.
+ * \since 14.0.0
+ *
+ * \return 0
+ */
+static int exten_state_publisher_cb(void *data)
+{
+	struct exten_state_pub_data *pub_data = data;
+	struct exten_state_publisher *publisher;
+	size_t idx;
+	struct ast_str *body_text;
+	pj_pool_t *pool;
+	struct ast_sip_body_data gen_data = {
+		.body_type = AST_SIP_EXTEN_STATE_DATA,
+		.body_data = &pub_data->exten_state_data,
+	};
+	struct ast_sip_body body;
+
+	body_text = ast_str_create(64);
+	if (!body_text) {
+		exten_state_pub_data_destroy(pub_data);
+		return 0;
+	}
+
+	/* Need a PJSIP memory pool to generate the bodies. */
+	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "pub_state_body",
+		1024, 1024);
+	if (!pool) {
+		ast_log(LOG_WARNING, "Exten state publishing unable to create memory pool\n");
+		exten_state_pub_data_destroy(pub_data);
+		ast_free(body_text);
+		return 0;
+	}
+	pub_data->exten_state_data.pool = pool;
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&pub_data->pubs); ++idx) {
+		const char *uri;
+		int res;
+
+		publisher = AST_VECTOR_GET(&pub_data->pubs, idx);
+
+		uri = ast_sip_publish_client_get_from_uri(publisher->client);
+		if (ast_strlen_zero(uri)) {
+			ast_log(LOG_WARNING, "PUBLISH client '%s' has no from_uri or server_uri defined.\n",
+				publisher->name);
+			continue;
+		}
+		ast_copy_string(pub_data->exten_state_data.local, uri, sizeof(pub_data->exten_state_data.local));
+
+		uri = ast_sip_publish_client_get_to_uri(publisher->client);
+		if (ast_strlen_zero(uri)) {
+			ast_log(LOG_WARNING, "PUBLISH client '%s' has no to_uri or server_uri defined.\n",
+				publisher->name);
+			continue;
+		}
+		ast_copy_string(pub_data->exten_state_data.remote, uri, sizeof(pub_data->exten_state_data.remote));
+
+		res = ast_sip_pubsub_generate_body_content(publisher->body_type,
+			publisher->body_subtype, &gen_data, &body_text);
+		pj_pool_reset(pool);
+		if (res) {
+			ast_log(LOG_WARNING,
+				"PUBLISH client '%s' unable to generate %s/%s PUBLISH body.\n",
+				publisher->name, publisher->body_type, publisher->body_subtype);
+			continue;
+		}
+
+		body.type = publisher->body_type;
+		body.subtype = publisher->body_subtype;
+		body.body_text = ast_str_buffer(body_text);
+		ast_sip_publish_client_send(publisher->client, &body);
+	}
+
+	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+
+	ast_free(body_text);
+	exten_state_pub_data_destroy(pub_data);
+	return 0;
+}
+
 /*!
  * \brief Global extension state callback function
  */
@@ -549,16 +688,45 @@
 {
 	struct ao2_iterator publisher_iter;
 	struct exten_state_publisher *publisher;
+	struct exten_state_pub_data *pub_data = NULL;
 
+	ast_debug(5, "Exten state publisher: %s@%s Reason:%s State:%s Presence:%s Subtype:'%s' Message:'%s'\n",
+		exten, context,
+		info->reason == AST_HINT_UPDATE_DEVICE
+			? "Device"
+			: info->reason == AST_HINT_UPDATE_PRESENCE
+				? "Presence"
+				: "Unknown",
+		ast_extension_state2str(info->exten_state),
+		ast_presence_state2str(info->presence_state),
+		S_OR(info->presence_subtype, ""),
+		S_OR(info->presence_message, ""));
 	publisher_iter = ao2_iterator_init(publishers, 0);
 	for (; (publisher = ao2_iterator_next(&publisher_iter)); ao2_ref(publisher, -1)) {
 		if ((publisher->context_filter && regexec(&publisher->context_regex, context, 0, NULL, 0)) ||
 		    (publisher->exten_filter && regexec(&publisher->exten_regex, exten, 0, NULL, 0))) {
 			continue;
 		}
-		/* This is a placeholder for additional code to come */
+
+		if (!pub_data) {
+			pub_data = exten_state_pub_data_alloc(exten, info);
+			if (!pub_data) {
+				ao2_ref(publisher, -1);
+				break;
+			}
+		}
+
+		ao2_ref(publisher, +1);
+		AST_VECTOR_APPEND(&pub_data->pubs, publisher);
+		ast_debug(5, "'%s' will publish exten state\n", publisher->name);
 	}
 	ao2_iterator_destroy(&publisher_iter);
+
+	if (pub_data
+		&& ast_sip_push_task(publish_exten_state_serializer, exten_state_publisher_cb,
+			pub_data)) {
+		exten_state_pub_data_destroy(pub_data);
+	}
 
 	return 0;
 }
@@ -755,6 +923,10 @@
 	ast_sip_unregister_subscription_handler(&presence_handler);
 
 	ast_extension_state_del(0, exten_state_publisher_state_cb);
+
+	ast_taskprocessor_unreference(publish_exten_state_serializer);
+	publish_exten_state_serializer = NULL;
+
 	ao2_cleanup(publishers);
 	publishers = NULL;
 
@@ -777,6 +949,12 @@
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
+	publish_exten_state_serializer = ast_sip_create_serializer("pjsip/exten_state");
+	if (!publish_exten_state_serializer) {
+		unload_module();
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
 	if (ast_sip_register_subscription_handler(&presence_handler)) {
 		ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
 			presence_handler.event_name);
diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c
index 0fe2e3e..0265c42 100644
--- a/res/res_pjsip_outbound_publish.c
+++ b/res/res_pjsip_outbound_publish.c
@@ -425,6 +425,20 @@
 	return state->client;
 }
 
+const char *ast_sip_publish_client_get_from_uri(struct ast_sip_outbound_publish_client *client)
+{
+	struct ast_sip_outbound_publish *publish = client->publish;
+
+	return S_OR(publish->from_uri, S_OR(publish->server_uri, ""));
+}
+
+const char *ast_sip_publish_client_get_to_uri(struct ast_sip_outbound_publish_client *client)
+{
+	struct ast_sip_outbound_publish *publish = client->publish;
+
+	return S_OR(publish->to_uri, S_OR(publish->server_uri, ""));
+}
+
 int ast_sip_register_event_publisher_handler(struct ast_sip_event_publisher_handler *handler)
 {
 	struct ast_sip_event_publisher_handler *existing;

-- 
To view, visit https://gerrit.asterisk.org/2733
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic0dab4022f5cf59302129483ed38398764ee3cca
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Richard Mudgett <rmudgett at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matthew Fredrickson <creslin at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>



More information about the asterisk-code-review mailing list