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

Richard Mudgett asteriskteam at digium.com
Thu Apr 28 17:26:31 CDT 2016


Richard Mudgett has uploaded a new change for review.

  https://gerrit.asterisk.org/2733

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

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, 212 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/33/2733/1

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 e84a25c..dfde940 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,139 @@
 			       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;
+	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;
+	}
+
+	for (idx = 0; idx < AST_VECTOR_SIZE(&pub_data->pubs); ++idx) {
+		pj_pool_t *pool;
+		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));
+
+		/* Need a PJSIP memory pool to generate each body. */
+		pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "pub_state_body",
+			1024, 1024);
+		if (!pool) {
+			ast_log(LOG_WARNING, "PUBLISH client '%s' unable to create memory pool\n",
+				publisher->name);
+			break;
+		}
+
+		pub_data->exten_state_data.pool = pool;
+		res = ast_sip_pubsub_generate_body_content(publisher->body_type,
+			publisher->body_subtype, &gen_data, &body_text);
+		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), 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);
+	}
+
+	ast_free(body_text);
+	exten_state_pub_data_destroy(pub_data);
+	return 0;
+}
+
 /*!
  * \brief Global extension state callback function
  */
@@ -549,16 +685,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 +920,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 +946,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 5b27bdf..6a39dbb 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: newchange
Gerrit-Change-Id: Ic0dab4022f5cf59302129483ed38398764ee3cca
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Richard Mudgett <rmudgett at digium.com>



More information about the asterisk-code-review mailing list