| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1999 - 2005, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Mark Spencer <markster@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. | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief Loopback PBX Module | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>core</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/logger.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/frame.h"
 | 
					
						
							|  |  |  | #include "asterisk/cli.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							|  |  |  | #include "asterisk/md5.h"
 | 
					
						
							|  |  |  | #include "asterisk/linkedlists.h"
 | 
					
						
							|  |  |  | #include "asterisk/chanvars.h"
 | 
					
						
							|  |  |  | #include "asterisk/sched.h"
 | 
					
						
							|  |  |  | #include "asterisk/io.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/astdb.h"
 | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  | /* Loopback switch creates a 'tunnel' to another context.  When extension
 | 
					
						
							|  |  |  |    lookups pass through the 'tunnel', Asterisk expressions can be used | 
					
						
							|  |  |  |    to modify the target extension, context, and priority in any way desired. | 
					
						
							|  |  |  |    If there is a match at the far end, execution jumps through the 'tunnel' | 
					
						
							|  |  |  |    to the matched context, extension, and priority. | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    Global variables as well as ${CONTEXT}, ${EXTEN}, and ${PRIORITY} are | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  |    available for substitution.  After substitution Loopback expects to get | 
					
						
							|  |  |  |    a string of the form: | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	[exten]@context[:priority][/extramatch] | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  |    Where exten, context, and priority are another extension, context, and priority | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  |    to lookup and "extramatch" is a dialplan extension pattern which the *original* | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  |    number must match.  If exten or priority are empty, the original values are | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  |    used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Note that the search context MUST be a different context from the current | 
					
						
							|  |  |  |    context or the search will not succeed.  This is intended to reduce the | 
					
						
							|  |  |  |    likelihood of loops (they're still possible if you try hard, so be careful!) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LOOPBACK_COMMON \
 | 
					
						
							|  |  |  | 	char buf[1024]; \ | 
					
						
							|  |  |  | 	int res; \ | 
					
						
							|  |  |  | 	char *newexten=(char *)exten, *newcontext=(char *)context; \ | 
					
						
							|  |  |  | 	int newpriority=priority; \ | 
					
						
							|  |  |  | 	char *newpattern=NULL; \ | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  | 	loopback_subst(buf, sizeof(buf), exten, context, priority, data); \ | 
					
						
							|  |  |  | 	loopback_parse(&newexten, &newcontext, &newpriority, &newpattern, buf); \ | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  | 	ast_debug(1, "Parsed into %s @ %s priority %d pattern %s\n", newexten, newcontext, newpriority, newpattern); \ | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	if (!strcasecmp(newcontext, context)) return -1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  | static char *loopback_subst(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_var_t *newvariable; | 
					
						
							|  |  |  | 	struct varshead headp; | 
					
						
							|  |  |  | 	char tmp[80]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(tmp, sizeof(tmp), "%d", priority); | 
					
						
							| 
									
										
										
										
											2005-10-31 15:34:11 +00:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&headp); | 
					
						
							| 
									
										
										
										
											2013-08-06 08:36:15 +00:00
										 |  |  | 	if ((newvariable = ast_var_assign("EXTEN", exten))) { | 
					
						
							|  |  |  | 		AST_LIST_INSERT_HEAD(&headp, newvariable, entries); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ((newvariable = ast_var_assign("CONTEXT", context))) { | 
					
						
							|  |  |  | 		AST_LIST_INSERT_HEAD(&headp, newvariable, entries); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ((newvariable = ast_var_assign("PRIORITY", tmp))) { | 
					
						
							|  |  |  | 		AST_LIST_INSERT_HEAD(&headp, newvariable, entries); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	/* Substitute variables */ | 
					
						
							| 
									
										
										
										
											2006-03-31 09:50:54 +00:00
										 |  |  | 	pbx_substitute_variables_varshead(&headp, data, buf, buflen); | 
					
						
							|  |  |  | 	/* free the list */ | 
					
						
							|  |  |  | 	while ((newvariable = AST_LIST_REMOVE_HEAD(&headp, entries))) | 
					
						
							|  |  |  |                 ast_var_delete(newvariable); | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	return buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-03 22:42:03 +00:00
										 |  |  | static void loopback_parse(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *con; | 
					
						
							|  |  |  | 	char *pri; | 
					
						
							|  |  |  | 	*newpattern = strchr(buf, '/'); | 
					
						
							| 
									
										
										
										
											2006-03-31 09:50:54 +00:00
										 |  |  | 	if (*newpattern) | 
					
						
							|  |  |  | 		*(*newpattern)++ = '\0'; | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	con = strchr(buf, '@'); | 
					
						
							|  |  |  | 	if (con) { | 
					
						
							| 
									
										
										
										
											2006-03-31 09:50:54 +00:00
										 |  |  | 		*con++ = '\0'; | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 		pri = strchr(con, ':'); | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		pri = strchr(buf, ':'); | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(buf)) | 
					
						
							|  |  |  | 		*newexten = buf; | 
					
						
							| 
									
										
										
										
											2005-11-08 01:55:31 +00:00
										 |  |  | 	if (!ast_strlen_zero(con)) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 		*newcontext = con; | 
					
						
							| 
									
										
										
										
											2005-11-08 01:55:31 +00:00
										 |  |  | 	if (!ast_strlen_zero(pri)) | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 		sscanf(pri, "%30d", priority); | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	LOOPBACK_COMMON; | 
					
						
							|  |  |  | 	if (newpattern && !ast_extension_match(newpattern, exten)) | 
					
						
							|  |  |  | 		res = 0; | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid); | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	LOOPBACK_COMMON; | 
					
						
							|  |  |  | 	if (newpattern && !ast_extension_match(newpattern, exten)) | 
					
						
							|  |  |  | 		res = 0; | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid); | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-30 21:29:39 +00:00
										 |  |  | static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
											
												This commits the performance mods that give the priority processing engine in the pbx, a 25-30% speed boost. The two updates used, are, first, to merge the ast_exists_extension() and the ast_spawn_extension() where they are called sequentially in a loop in the code, into a slightly upgraded version of ast_spawn_extension(), with a few extra args; and, second, I modified the substitute_variables_helper_full, so it zeroes out the byte after the evaluated string instead of demanding you pre-zero the buffer; I also went thru the code and removed the code that zeroed this buffer before every call to the substitute_variables_helper_full. The first fix provides about a 9% speedup, and the second the rest. These figures come from the 'PIPS' benchmark I describe in blogs, conf. reports, etc.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88166 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-11-01 22:26:51 +00:00
										 |  |  | 	int found; | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	LOOPBACK_COMMON; | 
					
						
							| 
									
										
										
											
												This commits the performance mods that give the priority processing engine in the pbx, a 25-30% speed boost. The two updates used, are, first, to merge the ast_exists_extension() and the ast_spawn_extension() where they are called sequentially in a loop in the code, into a slightly upgraded version of ast_spawn_extension(), with a few extra args; and, second, I modified the substitute_variables_helper_full, so it zeroes out the byte after the evaluated string instead of demanding you pre-zero the buffer; I also went thru the code and removed the code that zeroed this buffer before every call to the substitute_variables_helper_full. The first fix provides about a 9% speedup, and the second the rest. These figures come from the 'PIPS' benchmark I describe in blogs, conf. reports, etc.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88166 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-11-01 22:26:51 +00:00
										 |  |  | 	res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid, &found, 0); | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	LOOPBACK_COMMON; | 
					
						
							|  |  |  | 	if (newpattern && !ast_extension_match(newpattern, exten)) | 
					
						
							|  |  |  | 		res = 0; | 
					
						
							| 
									
										
										
										
											2014-12-02 17:10:57 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid); | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_switch loopback_switch = | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-04 18:08:28 +00:00
										 |  |  | 	.name			= "Loopback", | 
					
						
							|  |  |  | 	.description		= "Loopback Dialplan Switch", | 
					
						
							|  |  |  | 	.exists			= loopback_exists, | 
					
						
							|  |  |  | 	.canmatch		= loopback_canmatch, | 
					
						
							|  |  |  | 	.exec			= loopback_exec, | 
					
						
							|  |  |  | 	.matchmore		= loopback_matchmore, | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	ast_unregister_switch(&loopback_switch); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-26 20:02:27 +00:00
										 |  |  | 	if (ast_register_switch(&loopback_switch)) | 
					
						
							|  |  |  | 		return AST_MODULE_LOAD_FAILURE; | 
					
						
							|  |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							| 
									
										
										
										
											2004-10-24 03:14:44 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Loopback Switch"); |