[asterisk-commits] mmichelson: branch group/rls r416808 - /team/group/rls/res/res_pjsip_pubsub.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 20 10:33:28 CDT 2014


Author: mmichelson
Date: Fri Jun 20 10:33:19 2014
New Revision: 416808

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=416808
Log:
Add Resource List configuration handling.

ASTERISK-23866 #close
Review: https://reviewboard.asterisk.org/r/3648


Modified:
    team/group/rls/res/res_pjsip_pubsub.c

Modified: team/group/rls/res/res_pjsip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/team/group/rls/res/res_pjsip_pubsub.c?view=diff&rev=416808&r1=416807&r2=416808
==============================================================================
--- team/group/rls/res/res_pjsip_pubsub.c (original)
+++ team/group/rls/res/res_pjsip_pubsub.c Fri Jun 20 10:33:19 2014
@@ -72,6 +72,20 @@
                         </para>
 		</description>
 	</manager>
+	<manager name="PJSIPShowResourceLists" language="en_US">
+		<synopsis>
+			Displays settings for configured resource lists.
+		</synopsis>
+		<syntax />
+		<description>
+			<para>
+			Provides a listing of all resource lists.  An event <literal>ResourceListDetail</literal>
+			is issued for each resource list object.  Once all detail events are completed a
+			<literal>ResourceListDetailComplete</literal> event is issued.
+                        </para>
+		</description>
+	</manager>
+
 	<configInfo name="res_pjsip_pubsub" language="en_US">
 		<synopsis>Module that implements publish and subscribe support.</synopsis>
 		<configFile name="pjsip.conf">
@@ -108,6 +122,66 @@
 					<synopsis>The time at which the subscription expires</synopsis>
 				</configOption>
 			</configObject>
+			<configObject name="resource_list">
+				<synopsis>Resource list configuration parameters.</synopsis>
+				<configOption name="type">
+					<synopsis>Must be of type 'resource_list'</synopsis>
+				</configOption>
+				<configOption name="event">
+					<synopsis>The SIP event package that the list resource belong to.</synopsis>
+					<description><para>
+						The SIP event package describes the types of resources that Asterisk reports
+						the state of.
+					</para>
+						<enumlist>
+							<enum name="presence"><para>
+								Device state and presence reporting.
+							</para></enum>
+							<enum name="message-summary"><para>
+								Message-waiting indication (MWI) reporting.
+							</para></enum>
+						</enumlist>
+					</description>
+				</configOption>
+				<configOption name="list_item">
+					<synopsis>The name of a resource to report state on</synopsis>
+					<description>
+						<para>In general Asterisk looks up list items in the following way:</para>
+						<para>1. Check if the list item refers to another configured resource list.</para>
+						<para>2. Pass the name of the resource off to event-package-specific handlers
+						   to find the specified resource.</para>
+						<para>The second part means that the way the list item is specified depends
+						on what type of list this is. For instance, if you have the <replaceable>event</replaceable>
+						set to <literal>presence</literal>, then list items should be in the form of
+						dialplan_extension at dialplan_context. For <literal>message-summary</literal> mailbox
+						names should be listed.</para>
+					</description>
+				</configOption>
+				<configOption name="full_state" default="no">
+					<synopsis>Indicates if the entire list's state should be sent out.</synopsis>
+					<description>
+						<para>If this option is enabled, and a resource changes state, then Asterisk will construct
+						a notification that contains the state of all resources in the list. If the option is
+						disabled, Asterisk will construct a notification that only contains the states of
+						resources that have changed.</para>
+						<note>
+							<para>Even with this option disabled, there are certain situations where Asterisk is forced
+							to send a notification with the states of all resources in the list. When a subscriber
+							renews or terminates its subscription to the list, Asterisk MUST send a full state
+							notification.</para>
+						</note>
+					</description>
+				</configOption>
+				<configOption name="notification_batch_interval" default="0">
+					<synopsis>Time Asterisk should wait, in milliseconds, before sending notifications.</synopsis>
+					<description>
+						<para>When a resource's state changes, it may be desired to wait a certain amount before Asterisk
+						sends a notification to subscribers. This allows for other state changes to accumulate, so that
+						Asterisk can communicate multiple state changes in a single notification instead of rapidly sending
+						many notifications.</para>
+					</description>
+				</configOption>
+			</configObject>
 		</configFile>
 	</configInfo>
  ***/
@@ -194,6 +268,21 @@
 	 * an Expires header set to 0 and likely no body.
 	 */
 	SIP_PUBLISH_REMOVE,
+};
+
+/*!
+ * \brief Resource list configuration item
+ */
+struct resource_list {
+	SORCERY_OBJECT(details);
+	/*! SIP event package the list uses. */
+	char event[32];
+	/*! Strings representing resources in the list. */
+	AST_VECTOR(, const char *) items;
+	/*! Indicates if Asterisk sends full or partial state on notifications. */
+	unsigned int full_state;
+	/*! Time, in milliseconds Asterisk waits before sending a batched notification.*/
+	unsigned int notification_batch_interval;
 };
 
 /*!
@@ -1807,6 +1896,53 @@
 	return 0;
 }
 
+static int format_ami_resource_lists(void *obj, void *arg, int flags)
+{
+	struct resource_list *list = obj;
+	struct ast_sip_ami *ami = arg;
+	struct ast_str *buf;
+
+	buf = ast_sip_create_ami_event("ResourceListDetail", ami);
+	if (!buf) {
+		return CMP_STOP;
+	}
+
+	if (ast_sip_sorcery_object_to_ami(list, &buf)) {
+		ast_free(buf);
+		return CMP_STOP;
+	}
+	astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
+
+	ast_free(buf);
+	return 0;
+}
+
+static int ami_show_resource_lists(struct mansession *s, const struct message *m)
+{
+	struct ast_sip_ami ami = { .s = s, .m = m };
+	int num;
+	struct ao2_container *lists;
+
+	lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
+			AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+
+	if (!lists || !(num = ao2_container_count(lists))) {
+		astman_send_error(s, m, "No resource lists found\n");
+		return 0;
+	}
+
+	astman_send_listack(s, m, "A listing of resource lists follows, "
+			    "presented as ResourceListDetail events", "start");
+
+	ao2_callback(lists, OBJ_NODATA, format_ami_resource_lists, &ami);
+
+	astman_append(s,
+		      "Event: ResourceListDetailComplete\r\n"
+		      "EventList: Complete\r\n"
+		      "ListItems: %d\r\n\r\n", num);
+	return 0;
+}
+
 #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
 #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
 
@@ -1852,6 +1988,131 @@
 {
 	const struct subscription_persistence *persistence = obj;
 	return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
+}
+
+#define RESOURCE_LIST_INIT_SIZE 4
+
+static void resource_list_destructor(void *obj)
+{
+	struct resource_list *list = obj;
+	int i;
+
+	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
+		ast_free((char *) AST_VECTOR_GET(&list->items, i));
+	}
+
+	AST_VECTOR_FREE(&list->items);
+}
+
+static void *resource_list_alloc(const char *name)
+{
+	struct resource_list *list;
+
+	list = ast_sorcery_generic_alloc(sizeof(*list), resource_list_destructor);
+	if (!list) {
+		return NULL;
+	}
+
+	if (AST_VECTOR_INIT(&list->items, RESOURCE_LIST_INIT_SIZE)) {
+		ao2_cleanup(list);
+		return NULL;
+	}
+
+	return list;
+}
+
+static int item_in_vector(const struct resource_list *list, const char *item)
+{
+	int i;
+
+	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
+		if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int list_item_handler(const struct aco_option *opt,
+		struct ast_variable *var, void *obj)
+{
+	struct resource_list *list = obj;
+	char *items = ast_strdupa(var->value);
+	char *item;
+
+	while ((item = strsep(&items, ","))) {
+		if (item_in_vector(list, item)) {
+			ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
+			continue;
+		}
+		if (AST_VECTOR_APPEND(&list->items, ast_strdup(item))) {
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+	const struct resource_list *list = obj;
+	int i;
+	struct ast_str *str = ast_str_create(32);
+
+	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
+		ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
+	}
+
+	/* Chop off trailing comma */
+	ast_str_truncate(str, -1);
+	*buf = ast_strdup(ast_str_buffer(str));
+	ast_free(str);
+	return 0;
+}
+
+static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
+{
+	struct resource_list *list = obj;
+
+	if (ast_strlen_zero(list->event)) {
+		ast_log(LOG_WARNING, "Resource list '%s' has no event set\n",
+				ast_sorcery_object_get_id(list));
+		return -1;
+	}
+
+	if (AST_VECTOR_SIZE(&list->items) == 0) {
+		ast_log(LOG_WARNING, "Resource list '%s' has no list items\n",
+				ast_sorcery_object_get_id(list));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int apply_list_configuration(struct ast_sorcery *sorcery)
+{
+	ast_sorcery_apply_default(sorcery, "resource_list", "config",
+			"pjsip.conf,criteria=type=resource_list");
+	if (ast_sorcery_object_register(sorcery, "resource_list", resource_list_alloc,
+				NULL, resource_list_apply_handler)) {
+		return -1;
+	}
+
+	ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
+			OPT_NOOP_T, 0, 0);
+	ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
+			OPT_CHAR_ARRAY_T, 1, CHARFLDSET(struct resource_list, event));
+	ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "0",
+			OPT_BOOL_T, 0, FLDSET(struct resource_list, full_state));
+	ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
+			"0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
+	ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
+			"", list_item_handler, list_item_to_str, NULL, 0, 0);
+
+	ast_sorcery_reload_object(sorcery, "resource_list");
+
+	return 0;
 }
 
 static int load_module(void)
@@ -1910,6 +2171,11 @@
 	ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
 		persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0);
 
+	if (apply_list_configuration(sorcery)) {
+		ast_sip_unregister_service(&pubsub_module);
+		ast_sched_context_destroy(sched);
+	}
+
 	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
 		ast_sip_push_task(NULL, subscription_persistence_load, NULL);
 	} else {
@@ -1920,6 +2186,8 @@
 				 ami_show_subscriptions_inbound);
 	ast_manager_register_xml(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND, EVENT_FLAG_SYSTEM,
 				 ami_show_subscriptions_outbound);
+	ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
+			ami_show_resource_lists);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
@@ -1928,6 +2196,7 @@
 {
 	ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND);
 	ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND);
+	ast_manager_unregister("PJSIPShowResourceLists");
 
 	if (sched) {
 		ast_sched_context_destroy(sched);




More information about the asterisk-commits mailing list