[svn-commits] mmichelson: branch mmichelson/rls-subscribe r417444 - /team/mmichelson/rls-su...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Jun 26 15:59:23 CDT 2014


Author: mmichelson
Date: Thu Jun 26 15:59:15 2014
New Revision: 417444

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=417444
Log:
Tentative handling of inbound subscriptions.

This is only tentative due to a few things

1) There is no handling of known edge cases, like
list loops or duplicated resource names.
2) Persistent subscriptions do not rebuild the
entire subscription tree.

Also unhandled at this point are calls to subscription
handlers for cases such as resubscribing, subscription
termination, etc.


Modified:
    team/mmichelson/rls-subscribe/res/res_pjsip_pubsub.c

Modified: team/mmichelson/rls-subscribe/res/res_pjsip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/rls-subscribe/res/res_pjsip_pubsub.c?view=diff&rev=417444&r1=417443&r2=417444
==============================================================================
--- team/mmichelson/rls-subscribe/res/res_pjsip_pubsub.c (original)
+++ team/mmichelson/rls-subscribe/res/res_pjsip_pubsub.c Thu Jun 26 15:59:15 2014
@@ -431,12 +431,20 @@
 
 static pjsip_evsub *sip_subscription_get_evsub(const struct ast_sip_subscription *sub)
 {
-	return sub->reality.real.evsub;
+	if (sub->type == SIP_SUBSCRIPTION_VIRTUAL) {
+		return sip_subscription_get_evsub(sub->reality.virtual.parent);
+	} else {
+		return sub->reality.real.evsub;
+	}
 }
 
 static pjsip_dialog *sip_subscription_get_dlg(const struct ast_sip_subscription *sub)
 {
-	return sub->reality.real.dlg;
+	if (sub->type == SIP_SUBSCRIPTION_VIRTUAL) {
+		return sip_subscription_get_dlg(sub->reality.virtual.parent);
+	} else {
+		return sub->reality.real.dlg;
+	}
 }
 
 /*! \brief Destructor for subscription persistence */
@@ -654,6 +662,10 @@
 	ast_sip_mod_data_set(rdata.tp_info.pool, rdata.endpt_info.mod_data,
 			pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
 
+	/* XXX This section needs to use the same bit of logic as is used when
+	 * processing a new inbound subscription so that a subscription tree
+	 * is created
+	 */
 	resp = handler->notifier->new_subscribe(endpoint, resource);
 	if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 		sub = notifier_create_subscription(handler, endpoint, &rdata, resource, generator);
@@ -869,7 +881,8 @@
 };
 
 static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_subscription_handler *handler,
-		struct ast_sip_endpoint *endpoint, const char *resource, enum ast_sip_subscription_role role)
+		struct ast_sip_endpoint *endpoint, const char *resource, enum ast_sip_subscription_role role,
+		enum sip_subscription_type type)
 {
 	struct ast_sip_subscription *sub;
 
@@ -890,7 +903,7 @@
 		return NULL;
 	}
 	sub->role = role;
-	sub->type = SIP_SUBSCRIPTION_REAL;
+	sub->type = type;
 	sub->endpoint = ao2_bump(endpoint);
 	sub->handler = handler;
 
@@ -916,7 +929,7 @@
 	pjsip_dialog *dlg;
 	struct subscription_persistence *persistence;
 
-	sub = allocate_subscription(handler, endpoint, resource, AST_SIP_NOTIFIER);
+	sub = allocate_subscription(handler, endpoint, resource, AST_SIP_NOTIFIER, SIP_SUBSCRIPTION_REAL);
 	if (!sub) {
 		return NULL;
 	}
@@ -972,7 +985,7 @@
 	pjsip_tx_data *tdata;
 	pjsip_evsub *evsub;
 
-	sub = allocate_subscription(handler, endpoint, resource, AST_SIP_SUBSCRIBER);
+	sub = allocate_subscription(handler, endpoint, resource, AST_SIP_SUBSCRIBER, SIP_SUBSCRIPTION_REAL);
 	if (!sub) {
 		return NULL;
 	}
@@ -1399,6 +1412,141 @@
 	return generator;
 }
 
+struct tree_node {
+	AST_VECTOR(, struct tree_node *) children;
+	char resource[0];
+};
+
+static struct resource_list *retrieve_resource_list(const char *resource)
+{
+	return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
+}
+
+static struct tree_node *tree_node_alloc(const char *resource)
+{
+	struct tree_node *node;
+
+	node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
+	if (!node) {
+		return NULL;
+	}
+
+	strcpy(node->resource, resource);
+	AST_VECTOR_INIT(&node->children, 4);
+	return node;
+}
+
+static void tree_node_destroy(struct tree_node *node)
+{
+	int i;
+
+	for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
+		tree_node_destroy(AST_VECTOR_GET(&node->children, i));
+	}
+	AST_VECTOR_FREE(&node->children);
+	ast_free(node);
+}
+
+static void recurse_list(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
+		struct resource_list *list, struct tree_node *parent)
+{
+	int i;
+
+	for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
+		struct tree_node *current;
+		struct resource_list *child_list;
+		const char *resource = AST_VECTOR_GET(&list->items, i);
+
+		child_list = retrieve_resource_list(resource);
+		if (!child_list) {
+			int resp = handler->notifier->new_subscribe(endpoint, resource);
+			if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
+				current = tree_node_alloc(resource);
+				AST_VECTOR_APPEND(&parent->children, current);
+			}
+		} else {
+			current = tree_node_alloc(resource);
+			recurse_list(endpoint, handler, child_list, current);
+			if (AST_VECTOR_SIZE(&current->children) > 0) {
+				AST_VECTOR_APPEND(&parent->children, current);
+			} else {
+				tree_node_destroy(current);
+			}
+		}
+	}
+}
+
+struct resource_tree {
+	struct tree_node *root;
+	int single_resource;
+};
+
+static void resource_tree_destroy(struct resource_tree *tree)
+{
+	tree_node_destroy(tree->root);
+}
+
+static int build_subscription_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
+		const char *resource, struct resource_tree *tree)
+{
+	struct resource_list *list;
+
+	/* Simple shortcut in case the requested resource is not a list */
+	list = retrieve_resource_list(resource);
+	if (!list) {
+		tree->single_resource = 1;
+		return handler->notifier->new_subscribe(endpoint, resource);
+	}
+
+	/* XXX This initial effort is a naive approach that assumes there are
+	 * no loops in the lists and no duplicated resources. This will have
+	 * to be addressed later
+	 */
+	tree->root = tree_node_alloc(resource);
+	recurse_list(endpoint, handler, list, tree->root);
+
+	if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
+		return 200;
+	} else {
+		return 500;
+	}
+}
+
+static void create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler,
+		struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
+		struct ast_sip_pubsub_body_generator *generator, struct ast_sip_subscription *parent,
+		struct tree_node *parent_resource)
+{
+	int i;
+
+	for (i = 0; i < AST_VECTOR_SIZE(&parent_resource->children); ++i) {
+		struct ast_sip_subscription *sub;
+		
+		sub = allocate_subscription(handler, endpoint, resource,
+				AST_SIP_NOTIFIER, SIP_SUBSCRIPTION_VIRTUAL);
+		sub->body_generator = generator;
+		sub->reality.virtual.parent = parent;
+
+		create_virtual_subscriptions(handler, endpoint, rdata, resource,
+				generator, sub, AST_VECTOR_GET(&parent_resource->children, i));
+	}
+}
+
+static struct ast_sip_subscription *create_subscription_tree(const struct ast_sip_subscription_handler *handler,
+		struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
+		struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree)
+{
+	struct ast_sip_subscription *sub;
+	
+	/* Start by creating the root subscription. It's the only real subscription. */
+	sub = notifier_create_subscription(handler, endpoint, rdata, resource, generator);
+
+	/* Now we need to create virtual subscriptions */
+	create_virtual_subscriptions(handler, endpoint, rdata, resource, generator, sub, tree->root);
+
+	return sub;
+}
+
 static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
 {
 	pjsip_expires_hdr *expires_header;
@@ -1411,6 +1559,7 @@
 	pjsip_sip_uri *request_uri_sip;
 	size_t resource_size;
 	int resp;
+	struct resource_tree tree;
 
 	endpoint = ast_pjsip_rdata_get_endpoint(rdata);
 	ast_assert(endpoint != NULL);
@@ -1466,24 +1615,31 @@
 		return PJ_TRUE;
 	}
 
-	resp = handler->notifier->new_subscribe(endpoint, resource);
+	memset(&tree, 0, sizeof(tree));
+	resp = build_subscription_tree(endpoint, handler, resource, &tree);
 	if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
+		resource_tree_destroy(&tree);
 		return PJ_TRUE;
 	}
 
-	sub = notifier_create_subscription(handler, endpoint, rdata, resource, generator);
-	if (!sub) {
-		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+	if (tree.single_resource) {
+		sub = notifier_create_subscription(handler, endpoint, rdata, resource, generator);
+		if (!sub) {
+			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
+		} else {
+			sub->persistence = subscription_persistence_create(sub);
+			subscription_persistence_update(sub, rdata);
+			sip_subscription_accept(sub, rdata, resp);
+			if (handler->notifier->notify_required(sub, AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED)) {
+				pjsip_evsub_terminate(sip_subscription_get_evsub(sub), PJ_TRUE);
+			}
+		}
 	} else {
-		sub->persistence = subscription_persistence_create(sub);
-		subscription_persistence_update(sub, rdata);
-		sip_subscription_accept(sub, rdata, resp);
-		if (handler->notifier->notify_required(sub, AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED)) {
-			pjsip_evsub_terminate(sip_subscription_get_evsub(sub), PJ_TRUE);
-		}
-	}
-
+		sub = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree);
+	}
+
+	resource_tree_destroy(&tree);
 	return PJ_TRUE;
 }
 




More information about the svn-commits mailing list