[asterisk-commits] kharwell: branch kharwell/gulp_notify r391775 - in /team/kharwell/gulp_notify...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 14 10:47:17 CDT 2013


Author: kharwell
Date: Fri Jun 14 10:47:15 2013
New Revision: 391775

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=391775
Log:
adding notify support

Added:
    team/kharwell/gulp_notify/res/res_sip_notify.c   (with props)
Modified:
    team/kharwell/gulp_notify/include/asterisk/res_sip.h
    team/kharwell/gulp_notify/res/res_sip.exports.in
    team/kharwell/gulp_notify/res/res_sip/include/res_sip_private.h
    team/kharwell/gulp_notify/res/res_sip/sip_configuration.c
    team/kharwell/gulp_notify/res/res_sip/sip_options.c

Modified: team/kharwell/gulp_notify/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/include/asterisk/res_sip.h?view=diff&rev=391775&r1=391774&r2=391775
==============================================================================
--- team/kharwell/gulp_notify/include/asterisk/res_sip.h (original)
+++ team/kharwell/gulp_notify/include/asterisk/res_sip.h Fri Jun 14 10:47:15 2013
@@ -1060,6 +1060,13 @@
 struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata);
 
 /*!
+ * \brief Get the current defined endpoints
+ *
+ * \retval The current endpoints loaded by res_sip
+ */
+struct ao2_container *ast_sip_get_endpoints(void);
+
+/*!
  * \brief Retrieve relevant SIP auth structures from sorcery
  *
  * \param auth_names The sorcery IDs of auths to retrieve

Modified: team/kharwell/gulp_notify/res/res_sip.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/res/res_sip.exports.in?view=diff&rev=391775&r1=391774&r2=391775
==============================================================================
--- team/kharwell/gulp_notify/res/res_sip.exports.in (original)
+++ team/kharwell/gulp_notify/res/res_sip.exports.in Fri Jun 14 10:47:15 2013
@@ -29,6 +29,7 @@
 		LINKER_SYMBOL_PREFIXast_sip_append_body;
 		LINKER_SYMBOL_PREFIXast_sip_get_pjsip_endpoint;
 		LINKER_SYMBOL_PREFIXast_sip_endpoint_alloc;
+		LINKER_SYMBOL_PREFIXast_sip_get_endpoints;
 		LINKER_SYMBOL_PREFIXast_copy_pj_str;
 		LINKER_SYMBOL_PREFIXast_sip_get_sorcery;
 		LINKER_SYMBOL_PREFIXast_sip_create_dialog;

Modified: team/kharwell/gulp_notify/res/res_sip/include/res_sip_private.h
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/res/res_sip/include/res_sip_private.h?view=diff&rev=391775&r1=391774&r2=391775
==============================================================================
--- team/kharwell/gulp_notify/res/res_sip/include/res_sip_private.h (original)
+++ team/kharwell/gulp_notify/res/res_sip/include/res_sip_private.h Fri Jun 14 10:47:15 2013
@@ -47,11 +47,4 @@
  */
 int ast_sip_initialize_outbound_authentication(void);
 
-/*!
- * \brief Get the current defined endpoints
- *
- * \retval The current endpoints loaded by res_sip
- */
-struct ao2_container *ast_res_sip_get_endpoints(void);
-
 #endif /* RES_SIP_PRIVATE_H_ */

Modified: team/kharwell/gulp_notify/res/res_sip/sip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/res/res_sip/sip_configuration.c?view=diff&rev=391775&r1=391774&r2=391775
==============================================================================
--- team/kharwell/gulp_notify/res/res_sip/sip_configuration.c (original)
+++ team/kharwell/gulp_notify/res/res_sip/sip_configuration.c Fri Jun 14 10:47:15 2013
@@ -37,7 +37,7 @@
 		return NULL;
 	}
 
-	endpoints = ast_res_sip_get_endpoints();
+	endpoints = ast_sip_get_endpoints();
 	if (!endpoints) {
 		return CLI_FAILURE;
 	}
@@ -424,7 +424,7 @@
 	return endpoint;
 }
 
-struct ao2_container *ast_res_sip_get_endpoints(void)
+struct ao2_container *ast_sip_get_endpoints(void)
 {
 	struct ao2_container *endpoints;
 
@@ -460,4 +460,3 @@
 {
 	return sip_sorcery;
 }
-

Modified: team/kharwell/gulp_notify/res/res_sip/sip_options.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/res/res_sip/sip_options.c?view=diff&rev=391775&r1=391774&r2=391775
==============================================================================
--- team/kharwell/gulp_notify/res/res_sip/sip_options.c (original)
+++ team/kharwell/gulp_notify/res/res_sip/sip_options.c Fri Jun 14 10:47:15 2013
@@ -259,7 +259,7 @@
 	struct qualify_info *info;
 	char *endpoint_id;
 
-	endpoints = ast_res_sip_get_endpoints();
+	endpoints = ast_sip_get_endpoints();
 	if (!endpoints) {
 		return;
 	}

Added: team/kharwell/gulp_notify/res/res_sip_notify.c
URL: http://svnview.digium.com/svn/asterisk/team/kharwell/gulp_notify/res/res_sip_notify.c?view=auto&rev=391775
==============================================================================
--- team/kharwell/gulp_notify/res/res_sip_notify.c (added)
+++ team/kharwell/gulp_notify/res/res_sip_notify.c Fri Jun 14 10:47:15 2013
@@ -1,0 +1,504 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Kevin Harwell <kharwell at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+	<depend>res_sip</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include "pjsua-lib/pjsua.h"
+
+#include "asterisk/cli.h"
+#include "asterisk/config.h"
+#include "asterisk/manager.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/res_sip.h"
+#include "asterisk/sorcery.h"
+
+#define CONTENT_TYPE_SIZE 64
+#define CONTENT_SIZE 512
+
+/*!
+ * \internal
+ * \brief The configuration file containing NOTIFY payload types to send.
+ */
+static const char notify_config[] = "sip_notify.conf";
+
+/*!
+ * \internal
+ * \brief A list of configured NOTIFY payload types to send.
+ */
+static struct ast_config *notify_types = NULL;
+
+/*!
+ * \internal
+ * \brief Structure to hold task data for notifications.
+ */
+struct notify_data {
+	/*! The endpoint being notified */
+	struct ast_sip_endpoint *endpoint;
+	/*! The variable data of headers, types and content */
+	struct ast_variable *vars;
+	/*! If true destroy vars on destruction of this object */
+	char destroy_vars;
+};
+
+/*!
+ * \internal
+ * \brief Destroy the notify data releasing any resources.
+ */
+static void notify_data_destroy(void *obj)
+{
+	struct notify_data *data = obj;
+
+	ao2_cleanup(data->endpoint);
+
+	if (data->destroy_vars) {
+		ast_variables_destroy(data->vars);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Construct a notify data object.
+ */
+static struct notify_data* notify_data_create(struct ast_sip_endpoint *endpoint,
+					      struct ast_variable *vars,
+					      char destroy_vars)
+{
+	struct notify_data *data = ao2_alloc(sizeof(*data), notify_data_destroy);
+
+	if (!data) {
+		return NULL;
+	}
+
+	data->endpoint = endpoint;
+	ao2_ref(data->endpoint, +1);
+
+	data->vars = vars;
+	data->destroy_vars = destroy_vars;
+
+	return data;
+}
+
+/*!
+ * \internal
+ * \brief Checks if the given header name is not allowed.
+ *
+ * \details Some headers are not allowed to be set by the user within the
+ *          scope of a NOTIFY request.  If the given var header name is
+ *          found in the "not allowed" list then return true.
+ */
+static int not_allowed(const char *name)
+{
+	int i;
+	static const char *names[] = {
+		"Call-ID",
+		"Contact",
+		"CSeq",
+		"To",
+		"From",
+		"Record-Route",
+		"Route",
+		"Request-URI",
+		"Via",
+	};
+
+	for (i = 0; i < ARRAY_LEN(names); ++i) {
+		if (!strcasecmp(name, names[i])) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Build the NOTIFY request adding header and content when specified.
+ */
+static void build_notify(pjsip_tx_data *tdata, struct ast_variable *vars)
+{
+	RAII_VAR(struct ast_str *, content_type, NULL, ast_free);
+	RAII_VAR(struct ast_str *, content, NULL, ast_free);
+	struct ast_sip_body body;
+	struct ast_variable *i;
+
+	ast_sip_add_header(tdata, "Subscription-State", "terminated");
+
+	for (i = vars; i; i = i->next) {
+		if (not_allowed(i->name)) {
+			ast_log(LOG_WARNING, "Cannot specify %s header, "
+				"ignoring\n", i->name);
+			continue;
+		}
+
+		if (!strcasecmp(i->name, "Content-type")) {
+			if (!content_type) {
+				content_type = ast_str_create(CONTENT_TYPE_SIZE);
+			}
+			ast_str_set(&content_type, 0,"%s", i->value);
+		} else if (!strcasecmp(i->name, "Content")) {
+			if (!content) {
+				content = ast_str_create(CONTENT_SIZE);
+			}
+
+			if (ast_str_strlen(content)) {
+				ast_str_append(&content, 0, "\r\n");
+			}
+			ast_str_append(&content, 0, "%s", i->value);
+		} else {
+			ast_sip_add_header(tdata, i->name, i->value);
+		}
+	}
+
+	if (content_type) {
+		char *p;
+		if (content) {
+			body.body_text = ast_str_buffer(content);
+		}
+
+		body.type = ast_str_buffer(content_type);
+		if ((p = strchr(body.type, '/'))) {
+			*p++ = '\0';
+			body.subtype = p;
+		}
+		ast_sip_add_body(tdata, &body);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Build and send a NOTIFY request to a contact.
+ */
+static int notify_contact(void *obj, void *arg, int flags)
+{
+	struct ast_sip_contact *contact = obj;
+	struct notify_data *data = arg;
+	pjsip_tx_data *tdata;
+
+	if (ast_sip_create_request("NOTIFY", NULL, data->endpoint,
+				   contact->uri, &tdata)) {
+		ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for "
+			"contact %s\n",	contact->uri);
+		return -1;
+	}
+
+	build_notify(tdata, data->vars);
+
+	if (ast_sip_send_request(tdata, NULL, data->endpoint)) {
+		pjsip_tx_data_dec_ref(tdata);
+		ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for "
+			"contact %s\n",	contact->uri);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Send a NOTIFY request to the endpoint.
+ *
+ * \detail Iterates over an endpoint's AORs sending a NOTIFY request
+ *         with the appropriate payload information to each contact.
+ */
+static int notify_endpoint(void *obj)
+{
+	RAII_VAR(struct notify_data *, data, obj, ao2_cleanup);
+	char *aor_name, *aors;
+
+	if (ast_strlen_zero(data->endpoint->aors)) {
+		ast_log(LOG_WARNING, "Unable to NOTIFY - "
+			"endpoint has no configured AORs\n");
+		return -1;
+	}
+
+	aors = ast_strdupa(data->endpoint->aors);
+
+	while ((aor_name = strsep(&aors, ","))) {
+		RAII_VAR(struct ast_sip_aor *, aor,
+			 ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+
+		if (!aor || !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
+			continue;
+		}
+
+		ao2_callback(contacts, OBJ_NODATA, notify_contact, data);
+	}
+
+	return 0;
+}
+
+enum notify_result {
+	SUCCESS,
+	INVALID_ENDPOINT,
+	ALLOC_ERROR,
+	TASK_PUSH_ERROR
+};
+
+/*!
+ * \internal
+ * \brief Send a NOTIFY request to the endpoint within a threaded task.
+ */
+static enum notify_result push_notify(const char *endpoint_name,
+				      struct ast_variable *vars,
+				      char destroy_vars)
+{
+	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+	struct notify_data *data;
+
+	if (!(endpoint = ast_sorcery_retrieve_by_id(
+		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
+		return INVALID_ENDPOINT;
+	}
+
+	if (!(data = notify_data_create(endpoint, vars, destroy_vars))) {
+		return ALLOC_ERROR;
+	}
+
+	if (ast_sip_push_task(NULL, notify_endpoint, data)) {
+		ao2_cleanup(data);
+		return TASK_PUSH_ERROR;
+	}
+
+	return SUCCESS;
+}
+
+/*!
+ * \internal
+ * \brief Do completion on the endpoint.
+ */
+static char *cli_complete_endpoint(const char *word, int state)
+{
+	char *result = NULL;
+	int wordlen = strlen(word);
+	int which = 0;
+
+	struct ast_sip_endpoint *endpoint;
+	RAII_VAR(struct ao2_container *, endpoints,
+		 ast_sip_get_endpoints(), ao2_cleanup);
+
+	struct ao2_iterator i = ao2_iterator_init(endpoints, 0);
+	while ((endpoint = ao2_iterator_next(&i))) {
+		const char *name = ast_sorcery_object_get_id(endpoint);
+		if (!strncasecmp(word, name, wordlen) && ++which > state) {
+			result = ast_strdup(name);
+		}
+
+		ao2_cleanup(endpoint);
+		if (result) {
+			break;
+		}
+	}
+	ao2_iterator_destroy(&i);
+	return result;
+}
+
+/*!
+ * \internal
+ * \brief Do completion on the notify CLI command.
+ */
+static char *cli_complete_notify(const char *line, const char *word,
+				 int pos, int state)
+{
+	char *c = NULL;
+
+	if (pos == 2) {
+		int which = 0;
+		char *cat = NULL;
+		int wordlen = strlen(word);
+
+		/* do completion for notify type */
+
+		if (!notify_types)
+			return NULL;
+
+		while ((cat = ast_category_browse(notify_types, cat))) {
+			if (!strncasecmp(word, cat, wordlen) && ++which > state) {
+				c = ast_strdup(cat);
+				break;
+			}
+		}
+		return c;
+	}
+	return pos > 2 ? cli_complete_endpoint(word, state) : NULL;
+}
+
+/*!
+ * \internal
+ * \brief CLI command to send a SIP notify to an endpoint.
+ *
+ * \details Attempts to match the "type" given in the CLI command to a
+ *          configured one.  If found, sends a NOTIFY to the endpoint
+ *          with the associated payload.
+ */
+static char *cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ast_variable *vars;
+	int i;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "gulp notify";
+		e->usage =
+			"Usage: gulp notify <type> <peer> [<peer>...]\n"
+			"       Send a NOTIFY message to a SIP peer or peers\n"
+			"       Message types are defined in sip_notify.conf\n";
+		return NULL;
+	case CLI_GENERATE:
+		return cli_complete_notify(a->line, a->word, a->pos, a->n);
+	}
+
+	if (a->argc < 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (!notify_types) {
+		ast_cli(a->fd, "%s not found, or no types listed there\n",
+			notify_config);
+		return CLI_FAILURE;
+	}
+
+	if (!(vars = ast_variable_browse(notify_types, a->argv[2]))) {
+		ast_cli(a->fd, "Unable to find notify type '%s'\n",
+			a->argv[2]);
+		return CLI_FAILURE;
+	}
+
+	for (i = 3; i < a->argc; ++i) {
+		ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n",
+			a->argv[2], a->argv[i]);
+
+		switch (push_notify(a->argv[i], vars, 0)) {
+		case INVALID_ENDPOINT:
+			ast_log(LOG_WARNING, "Unable to retrieve endpoint %s\n",
+				a->argv[i]);
+			break;
+		case ALLOC_ERROR:
+			ast_cli(a->fd, "Unable to allocate NOTIFY task data\n");
+			return CLI_FAILURE;
+		case TASK_PUSH_ERROR:
+			ast_cli(a->fd, "Unable to push NOTIFY task\n");
+			return CLI_FAILURE;
+		default:
+			break;
+		}
+	}
+
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_options[] = {
+	AST_CLI_DEFINE(cli_notify, "Send an OPTIONS request to a SIP endpoint")
+};
+
+/*!
+ * \internal
+ * \brief AMI entry point to send a SIP notify to an endpoint.
+ */
+static int manager_notify(struct mansession *s, const struct message *m)
+{
+	const char *endpoint_name = astman_get_header(m, "Channel");
+	struct ast_variable *vars = astman_get_variables(m);
+
+	if (ast_strlen_zero(endpoint_name)) {
+		astman_send_error(s, m, "GulpNotify requires a channel name");
+		return 0;
+	}
+
+	if (!strncasecmp(endpoint_name, "sip/", 4)) {
+		endpoint_name += 4;
+	}
+
+	switch (push_notify(endpoint_name, vars, 1)) {
+	case INVALID_ENDPOINT:
+		astman_send_error_va(s, m, "Unable to retrieve endpoint %s\n",
+			endpoint_name);
+		return 0;
+	case ALLOC_ERROR:
+		astman_send_error(s, m, "Unable to allocate NOTIFY task data\n");
+		return 0;
+	case TASK_PUSH_ERROR:
+		astman_send_error(s, m, "Unable to push NOTIFY task\n");
+		return 0;
+	default:
+		break;
+	}
+
+	astman_send_ack(s, m, "Notify Sent");
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief [Re]Load data from the configuration file.
+ */
+static int load_config(int reload)
+{
+	struct ast_flags flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+
+	if (notify_types) {
+		ast_config_destroy(notify_types);
+	}
+
+	if ((notify_types = ast_config_load(
+		     notify_config, flags)) == CONFIG_STATUS_FILEINVALID) {
+
+		ast_log(LOG_ERROR, "Unable to parse %s - invalid content.\n",
+			notify_config);
+		notify_types = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int load_module(void)
+{
+	if (load_config(0)) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
+	ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
+	ast_manager_register_xml("GulpNotify", EVENT_FLAG_SYSTEM, manager_notify);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload_module(void)
+{
+	return load_config(1) ? AST_MODULE_LOAD_DECLINE :
+		AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+	ast_manager_unregister("GulpNotify");
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "CLI/AGI SIP Notify Support",
+		.load = load_module,
+		.reload = reload_module,
+		.unload = unload_module,
+		.load_pri = AST_MODPRI_APP_DEPEND,
+	       );

Propchange: team/kharwell/gulp_notify/res/res_sip_notify.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/kharwell/gulp_notify/res/res_sip_notify.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Propchange: team/kharwell/gulp_notify/res/res_sip_notify.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list