[svn-commits] file: trunk r420315 - in /trunk: include/asterisk/ res/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Aug 7 09:37:31 CDT 2014


Author: file
Date: Thu Aug  7 09:37:26 2014
New Revision: 420315

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=420315
Log:
res_pjsip_publish_asterisk: Add support for exchanging device and mailbox state using SIP.

This module uses the inbound and outbound PUBLISH support to exchange device and mailbox
state between Asterisk instances. Each instance is configured to publish to the other and
requires no intermediary server. The functionality provided is similar to the XMPP and
Corosync support.

Review: https://reviewboard.asterisk.org/r/3780/

Added:
    trunk/res/res_pjsip_publish_asterisk.c
      - copied unchanged from r420313, team/file/pjsip-outbound-publish/res/res_pjsip_publish_asterisk.c
Modified:
    trunk/include/asterisk/res_pjsip_pubsub.h
    trunk/res/res_pjsip_pubsub.c
    trunk/res/res_pjsip_pubsub.exports.in

Modified: trunk/include/asterisk/res_pjsip_pubsub.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/res_pjsip_pubsub.h?view=diff&rev=420315&r1=420314&r2=420315
==============================================================================
--- trunk/include/asterisk/res_pjsip_pubsub.h (original)
+++ trunk/include/asterisk/res_pjsip_pubsub.h Thu Aug  7 09:37:26 2014
@@ -58,9 +58,10 @@
 	 *
 	 * \param endpoint The endpoint from whom the PUBLISH arrived.
 	 * \param resource The resource whose state is being published.
+	 * \param event_configuration The name of the event type configuration to use for this resource.
 	 * \return Response code for the incoming PUBLISH
 	 */
-	int (*new_publication)(struct ast_sip_endpoint *endpoint, const char *resource);
+	int (*new_publication)(struct ast_sip_endpoint *endpoint, const char *resource, const char *event_configuration);
 	/*!
 	 * \brief Called when a publication has reached its expiration.
 	 */
@@ -97,6 +98,22 @@
  * \retval non-NULL The associated endpoint
  */
 struct ast_sip_endpoint *ast_sip_publication_get_endpoint(struct ast_sip_publication *pub);
+
+/*!
+ * \brief Given a publication, get the resource the publication is to
+ *
+ * \param pub The publication
+ * \return The resource
+ */
+const char *ast_sip_publication_get_resource(const struct ast_sip_publication *pub);
+
+/*!
+ * \brief Given a publication, get the configuration name for the event type in use
+ *
+ * \param pub The publication
+ * \return The configuration name
+ */
+const char *ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub);
 
 /*!
  * \brief Register a publish handler

Modified: trunk/res/res_pjsip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_pjsip_pubsub.c?view=diff&rev=420315&r1=420314&r2=420315
==============================================================================
--- trunk/res/res_pjsip_pubsub.c (original)
+++ trunk/res/res_pjsip_pubsub.c Thu Aug  7 09:37:26 2014
@@ -108,6 +108,15 @@
 					<synopsis>The time at which the subscription expires</synopsis>
 				</configOption>
 			</configObject>
+			<configObject name="inbound-publication">
+				<synopsis>The configuration for inbound publications</synopsis>
+				<configOption name="endpoint" default="">
+					<synopsis>Optional name of an endpoint that is only allowed to publish to this resource</synopsis>
+				</configOption>
+				<configOption name="type">
+					<synopsis>Must be of type 'inbound-publication'.</synopsis>
+				</configOption>
+			</configObject>
 		</configFile>
 	</configInfo>
  ***/
@@ -217,6 +226,12 @@
 	int expires;
 	/*! \brief Scheduled item for expiration of publication */
 	int sched_id;
+	/*! \brief The resource the publication is to */
+	char *resource;
+	/*! \brief The name of the event type configuration */
+	char *event_configuration_name;
+	/*! \brief Data containing the above */
+	char data[0];
 };
 
 
@@ -330,6 +345,18 @@
 	char resource[0];
 };
 
+/*!
+ * \brief Structure representing a publication resource
+ */
+struct ast_sip_publication_resource {
+	/*! \brief Sorcery object details */
+	SORCERY_OBJECT(details);
+	/*! \brief Optional name of an endpoint that is only allowed to publish to this resource */
+	char *endpoint;
+	/*! \brief Mapping for event types to configuration */
+	struct ast_variable *events;
+};
+
 static const char *sip_subscription_roles_map[] = {
 	[AST_SIP_SUBSCRIBER] = "Subscriber",
 	[AST_SIP_NOTIFIER] = "Notifier"
@@ -348,6 +375,21 @@
 static pjsip_dialog *sip_subscription_get_dlg(const struct ast_sip_subscription *sub)
 {
 	return sub->reality.real.dlg;
+}
+
+/*! \brief Destructor for publication resource */
+static void publication_resource_destroy(void *obj)
+{
+	struct ast_sip_publication_resource *resource = obj;
+
+	ast_free(resource->endpoint);
+	ast_variables_destroy(resource->events);
+}
+
+/*! \brief Allocator for publication resource */
+static void *publication_resource_alloc(const char *name)
+{
+	return ast_sorcery_generic_alloc(sizeof(struct ast_sip_publication_resource), publication_resource_destroy);
 }
 
 /*! \brief Destructor for subscription persistence */
@@ -1105,7 +1147,7 @@
 
 void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
 {
-	ao2_callback(subscription->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
+	ao2_find(subscription->datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
 }
 
 int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
@@ -1454,14 +1496,17 @@
 	ao2_cleanup(publication->endpoint);
 }
 
-static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
+	const char *resource, const char *event_configuration_name)
 {
 	struct ast_sip_publication *publication;
 	pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
+	size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
+	char *dst;
 
 	ast_assert(endpoint != NULL);
 
-	if (!(publication = ao2_alloc(sizeof(*publication), publication_destroy_fn))) {
+	if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
 		return NULL;
 	}
 
@@ -1475,6 +1520,10 @@
 	publication->endpoint = endpoint;
 	publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
 	publication->sched_id = -1;
+	dst = publication->data;
+	publication->resource = strcpy(dst, resource);
+	dst += resource_len;
+	publication->event_configuration_name = strcpy(dst, event_configuration_name);
 
 	return publication;
 }
@@ -1521,8 +1570,10 @@
 	struct ast_sip_publish_handler *handler)
 {
 	struct ast_sip_publication *publication;
-	char *resource;
+	char *resource_name;
 	size_t resource_size;
+	RAII_VAR(struct ast_sip_publication_resource *, resource, NULL, ao2_cleanup);
+	struct ast_variable *event_configuration_name = NULL;
 	pjsip_uri *request_uri;
 	pjsip_sip_uri *request_uri_sip;
 	int resp;
@@ -1540,17 +1591,39 @@
 
 	request_uri_sip = pjsip_uri_get_uri(request_uri);
 	resource_size = pj_strlen(&request_uri_sip->user) + 1;
-	resource = alloca(resource_size);
-	ast_copy_pj_str(resource, &request_uri_sip->user, resource_size);
-
-	resp = handler->new_publication(endpoint, resource);
-
-	if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
+	resource_name = alloca(resource_size);
+	ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
+
+	resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
+	if (!resource) {
+		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
+		return NULL;
+	}
+
+	if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
+		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
+		return NULL;
+	}
+
+	for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
+		if (!strcmp(event_configuration_name->name, handler->event_name)) {
+			break;
+		}
+	}
+
+	if (!event_configuration_name) {
+		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
+		return NULL;
+	}
+
+	resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
+
+	if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
 		return NULL;
 	}
 
-	publication = sip_create_publication(endpoint, rdata);
+	publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
 
 	if (!publication) {
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
@@ -1574,7 +1647,9 @@
 {
 	RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
 
-	publication->handler->publish_expire(publication);
+	if (publication->handler->publish_expire) {
+		publication->handler->publish_expire(publication);
+	}
 
 	return 0;
 }
@@ -1603,7 +1678,7 @@
 	pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
 	enum sip_publish_type publish_type;
 	RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
-	int expires = 0, entity_id;
+	int expires = 0, entity_id, response = 0;
 
 	endpoint = ast_pjsip_rdata_get_endpoint(rdata);
 	ast_assert(endpoint != NULL);
@@ -1647,19 +1722,18 @@
 			publication = publish_request_initial(endpoint, rdata, handler);
 			break;
 		case SIP_PUBLISH_REFRESH:
-			sip_publication_respond(publication, 200, rdata);
 		case SIP_PUBLISH_MODIFY:
 			if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
 						AST_SIP_PUBLISH_STATE_ACTIVE)) {
 				/* If an error occurs we want to terminate the publication */
 				expires = 0;
 			}
-			sip_publication_respond(publication, 200, rdata);
+			response = 200;
 			break;
 		case SIP_PUBLISH_REMOVE:
 			handler->publication_state_change(publication, rdata->msg_info.msg->body,
 					AST_SIP_PUBLISH_STATE_TERMINATED);
-			sip_publication_respond(publication, 200, rdata);
+			response = 200;
 			break;
 		case SIP_PUBLISH_UNKNOWN:
 		default:
@@ -1678,6 +1752,10 @@
 		}
 	}
 
+	if (response) {
+		sip_publication_respond(publication, response, rdata);
+	}
+
 	return PJ_TRUE;
 }
 
@@ -1686,6 +1764,15 @@
 	return pub->endpoint;
 }
 
+const char *ast_sip_publication_get_resource(const struct ast_sip_publication *pub)
+{
+	return pub->resource;
+}
+
+const char *ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub)
+{
+	return pub->event_configuration_name;
+}
 
 int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
 {
@@ -2045,6 +2132,40 @@
 {
 	const struct subscription_persistence *persistence = obj;
 	return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
+}
+
+static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct ast_sip_publication_resource *resource = obj;
+
+	ast_free(resource->endpoint);
+	resource->endpoint = ast_strdup(var->value);
+
+	return 0;
+}
+
+static int resource_event_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct ast_sip_publication_resource *resource = obj;
+	/* The event configuration name starts with 'event_' so skip past it to get the real name */
+	const char *event = var->name + 6;
+	struct ast_variable *item;
+
+	if (ast_strlen_zero(event) || ast_strlen_zero(var->value)) {
+		return -1;
+	}
+
+	item = ast_variable_new(event, var->value, "");
+	if (!item) {
+		return -1;
+	}
+
+	if (resource->events) {
+		item->next = resource->events;
+	}
+	resource->events = item;
+
+	return 0;
 }
 
 static int load_module(void)
@@ -2103,6 +2224,20 @@
 	ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
 		persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0);
 
+	ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
+	if (ast_sorcery_object_register(sorcery, "inbound-publication", publication_resource_alloc,
+		NULL, NULL)) {
+		ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
+		ast_sip_unregister_service(&pubsub_module);
+		ast_sched_context_destroy(sched);
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0);
+	ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "",
+		resource_endpoint_handler, NULL, NULL, 0, 0);
+	ast_sorcery_object_fields_register(sorcery, "inbound-publication", "^event_", resource_event_handler, NULL);
+	ast_sorcery_reload_object(sorcery, "inbound-publication");
+
 	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
 		ast_sip_push_task(NULL, subscription_persistence_load, NULL);
 	} else {

Modified: trunk/res/res_pjsip_pubsub.exports.in
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_pjsip_pubsub.exports.in?view=diff&rev=420315&r1=420314&r2=420315
==============================================================================
--- trunk/res/res_pjsip_pubsub.exports.in (original)
+++ trunk/res/res_pjsip_pubsub.exports.in Thu Aug  7 09:37:26 2014
@@ -15,6 +15,8 @@
 		LINKER_SYMBOL_PREFIXast_sip_unregister_subscription_handler;
 		LINKER_SYMBOL_PREFIXast_sip_create_publication;
 		LINKER_SYMBOL_PREFIXast_sip_publication_get_endpoint;
+		LINKER_SYMBOL_PREFIXast_sip_publication_get_resource;
+		LINKER_SYMBOL_PREFIXast_sip_publication_get_event_configuration;
 		LINKER_SYMBOL_PREFIXast_sip_publication_create_response;
 		LINKER_SYMBOL_PREFIXast_sip_publication_send_response;
 		LINKER_SYMBOL_PREFIXast_sip_register_publish_handler;




More information about the svn-commits mailing list