[svn-commits] mmichelson: branch mmichelson/pubsub_bodies r405642 - in /team/mmichelson/pub...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Jan 15 17:52:12 CST 2014


Author: mmichelson
Date: Wed Jan 15 17:52:06 2014
New Revision: 405642

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=405642
Log:
Introduce the concept of body generators for pubsub purposes.

One common task taken by contributors to Asterisk is to add propietary
add-ons to established code. With res_pjsip, the idea is to be able
to put as much as possible into its own module, without the need to
clutter any of the Asterisk core in the process. For a lot of needs,
this is quite possible.

However, modifying the body of SIP NOTIFY and PUBLISH requests to
include supplementary data is not a simple task. It's possible to
add an ast_sip_supplement so that you can be called into before the
request is sent out, but you won't have access to the data that actually
caused the NOTIFY or PUBLISH to be sent in the first place. Even if
you could get access to the data, the body will have been constructed
already and be in string format, which may not be ideal depending
on the format of the body.

This commit introduces body generators. Body generators are used as
a way to generate bodies based on modules that have registered themselves
to indicate that they wish to contribute to certain body types. Primary
body generators are responsible for creating the "core" body, usually
as defined by some standards body. Supplementary body generators are
responsible for editing and augmenting the body as it currently exists
in order to add nonstandard content.

This commit changes res_pjsip_mwi.c to use a body generator mostly as
a proof of concept. Body generators will get much more mileage in
res_pjsip_exten_state.c.

Future updates will include:
 * Added locking to body generator list in res_pjsip_pubsub.c.
 * Checks in res_pjsip_pubsub.c that a primary body generator exists
   before accepting an incoming SUBSCRIBE request.
 * Addition of body generators to res_pjsip_exten_state.c
 * Separation of body generators from subscription handlers. This will
   allow easy replacement of primary body generators in case someone
   wishes to do so.


Modified:
    team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_pubsub.h
    team/mmichelson/pubsub_bodies/res/res_pjsip_mwi.c
    team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.c
    team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.exports.in

Modified: team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_pubsub.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_pubsub.h?view=diff&rev=405642&r1=405641&r2=405642
==============================================================================
--- team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_pubsub.h (original)
+++ team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_pubsub.h Wed Jan 15 17:52:06 2014
@@ -537,4 +537,108 @@
  */
 void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler);
 
+/*!
+ * The types of body generators
+ */
+enum ast_sip_pubsub_body_generator_type {
+	/*!
+	 * \brief Primary body generator
+	 *
+	 * A primary body generator is expected to follow whichever
+	 * RFC or RFCs define the behavior for a given event package
+	 * and a given body type. A primary body generator is required
+	 * in order to create NOTIFY or PUBLISH requests. Only one
+	 * primary body generator of a given type is permitted.
+	 */
+	AST_SIP_PUBSUB_BODY_GENERATOR_PRIMARY,
+	/*!
+	 * \brief Supplementary body generator
+	 *
+	 * A supplementary body generator adds onto the body created
+	 * by the primary body generator. Supplementary body generators
+	 * are typically used to provide proprietary or other nonstandard
+	 * information in a body. There is no limit on the number of
+	 * supplementary body generators allowed for a given type.
+	 */
+	AST_SIP_PUBSUB_BODY_GENERATOR_SUPPLEMENTARY,
+};
+
+/*!
+ * \brief Pubsub body generator
+ *
+ * A body generator is responsible for taking Asterisk content
+ * and converting it into a body format to be placed in an outbound
+ * SIP NOTIFY or PUBLISH request.
+ */
+struct ast_sip_pubsub_body_generator {
+	/*!
+	 * \brief Content type
+	 * In "plain/text", "plain" is the type
+	 */
+	const char *type;
+	/*!
+	 * \brief Content subtype
+	 * In "plain/text", "text" is the subtype
+	 */
+	const char *subtype;
+	/*!
+	 * Type of body generator this is
+	 */
+	enum ast_sip_pubsub_body_generator_type generator_type;
+	/*!
+	 * \brief Add content to the body of a SIP request
+	 *
+	 * The body of the request has already been allocated. Primary body
+	 * generators will be given an empty body and will populate it with the
+	 * initial set of data. Supplementary body generators will then be given
+	 * the generated body to edit or augment as desired.
+	 *
+	 * \param body The body of the SIP request. The type is determined by the
+	 * content type.
+	 * \param data The subscription data used to populate the body. The type is
+	 * determined by the content type.
+	 */
+	int (*generate_body_content)(void *body, void *data);
+	AST_LIST_ENTRY(ast_sip_pubsub_body_generator) list;
+};
+
+/*!
+ * \since 13.0.0
+ * \brief Generate body content for a PUBLISH or NOTIFY
+ *
+ * This function takes a pre-allocated body and calls into registered body
+ * generators in order to fill in the body with appropriate details.
+ * The primary body generator will be called first, followed by the
+ * supplementary body generators
+ *
+ * \param content_type The content type of the body
+ * \param content_subtype The content subtype of the body
+ * \param body The pre-allocated body.
+ * \param data The data associated with body generation.
+ */
+int ast_sip_pubsub_generate_body_content(char *content_type, char *content_subtype,
+		void *body, void *data);
+
+/*!
+ * \since 13.0.0
+ * \brief Register a body generator with the pubsub core.
+ *
+ * This may fail if an attempt is made to register a primary body supplement
+ * for a given content type if a primary body supplement for that content type
+ * has already been registered.
+ * 
+ * \param generator Body generator to register
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator);
+
+/*!
+ * \since 13.0.0
+ * \brief Unregister a body generator with the pubsub core.
+ *
+ * \param generator Body generator to unregister
+ */
+void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator);
+
 #endif /* RES_PJSIP_PUBSUB_H */

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_mwi.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_mwi.c?view=diff&rev=405642&r1=405641&r2=405642
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_mwi.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_mwi.c Wed Jan 15 17:52:06 2014
@@ -43,6 +43,10 @@
 
 #define STASIS_BUCKETS 13
 #define MWI_BUCKETS 53
+
+#define MWI_TYPE "application"
+#define MWI_SUBTYPE "simple-message-summary"
+
 static void mwi_subscription_shutdown(struct ast_sip_subscription *sub);
 static struct ast_sip_subscription *mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
 		pjsip_rx_data *rdata);
@@ -58,7 +62,7 @@
 
 static struct ast_sip_subscription_handler mwi_handler = {
 	.event_name = "message-summary",
-	.accept = { "application/simple-message-summary", },
+	.accept = { MWI_TYPE"/"MWI_SUBTYPE, },
 	.handles_default_accept = 1,
 	.subscription_shutdown = mwi_subscription_shutdown,
 	.new_subscribe = mwi_new_subscribe,
@@ -69,6 +73,15 @@
 	.notify_request = mwi_notify_request,
 	.refresh_subscription = mwi_refresh_subscription,
 	.to_ami = mwi_to_ami,
+};
+
+static int mwi_generate_body_content(void *body, void *data);
+
+static struct ast_sip_pubsub_body_generator mwi_generator = {
+	.type = MWI_TYPE,
+	.subtype = MWI_SUBTYPE,
+	.generator_type = AST_SIP_PUBSUB_BODY_GENERATOR_PRIMARY,
+	.generate_body_content = mwi_generate_body_content,
 };
 
 /*!
@@ -363,12 +376,23 @@
 	}
 }
 
+static int mwi_generate_body_content(void *body, void *data)
+{
+	struct ast_str **body_str = body;
+	struct message_accumulator *counter = data;
+
+	ast_str_append(body_str, 0, "Messages-Waiting: %s\r\n", counter->new_msgs ? "yes" : "no");
+	ast_str_append(body_str, 0, "Voice-Message: %d/%d (0/0)\r\n", counter->new_msgs, counter->old_msgs);
+
+	return 0;
+}
+
 static void send_mwi_notify(struct mwi_subscription *sub, pjsip_evsub_state state, const char *reason)
 {
 	const pj_str_t *reason_str_ptr = NULL;
 	static pjsip_media_type mwi_type = {
-		.type = { "application", 11 },
-		.subtype = { "simple-message-summary", 22 },
+		.type = { MWI_TYPE, sizeof(MWI_TYPE) - 1 },
+		.subtype = { MWI_SUBTYPE, sizeof(MWI_SUBTYPE) - 1 },
 	};
 	struct message_accumulator counter = {
 		.old_msgs = 0,
@@ -385,8 +409,7 @@
 		pj_cstr(&reason_str, reason);
 		reason_str_ptr = &reason_str;
 	}
-	ast_str_append(&body, 0, "Messages-Waiting: %s\r\n", counter.new_msgs ? "yes" : "no");
-	ast_str_append(&body, 0, "Voice-Message: %d/%d (0/0)\r\n", counter.new_msgs, counter.old_msgs);
+	ast_sip_pubsub_generate_body_content(MWI_TYPE, MWI_SUBTYPE, &body, &counter);
 	pj_cstr(&pj_body, ast_str_buffer(body));
 
 	ast_debug(5, "Sending  %s MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n",
@@ -736,6 +759,10 @@
 	if (ast_sip_register_subscription_handler(&mwi_handler)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
+	if (ast_sip_pubsub_register_body_generator(&mwi_generator)) {
+		ast_sip_unregister_subscription_handler(&mwi_handler);
+		return AST_MODULE_LOAD_DECLINE;
+	}
 	create_mwi_subscriptions();
 	return AST_MODULE_LOAD_SUCCESS;
 }
@@ -748,6 +775,7 @@
 		ao2_global_obj_release(unsolicited_mwi);
 	}
 	ast_sip_unregister_subscription_handler(&mwi_handler);
+	ast_sip_pubsub_unregister_body_generator(&mwi_generator);
 	return 0;
 }
 

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.c?view=diff&rev=405642&r1=405641&r2=405642
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.c Wed Jan 15 17:52:06 2014
@@ -796,6 +796,7 @@
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
 		return PJ_TRUE;
 	}
+	/* XXX Add code here to check for presence of body generators */
 	sub = handler->new_subscribe(endpoint, rdata);
 	if (!sub) {
 		pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
@@ -1063,6 +1064,68 @@
 	return pjsip_tsx_send_msg(tsx, tdata);
 }
 
+AST_LIST_HEAD_STATIC(body_generators, ast_sip_pubsub_body_generator);
+
+int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
+{
+	struct ast_sip_pubsub_body_generator *iter;
+
+	if (generator->generator_type == AST_SIP_PUBSUB_BODY_GENERATOR_SUPPLEMENTARY) {
+		AST_LIST_INSERT_TAIL(&body_generators, generator, list);
+		return 0;
+	}
+
+	/* Primary body generators have to be checked in case they clash with a registered
+	 * body primary body generator.
+	 */
+	AST_LIST_TRAVERSE(&body_generators, iter, list) {
+		if (iter->generator_type == AST_SIP_PUBSUB_BODY_GENERATOR_SUPPLEMENTARY) {
+			continue;
+		}
+		if (!strcmp(iter->type, generator->type) &&
+				!strcmp(iter->subtype, generator->subtype)) {
+			ast_log(LOG_WARNING, "Cannot register primary body generator of %s/%s."
+					"One is already registered.\n", generator->type, generator->subtype);
+			return -1;
+		}
+	}
+
+	AST_LIST_INSERT_HEAD(&body_generators, generator, list);
+	return 0;
+}
+
+void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
+{
+	struct ast_sip_pubsub_body_generator *iter;
+
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&body_generators, iter, list) {
+		if (iter == generator) {
+			AST_LIST_REMOVE_CURRENT(list);
+			break;
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END;
+}
+
+int ast_sip_pubsub_generate_body_content(char *content_type, char *content_subtype,
+		void *body, void *data)
+{
+	struct ast_sip_pubsub_body_generator *iter;
+	int res = -1;
+
+	AST_LIST_TRAVERSE(&body_generators, iter, list) {
+		if (!strcmp(content_type, iter->type) &&
+				!strcmp(content_subtype, iter->subtype)) {
+			res = iter->generate_body_content(body, data);
+			if (res) {
+				break;
+			}
+		}
+	}
+
+	return res;
+}
+
 static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
 {
 	if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.exports.in?view=diff&rev=405642&r1=405641&r2=405642
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.exports.in (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_pubsub.exports.in Wed Jan 15 17:52:06 2014
@@ -21,6 +21,10 @@
 		LINKER_SYMBOL_PREFIXast_sip_publication_add_datastore;
 		LINKER_SYMBOL_PREFIXast_sip_publication_get_datastore;
 		LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore;
+		LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore;
+		LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_generator;
+		LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_generator;
+		LINKER_SYMBOL_PREFIXast_sip_pubsub_generate_body_content;
 	local:
 		*;
 };




More information about the svn-commits mailing list