[asterisk-commits] mjordan: branch group/pimp_my_sip r380245 - in /team/group/pimp_my_sip: chann...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jan 28 08:44:59 CST 2013


Author: mjordan
Date: Mon Jan 28 08:44:54 2013
New Revision: 380245

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=380245
Log:
Add initial OPTIONS request handling; move some stuff into separate files

This adds support for inbound OPTIONS request handling and, theoretically,
outbound OPTIONS request handling for endpoint qualifying.

It also moves the configuration stuff into its own separate file.

Added:
    team/group/pimp_my_sip/res/res_sip/include/
    team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h   (with props)
    team/group/pimp_my_sip/res/res_sip/sip_configuration.c   (with props)
    team/group/pimp_my_sip/res/res_sip/sip_options.c   (with props)
Modified:
    team/group/pimp_my_sip/channels/Makefile
    team/group/pimp_my_sip/include/asterisk/res_sip.h
    team/group/pimp_my_sip/res/Makefile
    team/group/pimp_my_sip/res/res_sip.c
    team/group/pimp_my_sip/res/res_sip_endpoint_identifier_constant.c
    team/group/pimp_my_sip/res/res_sorcery_config.c

Modified: team/group/pimp_my_sip/channels/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/channels/Makefile?view=diff&rev=380245&r1=380244&r2=380245
==============================================================================
--- team/group/pimp_my_sip/channels/Makefile (original)
+++ team/group/pimp_my_sip/channels/Makefile Mon Jan 28 08:44:54 2013
@@ -114,7 +114,7 @@
 	$(CMD_PREFIX) $(MAKE) -C h323 libchanh323.a
 
 ../res/pjproject/build.mak:
-        cd ../res/pjproject && ./configure AR="" CFLAGS=-fPIC  --disable-floating-point --disable-sound --disable-oss --disable-speex-aec --disable-l16-codec --disable-gsm-codec --disable-g722-codec --disable-g7221-codec --disable-speex-codec --disable-ilbc-codec --disable-g711-codec
+	cd ../res/pjproject && ./configure AR="" CFLAGS=-fPIC  --disable-floating-point --disable-sound --disable-oss --disable-speex-aec --disable-l16-codec --disable-gsm-codec --disable-g722-codec --disable-g7221-codec --disable-speex-codec --disable-ilbc-codec --disable-g711-codec
 
 include ../res/pjproject/build.mak
 

Modified: team/group/pimp_my_sip/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/include/asterisk/res_sip.h?view=diff&rev=380245&r1=380244&r2=380245
==============================================================================
--- team/group/pimp_my_sip/include/asterisk/res_sip.h (original)
+++ team/group/pimp_my_sip/include/asterisk/res_sip.h Mon Jan 28 08:44:54 2013
@@ -198,6 +198,8 @@
 	enum ast_sip_dtmf_mode dtmf;
 	/*! List of outbound registrations */
 	AST_LIST_HEAD_NOLOCK(, ast_sip_registration) registrations;
+	/*! Frequency to send OPTIONS requests to endpoint. 0 is disabled. */
+	unsigned int qualify_frequency;
 };
 
 /*!

Modified: team/group/pimp_my_sip/res/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/Makefile?view=diff&rev=380245&r1=380244&r2=380245
==============================================================================
--- team/group/pimp_my_sip/res/Makefile (original)
+++ team/group/pimp_my_sip/res/Makefile Mon Jan 28 08:44:54 2013
@@ -71,7 +71,7 @@
 
 clean::
 	$(MAKE) -C pjproject realclean
-	rm -f snmp/*.o snmp/*.i ael/*.o ael/*.i ais/*.o ais/*.i
+	rm -f snmp/*.o snmp/*.i ael/*.o ael/*.i ais/*.o ais/*.i res_sip/*.o res_sip/*.i
 
 pjproject/build.mak:
 	cd pjproject && ./configure AR="" CFLAGS=-fPIC  --disable-floating-point --disable-sound --disable-oss --disable-speex-aec --disable-l16-codec --disable-gsm-codec --disable-g722-codec --disable-g7221-codec --disable-speex-codec --disable-ilbc-codec --disable-g711-codec
@@ -90,6 +90,8 @@
 res_rtp_asterisk.so: _ASTLDFLAGS+=$(PJ_LDFLAGS)
 res_rtp_asterisk.so: LIBS+=$(PJ_LDLIBS)
 
+res_sip/%.o: $(PJ_LIB_FILES)
+
 res_sip.o: $(PJ_LIB_FILES)
 res_sip.o: _ASTCFLAGS+=$(PJ_CFLAGS)
 res_sip.so: _ASTLDFLAGS+=$(PJ_LDFLAGS)

Modified: team/group/pimp_my_sip/res/res_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip.c?view=diff&rev=380245&r1=380244&r2=380245
==============================================================================
--- team/group/pimp_my_sip/res/res_sip.c (original)
+++ team/group/pimp_my_sip/res/res_sip.c Mon Jan 28 08:44:54 2013
@@ -25,6 +25,7 @@
 #include "pjlib.h"
 
 #include "asterisk/res_sip.h"
+#include "res_sip/include/res_sip_private.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/logger.h"
 #include "asterisk/lock.h"
@@ -45,143 +46,6 @@
 
 static struct ast_threadpool *sip_threadpool;
 
-static struct ast_sorcery *sip_sorcery;
-
-/*!
- * \brief Structure used to map an IP address to an endpoint.
- *
- * This is useful for determining if an incoming request
- * is coming from a particular endpoint.
- */
-struct sip_location_to_endpoint {
-	SORCERY_OBJECT(details);
-	const char *endpoint_name;
-};
-
-static void sip_location_to_endpoint_destroy(void *obj)
-{
-	struct sip_location_to_endpoint *location_to_endpoint = obj;
-	ast_free((char *)location_to_endpoint->endpoint_name);
-}
-
-static void *sip_location_to_endpoint_alloc(const char *name)
-{
-	return ao2_alloc(sizeof(struct sip_location_to_endpoint), sip_location_to_endpoint_destroy);
-}
-/*!
- * \brief Structure used to map an endpoint name to its location
- *
- * Location is stored as a string so that a FQDN may be stored
- * and the location may be resolved.
- *
- * This is useful for determining the destination for an outgoing
- * request to a specific endpoint
- */
-struct sip_endpoint_to_location {
-	SORCERY_OBJECT(details);
-	const char *host;
-};
-
-static void sip_endpoint_to_location_destroy(void *obj)
-{
-	struct sip_endpoint_to_location *endpoint_to_location = obj;
-	ast_free((char *) endpoint_to_location->host);
-}
-
-static void *sip_endpoint_to_location_alloc(const char *name)
-{
-	return ao2_alloc(sizeof(struct sip_endpoint_to_location), sip_endpoint_to_location_destroy);
-}
-
-static int host_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	RAII_VAR(struct sip_location_to_endpoint *, location_to_endpoint, NULL, ao2_cleanup);
-	RAII_VAR(struct sip_endpoint_to_location *, endpoint_to_location, NULL, ao2_cleanup);
-	const char *host = var->value;
-	const char *name = ast_sorcery_object_get_id(obj);
-
-	location_to_endpoint = ast_sorcery_alloc(sip_sorcery, "location_to_endpoint", host);
-	if (!location_to_endpoint) {
-		return -1;
-	}
-	endpoint_to_location = ast_sorcery_alloc(sip_sorcery, "endpoint_to_location", name);
-	if (!endpoint_to_location) {
-		return -1;
-	}
-
-	location_to_endpoint->endpoint_name = ast_strdup(name);
-	endpoint_to_location->host = ast_strdup(host);
-
-	if (ast_sorcery_create(sip_sorcery, location_to_endpoint)) {
-		return -1;
-	}
-	if (ast_sorcery_create(sip_sorcery, endpoint_to_location)) {
-		ast_sorcery_delete(sip_sorcery, location_to_endpoint);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	if (!strcasecmp(var->value, "rfc4733")) {
-		endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
-	} else if (!strcasecmp(var->value, "inband")) {
-		endpoint->dtmf = AST_SIP_DTMF_INBAND;
-	} else if (!strcasecmp(var->value, "info")) {
-		endpoint->dtmf = AST_SIP_DTMF_INFO;
-	} else if (!strcasecmp(var->value, "none")) {
-		endpoint->dtmf = AST_SIP_DTMF_NONE;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-static int sip_initialize_sorcery(void)
-{
-	if (!(sip_sorcery = ast_sorcery_open())) {
-		ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
-		return -1;
-	}
-
-	ast_sorcery_apply_config(sip_sorcery, "res_sip");
-	ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "res_sip.conf,criteria=type=endpoint");
-
-	ast_sorcery_apply_default(sip_sorcery, "location_to_endpoint", "memory", NULL);
-	ast_sorcery_apply_default(sip_sorcery, "endpoint_to_location", "memory", NULL);
-
-	if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, NULL)) {
-		ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	ast_sorcery_object_register(sip_sorcery, "location_to_endpoint", sip_location_to_endpoint_alloc, NULL, NULL);
-	ast_sorcery_object_register(sip_sorcery, "endpoint_to_location", sip_endpoint_to_location_alloc, NULL, NULL);
-
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, prefs, codecs));
-	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, prefs, codecs));
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "host", "", host_handler, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmfmode", "rfc4733", dtmf_handler, NULL, 0, 0);
-
-	if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
-		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
-		ast_sorcery_unref(sip_sorcery);
-		sip_sorcery = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
 int ast_sip_register_service(pjsip_module *module)
 {
 	if (!ast_pjsip_endpoint) {
@@ -350,70 +214,9 @@
 	return endpoint;
 }
 
-static void endpoint_destructor(void* obj)
-{
-	struct ast_sip_endpoint *endpoint = obj;
-
-	ast_string_field_free_memory(endpoint);
-
-	if (endpoint->codecs) {
-		ast_format_cap_destroy(endpoint->codecs);
-	}
-
-	/* XXX Will likely need to destroy a bunch
-	 * more other endpoint data too.
-	 */
-}
-
-void *ast_sip_endpoint_alloc(const char *name)
-{
-	struct ast_sip_endpoint *endpoint = ao2_alloc(sizeof(*endpoint), endpoint_destructor);
-	if (!endpoint) {
-		return NULL;
-	}
-	if (ast_string_field_init(endpoint, 64)) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	if (!(endpoint->codecs = ast_format_cap_alloc_nolock())) {
-		ao2_cleanup(endpoint);
-		return NULL;
-	}
-	return endpoint;
-}
-
-void ast_sip_endpoint_get_location(const struct ast_sip_endpoint *endpoint, char *location_buf, size_t size)
-{
-	struct sip_endpoint_to_location *endpoint_to_location;
-	endpoint_to_location = ast_sorcery_retrieve_by_id(sip_sorcery, "endpoint_to_location", ast_sorcery_object_get_id(endpoint));
-	if (!endpoint_to_location) {
-		return;
-	}
-	ast_copy_string(location_buf, endpoint_to_location->host, size);
-	ao2_ref(endpoint_to_location, -1);
-}
-
-struct ast_sip_endpoint *ast_sip_get_endpoint_from_location(const char *location)
-{
-	struct sip_location_to_endpoint *location_to_endpoint;
-	struct ast_sip_endpoint *endpoint;
-	location_to_endpoint = ast_sorcery_retrieve_by_id(sip_sorcery, "location_to_endpoint", location);
-	if (!location_to_endpoint) {
-		return NULL;
-	}
-	endpoint = ast_sorcery_retrieve_by_id(sip_sorcery, "endpoint", location_to_endpoint->endpoint_name);
-	ao2_ref(location_to_endpoint, -1);
-	return endpoint;
-}
-
 pjsip_endpoint *ast_sip_get_pjsip_endpoint(void)
 {
 	return ast_pjsip_endpoint;
-}
-
-struct ast_sorcery *ast_sip_get_sorcery(void)
-{
-	return sip_sorcery;
 }
 
 /* PJSIP doesn't know about the INFO method, so we have to define it ourselves */
@@ -733,23 +536,22 @@
 		goto error;
 	}
 
+	if (ast_res_sip_initialize_configuration()) {
+		ast_log(LOG_ERROR, "Failed to initialize SIP configuration. Aborting load\n");
+		goto error;
+	}
+
 	if (ast_sip_register_service(&unhandled_module)) {
 		ast_log(LOG_ERROR, "Failed to register unhandled request module. Aborting load\n");
 		goto error;
 	}
 
-	if (sip_initialize_sorcery()) {
-		ast_log(LOG_ERROR, "Failed to initialize SIP sorcery. Aborting load\n");
-		goto error;
-	}
-
-	ast_sorcery_load(sip_sorcery);
-
-	return AST_MODULE_LOAD_SUCCESS;
+	ast_res_sip_init_options_handling(0);
+
+return AST_MODULE_LOAD_SUCCESS;
 
 error:
-	ast_sorcery_unref(sip_sorcery);
-
+	ast_res_sip_destroy_configuration();
 	if (monitor_thread) {
 		stop_monitor_thread();
 	}
@@ -766,19 +568,23 @@
 
 static int reload_module(void)
 {
-	if (sip_sorcery) {
-		ast_sorcery_reload(sip_sorcery);
-	}
+	if (ast_res_sip_reload_configuration()) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	ast_res_sip_init_options_handling(1);
 	return 0;
 }
 
 static int unload_module(void)
 {
-	ast_sorcery_unref(sip_sorcery);
+	ast_res_sip_destroy_configuration();
 	if (monitor_thread) {
 		stop_monitor_thread();
 	}
 	if (memory_pool) {
+		/* This will cause a crash in Asterisk in debug mode, as the thread
+		 * calling this is not a pjsip thread
+		 */
 		pj_pool_release(memory_pool);
 	}
 	if (ast_pjsip_endpoint) {
@@ -793,4 +599,4 @@
 		.unload = unload_module,
 		.reload = reload_module,
 		.load_pri = AST_MODPRI_CHANNEL_DEPEND,
-	       );
+);

Added: team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h?view=auto&rev=380245
==============================================================================
--- team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h (added)
+++ team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h Mon Jan 28 08:44:54 2013
@@ -1,0 +1,49 @@
+/*
+ * res_sip.h
+ *
+ *  Created on: Jan 25, 2013
+ *      Author: mjordan
+ */
+
+#ifndef RES_SIP_PRIVATE_H_
+#define RES_SIP_PRIVATE_H_
+
+struct ao2_container;
+
+/*!
+ * \brief Initialize the configuration for res_sip
+ */
+int ast_res_sip_initialize_configuration(void);
+
+/*!
+ * \brief Annihilate the configuration objects
+ */
+void ast_res_sip_destroy_configuration(void);
+
+/*!
+ * \brief Reload the configuration
+ */
+int ast_res_sip_reload_configuration(void);
+
+/*!
+ * \brief Initialize OPTIONS request handling.
+ *
+ * XXX This currently includes qualifying peers. It shouldn't.
+ * That should go into a registrar. When that occurs, we won't
+ * need the reload stuff.
+ *
+ * \param reload Reload options handling
+ *
+ * \retval 0 on success
+ * \retval other on failure
+ */
+int ast_res_sip_init_options_handling(int reload);
+
+/*!
+ * \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_ */

Propchange: team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/pimp_my_sip/res/res_sip/include/res_sip_private.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/pimp_my_sip/res/res_sip/sip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip/sip_configuration.c?view=auto&rev=380245
==============================================================================
--- team/group/pimp_my_sip/res/res_sip/sip_configuration.c (added)
+++ team/group/pimp_my_sip/res/res_sip/sip_configuration.c Mon Jan 28 08:44:54 2013
@@ -1,0 +1,282 @@
+/*
+ * sip_cli_commands.c
+ *
+ *  Created on: Jan 25, 2013
+ *      Author: mjordan
+ */
+
+#include "asterisk.h"
+
+#undef bzero
+#define bzero bzero
+#include "pjsip.h"
+
+#include "asterisk/res_sip.h"
+#include "include/res_sip_private.h"
+#include "asterisk/cli.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/utils.h"
+#include "asterisk/sorcery.h"
+
+static struct ast_sorcery *sip_sorcery;
+
+/*!
+ * \brief Structure used to map an IP address to an endpoint.
+ *
+ * This is useful for determining if an incoming request
+ * is coming from a particular endpoint.
+ */
+struct sip_location_to_endpoint {
+	SORCERY_OBJECT(details);
+	const char *endpoint_name;
+};
+
+static char *handle_cli_show_endpoints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
+	struct ao2_iterator it_endpoints;
+	struct ast_sip_endpoint *endpoint;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "sip show endpoints";
+		e->usage =
+			"Usage: sip show endpoints\n"
+			"       Show the registered SIP endpoints\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	endpoints = ast_res_sip_get_endpoints();
+	if (!endpoints) {
+		return CLI_FAILURE;
+	}
+
+	if (!ao2_container_count(endpoints)) {
+		ast_cli(a->fd, "No endpoints found\n");
+		return CLI_SUCCESS;
+	}
+
+	ast_cli(a->fd, "Endpoints:\n");
+	it_endpoints = ao2_iterator_init(endpoints, 0);
+	while ((endpoint = ao2_iterator_next(&it_endpoints))) {
+		ast_cli(a->fd, "%s\n", ast_sorcery_object_get_id(endpoint));
+		ao2_ref(endpoint, -1);
+	}
+	ao2_iterator_destroy(&it_endpoints);
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_commands[] = {
+	AST_CLI_DEFINE(handle_cli_show_endpoints, "Show SIP Endpoints"),
+};
+
+static void sip_location_to_endpoint_destroy(void *obj)
+{
+	struct sip_location_to_endpoint *location_to_endpoint = obj;
+	ast_free((char *)location_to_endpoint->endpoint_name);
+}
+
+static void *sip_location_to_endpoint_alloc(const char *name)
+{
+	return ao2_alloc(sizeof(struct sip_location_to_endpoint), sip_location_to_endpoint_destroy);
+}
+/*!
+ * \brief Structure used to map an endpoint name to its location
+ *
+ * Location is stored as a string so that a FQDN may be stored
+ * and the location may be resolved.
+ *
+ * This is useful for determining the destination for an outgoing
+ * request to a specific endpoint
+ */
+struct sip_endpoint_to_location {
+	SORCERY_OBJECT(details);
+	const char *host;
+};
+
+static void sip_endpoint_to_location_destroy(void *obj)
+{
+	struct sip_endpoint_to_location *endpoint_to_location = obj;
+	ast_free((char *) endpoint_to_location->host);
+}
+
+static void *sip_endpoint_to_location_alloc(const char *name)
+{
+	return ao2_alloc(sizeof(struct sip_endpoint_to_location), sip_endpoint_to_location_destroy);
+}
+
+static int host_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	RAII_VAR(struct sip_location_to_endpoint *, location_to_endpoint, NULL, ao2_cleanup);
+	RAII_VAR(struct sip_endpoint_to_location *, endpoint_to_location, NULL, ao2_cleanup);
+	const char *host = var->value;
+	const char *name = ast_sorcery_object_get_id(obj);
+
+	location_to_endpoint = ast_sorcery_alloc(sip_sorcery, "location_to_endpoint", host);
+	if (!location_to_endpoint) {
+		return -1;
+	}
+	endpoint_to_location = ast_sorcery_alloc(sip_sorcery, "endpoint_to_location", name);
+	if (!endpoint_to_location) {
+		return -1;
+	}
+
+	location_to_endpoint->endpoint_name = ast_strdup(name);
+	endpoint_to_location->host = ast_strdup(host);
+
+	if (ast_sorcery_create(sip_sorcery, location_to_endpoint)) {
+		return -1;
+	}
+	if (ast_sorcery_create(sip_sorcery, endpoint_to_location)) {
+		ast_sorcery_delete(sip_sorcery, location_to_endpoint);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct ast_sip_endpoint *endpoint = obj;
+
+	if (!strcasecmp(var->value, "rfc4733")) {
+		endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
+	} else if (!strcasecmp(var->value, "inband")) {
+		endpoint->dtmf = AST_SIP_DTMF_INBAND;
+	} else if (!strcasecmp(var->value, "info")) {
+		endpoint->dtmf = AST_SIP_DTMF_INFO;
+	} else if (!strcasecmp(var->value, "none")) {
+		endpoint->dtmf = AST_SIP_DTMF_NONE;
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+int ast_res_sip_initialize_configuration(void)
+{
+	if (ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands))) {
+		return -1;
+	}
+
+	if (!(sip_sorcery = ast_sorcery_open())) {
+		ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
+		return -1;
+	}
+
+	ast_sorcery_apply_config(sip_sorcery, "res_sip");
+	ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "res_sip.conf,criteria=type=endpoint");
+
+	ast_sorcery_apply_default(sip_sorcery, "location_to_endpoint", "memory", NULL);
+	ast_sorcery_apply_default(sip_sorcery, "endpoint_to_location", "memory", NULL);
+
+	if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, NULL)) {
+		ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
+		ast_sorcery_unref(sip_sorcery);
+		sip_sorcery = NULL;
+		return -1;
+	}
+
+	ast_sorcery_object_register(sip_sorcery, "location_to_endpoint", sip_location_to_endpoint_alloc, NULL, NULL);
+	ast_sorcery_object_register(sip_sorcery, "endpoint_to_location", sip_endpoint_to_location_alloc, NULL, NULL);
+
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, prefs, codecs));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, prefs, codecs));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_endpoint, qualify_frequency), 0, 86400);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "host", "", host_handler, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmfmode", "rfc4733", dtmf_handler, NULL, 0, 0);
+
+	ast_sorcery_load(sip_sorcery);
+
+	return 0;
+}
+
+void ast_res_sip_destroy_configuration(void)
+{
+	ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
+	ast_sorcery_unref(sip_sorcery);
+}
+
+int ast_res_sip_reload_configuration(void)
+{
+	if (sip_sorcery) {
+		ast_sorcery_reload(sip_sorcery);
+	}
+	return 0;
+}
+
+static void endpoint_destructor(void* obj)
+{
+	struct ast_sip_endpoint *endpoint = obj;
+
+	ast_string_field_free_memory(endpoint);
+
+	if (endpoint->codecs) {
+		ast_format_cap_destroy(endpoint->codecs);
+	}
+
+	/* XXX Will likely need to destroy a bunch
+	 * more other endpoint data too.
+	 */
+}
+
+void *ast_sip_endpoint_alloc(const char *name)
+{
+	struct ast_sip_endpoint *endpoint = ao2_alloc(sizeof(*endpoint), endpoint_destructor);
+	if (!endpoint) {
+		return NULL;
+	}
+	if (ast_string_field_init(endpoint, 64)) {
+		ao2_cleanup(endpoint);
+		return NULL;
+	}
+	if (!(endpoint->codecs = ast_format_cap_alloc_nolock())) {
+		ao2_cleanup(endpoint);
+		return NULL;
+	}
+	return endpoint;
+}
+
+void ast_sip_endpoint_get_location(const struct ast_sip_endpoint *endpoint, char *location_buf, size_t size)
+{
+	struct sip_endpoint_to_location *endpoint_to_location;
+	endpoint_to_location = ast_sorcery_retrieve_by_id(sip_sorcery, "endpoint_to_location", ast_sorcery_object_get_id(endpoint));
+	if (!endpoint_to_location) {
+		return;
+	}
+	ast_copy_string(location_buf, endpoint_to_location->host, size);
+	ao2_ref(endpoint_to_location, -1);
+}
+
+struct ast_sip_endpoint *ast_sip_get_endpoint_from_location(const char *location)
+{
+	struct sip_location_to_endpoint *location_to_endpoint;
+	struct ast_sip_endpoint *endpoint;
+	location_to_endpoint = ast_sorcery_retrieve_by_id(sip_sorcery, "location_to_endpoint", location);
+	if (!location_to_endpoint) {
+		return NULL;
+	}
+	endpoint = ast_sorcery_retrieve_by_id(sip_sorcery, "endpoint", location_to_endpoint->endpoint_name);
+	ao2_ref(location_to_endpoint, -1);
+	return endpoint;
+}
+
+struct ao2_container *ast_res_sip_get_endpoints(void)
+{
+	struct ao2_container *endpoints;
+
+	endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+
+	return endpoints;
+}
+
+struct ast_sorcery *ast_sip_get_sorcery(void)
+{
+	return sip_sorcery;
+}
+

Propchange: team/group/pimp_my_sip/res/res_sip/sip_configuration.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/pimp_my_sip/res/res_sip/sip_configuration.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/pimp_my_sip/res/res_sip/sip_configuration.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/pimp_my_sip/res/res_sip/sip_options.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip/sip_options.c?view=auto&rev=380245
==============================================================================
--- team/group/pimp_my_sip/res/res_sip/sip_options.c (added)
+++ team/group/pimp_my_sip/res/res_sip/sip_options.c Mon Jan 28 08:44:54 2013
@@ -1,0 +1,394 @@
+/*
+ * sip_options.c
+ *
+ *  Created on: Jan 25, 2013
+ *      Author: mjordan
+ */
+
+#include "asterisk.h"
+
+#undef bzero
+#define bzero bzero
+#include "pjsip.h"
+#include "pjsip_ua.h"
+#include "pjlib.h"
+
+#include "asterisk/res_sip.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/astobj2.h"
+#include "include/res_sip_private.h"
+
+#define DEFAULT_LANGUAGE "en"
+#define DEFAULT_ENCODING "text/plain"
+#define QUALIFIED_BUCKETS 211
+
+/*! \brief Scheduling context for qualifies */
+static struct ast_sched_context *sched; /* XXX move this to registrar */
+
+struct ao2_container *scheduled_qualifies;
+
+struct qualify_info {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(endpoint_id);
+	);
+	char *scheduler_data;
+	int scheduler_id;
+};
+
+static pj_bool_t options_module_on_rx_request(pjsip_rx_data *rdata);
+static pj_bool_t options_module_on_rx_response(pjsip_rx_data *rdata);
+static pj_bool_t options_module_on_tx_request(pjsip_tx_data *tdata);
+static pj_bool_t options_module_on_tx_response(pjsip_tx_data *tdata);
+
+static pjsip_module options_module = {
+	.name = {"Options Module", 14},
+	.id = -1,
+	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
+	.on_rx_request = options_module_on_rx_request,
+	.on_rx_response = options_module_on_rx_response,
+	.on_tx_request = options_module_on_tx_request,
+	.on_tx_response = options_module_on_tx_response,
+};
+
+static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
+{
+	pj_str_t msg;
+	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
+	pjsip_transaction *pj_trans = pjsip_rdata_get_tsx(rdata);
+	pjsip_dialog *pj_dlg = pjsip_rdata_get_dlg(rdata);
+	pjsip_tx_data *tdata;
+	pjsip_response_addr res_addr;
+	pj_status_t status;
+
+	switch (code) {
+	case 200:
+		pj_cstr(&msg, "OK");
+		break;
+	case 404:
+		pj_cstr(&msg, "Not Found");
+		break;
+	case 503:
+		pj_cstr(&msg, "Unavailable");
+		break;
+	default:
+		pj_cstr(&msg, "");
+		break;
+	}
+
+	/* Make the response object */
+	status = pjsip_endpt_create_response(endpt, rdata, code, &msg, &tdata);
+	if (status != PJ_SUCCESS) {
+		return status;
+	}
+
+	if (pj_dlg && pj_trans) {
+		status = pjsip_dlg_send_response(pj_dlg, pj_trans, tdata);
+	} else {
+		/* Get where to send request. */
+		status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
+		if (status != PJ_SUCCESS) {
+			pjsip_tx_data_dec_ref(tdata);
+			return status;
+		}
+		status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL, NULL);
+	}
+
+	return status;
+}
+
+static pj_bool_t options_module_on_rx_request(pjsip_rx_data *rdata)
+{
+	pj_bool_t res = PJ_FALSE;
+	pjsip_uri *ruri;
+	pjsip_sip_uri *sip_ruri;
+	char exten[AST_MAX_EXTENSION];
+
+	switch (rdata->msg_info.msg->line.req.method.id) {
+	case PJSIP_OPTIONS_METHOD:
+		ruri = rdata->msg_info.msg->line.req.uri;
+		if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
+			break;
+		}
+		sip_ruri = pjsip_uri_get_uri(ruri);
+		ast_copy_pj_str(exten, &sip_ruri->user, sizeof(exten));
+
+		/* XXX TODO: eventually, this needs to be replaced with
+		 * some more advanced stuff (like inbound context, etc.)
+		 * We also need to authentication on the user.
+		 */
+		res = PJ_TRUE;
+
+		if (ast_shutting_down()) {
+			send_options_response(rdata, 503);
+			break;
+		}
+
+		/* XXX TODO: we should probably take the destination and see if it
+		 * matches a known endpoint. If so, and they happen to be in a dialog,
+		 * we can expose some additional information.
+		 */
+		if (!ast_exists_extension(NULL, "default", exten, 1, NULL)) {
+			send_options_response(rdata, 404);
+			break;
+		}
+
+		send_options_response(rdata, 200);
+		break;
+	default:
+		break;
+	}
+
+	return res;
+}
+
+static pj_bool_t options_module_on_rx_response(pjsip_rx_data *rdata)
+{
+
+	return PJ_SUCCESS;
+}
+
+static void add_outbound_headers(pjsip_tx_data *tdata)
+{
+	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
+	const pjsip_hdr *c_hdr;
+	pjsip_hdr *hdr;
+
+	ast_assert(endpt != NULL);
+
+	/* XXX TODO: add a contact header? */
+	if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ACCEPT, NULL) == NULL) {
+		c_hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL);
+		if (c_hdr) {
+			hdr = (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, c_hdr);
+			pjsip_msg_add_hdr(tdata->msg, hdr);
+		}
+	}
+	if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL) == NULL) {
+		c_hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL);
+		if (c_hdr) {
+			hdr = (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, c_hdr);
+			pjsip_msg_add_hdr(tdata->msg, hdr);
+		}
+	}
+	if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL) == NULL) {
+		c_hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL);
+		if (c_hdr) {
+			hdr = (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, c_hdr);
+			pjsip_msg_add_hdr(tdata->msg, hdr);
+		}
+	}
+
+	/*
+	 * XXX TODO: pjsip doesn't care a lot about either of these headers -
+	 * while it provides specific methods to create them, they are defined
+	 * to be the standard string header creation. We never did add them
+	 * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here.
+	 */
+	ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
+	ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
+}
+
+static pj_bool_t options_module_on_tx_request(pjsip_tx_data *tdata)
+{
+	add_outbound_headers(tdata);
+
+	return PJ_SUCCESS;
+}
+
+static pj_bool_t options_module_on_tx_response(pjsip_tx_data *tdata)
+{
+	struct pjsip_status_line status = tdata->msg->line.status;
+
+	if (status.code < 200 || status.code >= 300) {
+		return PJ_SUCCESS;
+	}
+
+	add_outbound_headers(tdata);
+
+	/* XXX TODO: If we can map the options requester against an endpoint,
+	 * we should include what media we think they have here in an SDP.
+	 */
+	return PJ_SUCCESS;
+}
+
+static int qualify_info_hash_fn(const void *obj, int flags)
+{
+	const struct qualify_info *info = obj;
+	const char *endpoint_id = flags & OBJ_KEY ? obj : info->endpoint_id;
+
+	return ast_str_hash(endpoint_id);
+}
+
+static int qualify_info_cmp_fn(void *obj, void *arg, int flags)
+{
+	struct qualify_info *left = obj;
+	struct qualify_info *right = arg;
+	const char *right_endpoint_id = flags & OBJ_KEY ? arg : right->endpoint_id;
+
+	return strcmp(left->endpoint_id, right_endpoint_id) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+
+static void qualify_info_destructor(void *obj)
+{
+	struct qualify_info *info = obj;
+	if (!info) {
+		return;
+	}
+	ast_string_field_free_memory(info);
+	/* Cancel the qualify */
+	if (!AST_SCHED_DEL(sched, info->scheduler_id)) {
+		/* If we successfully deleted the qualify, we got it before it
+		 * fired. We can safely delete the data that was passed to it.
+		 * Otherwise, we're getting deleted while this is firing - don't
+		 * touch that memory!
+		 */
+		ast_free(info->scheduler_data);
+	}
+}
+
+static struct qualify_info *create_qualify_info(struct ast_sip_endpoint *endpoint)
+{
+	struct qualify_info *info;
+
+	info = ao2_alloc(sizeof(*info), qualify_info_destructor);
+	if (!info) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(info, 64)) {
+		ao2_ref(info, -1);
+		return NULL;
+	}
+	ast_string_field_set(info, endpoint_id, ast_sorcery_object_get_id(endpoint));
+
+	return info;
+}
+
+static void send_qualify_request(struct ast_sip_endpoint *endpoint)
+{
+	/* YAY! Send an OPTIONS request. */
+
+	ast_sip_send_request("OPTIONS", NULL, NULL, endpoint);
+
+	return;
+}
+
+static int qualify_endpoint_scheduler_cb(const void *data)
+{
+	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+	struct ast_sorcery *sorcery;
+	char *endpoint_id = (char *)data;
+
+	sorcery = ast_sip_get_sorcery();
+	if (!sorcery) {
+		ast_free(endpoint_id);
+		return 0;
+	}
+
+	endpoint = ast_sorcery_retrieve_by_id(sorcery, "endpoint", endpoint_id);
+	if (!endpoint) {
+		/* Whoops, endpoint went away */
+		ast_free(endpoint_id);
+		return 0;
+	}
+
+	/* Actually do the qualify */
+	send_qualify_request(endpoint);
+
+	return 1;
+}
+
+static void schedule_qualifies(void)
+{
+	RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
+	struct ao2_iterator it_endpoints;
+	struct ast_sip_endpoint *endpoint;
+	struct qualify_info *info;
+	char *endpoint_id;
+
+	endpoints = ast_res_sip_get_endpoints();
+	if (!endpoints) {
+		return;
+	}
+
+	it_endpoints = ao2_iterator_init(endpoints, 0);
+	while ((endpoint = ao2_iterator_next(&it_endpoints))) {
+		if (endpoint->qualify_frequency) {
+			/* XXX TODO: This really should only qualify registered peers,
+			 * which means we need a registrar. We should check the
+			 * registrar to see if this endpoint has registered and, if
+			 * not, pass on it.
+			 *
+			 * Actually, all of this should just get moved into the registrar.
+			 * Otherwise, the registar will have to kick this off when a
+			 * new endpoint registers, so it just makes sense to have it
+			 * all live there.
+			 */
+			info = create_qualify_info(endpoint);
+			if (!info) {
+				ao2_ref(endpoint, -1);
+				break;
+			}
+			endpoint_id = ast_strdup(info->endpoint_id);
+			if (!endpoint_id) {
+				ao2_t_ref(info, -1, "Dispose of info on off nominal");
+				ao2_ref(endpoint, -1);
+				break;
+			}
+			info->scheduler_data = endpoint_id;
+			info->scheduler_id = ast_sched_add_variable(sched, endpoint->qualify_frequency * 1000, qualify_endpoint_scheduler_cb, endpoint_id, 1);
+			ao2_t_link(scheduled_qualifies, info, "Link scheduled qualify information into container");
+			ao2_t_ref(info, -1, "Dispose of creation ref");
+		}
+		ao2_t_ref(endpoint, -1, "Dispose of iterator ref");
+	}
+	ao2_iterator_destroy(&it_endpoints);
+}
+
+static void options_cleanup(void)
+{
+	ao2_t_ref(scheduled_qualifies, -1, "Remove scheduled qualifies on exit");
+	ast_sip_unregister_service(&options_module);
+	if (sched) {
+		ast_sched_context_destroy(sched);
+	}
+}
+
+int ast_res_sip_init_options_handling(int reload)
+{
+	if (scheduled_qualifies) {
+		ao2_t_ref(scheduled_qualifies, -1, "Remove old scheduled qualifies");
+	}
+	scheduled_qualifies = ao2_t_container_alloc(QUALIFIED_BUCKETS, qualify_info_hash_fn, qualify_info_cmp_fn, "Create container for scheduled qualifies");
+	if (!scheduled_qualifies) {
+		return -1;
+	}
+
+	if (!reload) {
+		if (ast_sip_register_service(&options_module)) {
+			ao2_t_ref(scheduled_qualifies, -1, "Remove scheduled qualifies on off nominal path");
+			return -1;
+		}
+
+		sched = ast_sched_context_create();
+		if (!sched) {
+			ao2_t_ref(scheduled_qualifies, -1, "Remove scheduled qualifies on off nominal path");
+			ast_sip_unregister_service(&options_module);
+			return -1;
+		}
+
+		if (ast_sched_start_thread(sched)) {
+			ao2_t_ref(scheduled_qualifies, -1, "Remove scheduled qualifies on off nominal path");
+			ast_sip_unregister_service(&options_module);
+			ast_sched_context_destroy(sched);
+			return -1;
+		}
+
+		schedule_qualifies();
+	}
+
+	ast_register_atexit(options_cleanup);
+	return 0;
+}

Propchange: team/group/pimp_my_sip/res/res_sip/sip_options.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/pimp_my_sip/res/res_sip/sip_options.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/pimp_my_sip/res/res_sip/sip_options.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/group/pimp_my_sip/res/res_sip_endpoint_identifier_constant.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sip_endpoint_identifier_constant.c?view=diff&rev=380245&r1=380244&r2=380245
==============================================================================
--- team/group/pimp_my_sip/res/res_sip_endpoint_identifier_constant.c (original)
+++ team/group/pimp_my_sip/res/res_sip_endpoint_identifier_constant.c Mon Jan 28 08:44:54 2013
@@ -65,7 +65,7 @@
 	return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ADSI Resource",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP Constant Endpoint Identifier",
 		.load = load_module,
 		.unload = unload_module,
 		.load_pri = AST_MODPRI_APP_DEPEND,

Modified: team/group/pimp_my_sip/res/res_sorcery_config.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pimp_my_sip/res/res_sorcery_config.c?view=diff&rev=380245&r1=380244&r2=380245
==============================================================================
--- team/group/pimp_my_sip/res/res_sorcery_config.c (original)
+++ team/group/pimp_my_sip/res/res_sorcery_config.c Mon Jan 28 08:44:54 2013
@@ -182,7 +182,6 @@
 	if (!config_objects) {
 		return;
 	}
-
 	ao2_callback(config_objects, 0, sorcery_config_fields_cmp, &params);
 }
 




More information about the asterisk-commits mailing list