[asterisk-commits] murf: trunk r106757 - in /trunk: apps/ channels/ include/asterisk/ main/ pbx/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Mar 7 12:57:57 CST 2008


Author: murf
Date: Fri Mar  7 12:57:57 2008
New Revision: 106757

URL: http://svn.digium.com/view/asterisk?view=rev&rev=106757
Log:
(closes issue #6002)
Reported by: rizzo
Tested by: murf

Proposal of the changes to be made, and then an announcement of how they were accomplished:

http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html

and:

http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html

Here is a recap, file by file, of what I have done:

pbx/pbx_config.c
pbx/pbx_ael.c

All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.

We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.

pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and 
then call merge_contexts_and_delete, which will merge (now) existing contexts and 
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then 
destroy the old dialplan.



chan_sip.c
chan_iax.c
chan_skinny.c

All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.

chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.


apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c

All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.


include/asterisk/pbx.h

ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create()  interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.


include/asterisk/pval.h

ast_compile_ael2() interface changed to include the local hashtab table ptr.


main/features.c

For the sake of the parking context, we use ast_context_find_or_create().



main/pbx.c

I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.

refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.

Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.

Added some calls to ast_verb(3,...) for debug messages

Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.

find_or_create was upgraded to handle both local lists/tables as well as the globals.

context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables

ast_merge_contexts_and_delete() was heavily modified.

ast_add_extension2() was also upgraded to handle changes. 

the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.



res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile

Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps.  The main gotcha was I had to 
include lock.h and hashtab.h in several places.


As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.

How's this for verbose commit messages?



Modified:
    trunk/apps/app_dial.c
    trunk/apps/app_meetme.c
    trunk/apps/app_queue.c
    trunk/channels/chan_iax2.c
    trunk/channels/chan_sip.c
    trunk/channels/chan_skinny.c
    trunk/include/asterisk/pbx.h
    trunk/include/asterisk/pval.h
    trunk/main/features.c
    trunk/main/pbx.c
    trunk/pbx/pbx_ael.c
    trunk/pbx/pbx_config.c
    trunk/res/ael/ael.flex
    trunk/res/ael/ael.tab.c
    trunk/res/ael/ael.tab.h
    trunk/res/ael/ael.y
    trunk/res/ael/ael_lex.c
    trunk/res/ael/pval.c
    trunk/utils/Makefile
    trunk/utils/ael_main.c
    trunk/utils/conf2ael.c
    trunk/utils/extconf.c

Modified: trunk/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_dial.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/apps/app_dial.c (original)
+++ trunk/apps/app_dial.c Fri Mar  7 12:57:57 2008
@@ -2096,9 +2096,7 @@
 	int res;
 	struct ast_context *con;
 
-	con = ast_context_find("app_dial_gosub_virtual_context");
-	if (!con)
-		con = ast_context_create(NULL, "app_dial_gosub_virtual_context", "app_dial");
+	con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
 	if (!con)
 		ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
 	else

Modified: trunk/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_meetme.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/apps/app_meetme.c (original)
+++ trunk/apps/app_meetme.c Fri Mar  7 12:57:57 2008
@@ -5280,7 +5280,7 @@
 
 	if (!ast_strlen_zero(trunk->autocontext)) {
 		struct ast_context *context;
-		context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
+		context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
 		if (!context) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", trunk->autocontext);
@@ -5417,7 +5417,7 @@
 	if (!ast_strlen_zero(station->autocontext)) {
 		struct ast_context *context;
 		struct sla_trunk_ref *trunk_ref;
-		context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
+		context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
 		if (!context) {
 			ast_log(LOG_ERROR, "Failed to automatically find or create "
 				"context '%s' for SLA!\n", station->autocontext);

Modified: trunk/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_queue.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Fri Mar  7 12:57:57 2008
@@ -6147,9 +6147,7 @@
 	if (!reload_queues(0))
 		return AST_MODULE_LOAD_DECLINE;
 
-	con = ast_context_find("app_queue_gosub_virtual_context");
-	if (!con)
-		con = ast_context_create(NULL, "app_queue_gosub_virtual_context", "app_queue");
+	con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
 	if (!con)
 		ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
 	else

Modified: trunk/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_iax2.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/channels/chan_iax2.c (original)
+++ trunk/channels/chan_iax2.c Fri Mar  7 12:57:57 2008
@@ -10771,8 +10771,7 @@
 		} else if (!strcasecmp(v->name, "regcontext")) {
 			ast_copy_string(regcontext, v->value, sizeof(regcontext));
 			/* Create context if it doesn't exist already */
-			if (!ast_context_find(regcontext))
-				ast_context_create(NULL, regcontext, "IAX2");
+			ast_context_find_or_create(NULL, NULL, regcontext, "IAX2");
 		} else if (!strcasecmp(v->name, "tos")) {
 			if (ast_str2tos(v->value, &tos))
 				ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Fri Mar  7 12:57:57 2008
@@ -3388,6 +3388,7 @@
 {
 	char multi[256];
 	char *stringp, *ext, *context;
+	struct pbx_find_info q = { .stacklen = 0 };
 
 	/* XXX note that global_regcontext is both a global 'enable' flag and
 	 * the name of the global regexten context, if not specified
@@ -3408,11 +3409,12 @@
 		} else {
 			context = global_regcontext;
 		}
-		if (onoff)
+		if (onoff) {
 			ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
 				 ast_strdup(peer->name), ast_free_ptr, "SIP");
-		else
+		} else if (pbx_find_extension(NULL, NULL, &q, context, ext, 1, NULL, "", E_MATCH)) {
 			ast_context_remove_extension(context, ext, 1, NULL);
+		}
 	}
 }
 
@@ -20297,8 +20299,7 @@
 			/* Create contexts if they don't exist already */
 			while ((context = strsep(&stringp, "&"))) {
 				ast_copy_string(used_context, context, sizeof(used_context));
-				if (!ast_context_find(context))
-					ast_context_create(NULL, context, "SIP");
+				ast_context_find_or_create(NULL, NULL, context, "SIP");
 			}
 			ast_copy_string(global_regcontext, v->value, sizeof(global_regcontext));
 		} else if (!strcasecmp(v->name, "regextenonqualify")) {

Modified: trunk/channels/chan_skinny.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_skinny.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/channels/chan_skinny.c (original)
+++ trunk/channels/chan_skinny.c Fri Mar  7 12:57:57 2008
@@ -5801,8 +5801,7 @@
 			/* Create contexts if they don't exist already */
 			while ((context = strsep(&stringp, "&"))) {
 				ast_copy_string(used_context, context, sizeof(used_context));
-				if (!ast_context_find(context))
-					ast_context_create(NULL, context, "Skinny");
+				ast_context_find_or_create(NULL, NULL, context, "Skinny");
 			}
 			ast_copy_string(regcontext, v->value, sizeof(regcontext));
 		} else if (!strcasecmp(v->name, "dateformat")) {

Modified: trunk/include/asterisk/pbx.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/pbx.h?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/include/asterisk/pbx.h (original)
+++ trunk/include/asterisk/pbx.h Fri Mar  7 12:57:57 2008
@@ -25,6 +25,7 @@
 
 #include "asterisk/sched.h"
 #include "asterisk/chanvars.h"
+#include "asterisk/hashtab.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
@@ -167,11 +168,16 @@
 int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
 
 /*!
- * \brief Register a new context
+ * \brief Register a new context or find an existing one
  *
  * \param extcontexts pointer to the ast_context structure pointer
+ * \param exttable pointer to the hashtable that contains all the elements in extcontexts
  * \param name name of the new context
  * \param registrar registrar of the context
+ *
+ * This function allows you to play in two environments: the global contexts (active dialplan)
+ * or an external context set of your choosing. To act on the external set, make sure extcontexts
+ * and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.
  *
  * This will first search for a context with your name.  If it exists already, it will not
  * create a new one.  If it does not exist, it will create a new one with the given name
@@ -179,33 +185,19 @@
  *
  * \return NULL on failure, and an ast_context structure on success
  */
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
-
-/*!
- * \brief Register a new context or find an existing one
- *
- * \param extcontexts pointer to the ast_context structure pointer
- * \param name name of the new context
- * \param registrar registrar of the context
- *
- * This will first search for a context with your name.  If it exists already, it will not
- * create a new one.  If it does not exist, it will create a new one with the given name
- * and registrar.
- *
- * \return NULL on failure, and an ast_context structure on success
- */
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar);
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar);
 
 /*!
  * \brief Merge the temporary contexts into a global contexts list and delete from the 
  *        global list the ones that are being added
  *
- * \param extcontexts pointer to the ast_context structure pointer
+ * \param extcontexts pointer to the ast_context structure
+ * \param exttable pointer to the ast_hashtab structure that contains all the elements in extcontexts
  * \param registrar of the context; if it's set the routine will delete all contexts 
  *        that belong to that registrar; if NULL only the contexts that are specified 
  *        in extcontexts
  */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
 
 /*!
  * \brief Destroy a context (matches the specified context (or ANY context if NULL)
@@ -973,8 +965,18 @@
 									 struct ast_context *bypass, struct pbx_find_info *q,
 									 const char *context, const char *exten, int priority,
 									 const char *label, const char *callerid, enum ext_match_t action);
+
+
+/* every time a write lock is obtained for contexts,
+   a counter is incremented. You can check this via the
+   following func */
+
+int ast_wrlock_contexts_version(void);
 	
 
+/* hashtable functions for contexts */
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

Modified: trunk/include/asterisk/pval.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/pval.h?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/include/asterisk/pval.h (original)
+++ trunk/include/asterisk/pval.h Fri Mar  7 12:57:57 2008
@@ -1,6 +1,7 @@
 #ifndef _ASTERISK_PVAL_H
 #define _ASTERISK_PVAL_H
 
+/* whatever includes this, better include asterisk/lock.h and asterisk/hashtab.h */
 
 typedef enum 
 {
@@ -143,7 +144,7 @@
    static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context ); */
 void set_priorities(struct ael_extension *exten);
 void add_extensions(struct ael_extension *exten);
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
 void destroy_pval(pval *item);
 void destroy_pval_item(pval *item);
 int is_float(char *arg );

Modified: trunk/main/features.c
URL: http://svn.digium.com/view/asterisk/trunk/main/features.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/main/features.c (original)
+++ trunk/main/features.c Fri Mar  7 12:57:57 2008
@@ -488,9 +488,7 @@
 		ast_adsi_unload_session(peer);
 	}
 
-	con = ast_context_find(parking_con);
-	if (!con) 
-		con = ast_context_create(NULL, parking_con, registrar);
+	con = ast_context_find_or_create(NULL, NULL, parking_con, registrar);
 	if (!con)	/* Still no context? Bad */
 		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
 	/* Tell the peer channel the number of the parking space */
@@ -2228,12 +2226,9 @@
 						if (peername_flat[i] == '/') 
 							peername_flat[i]= '0';
 					}
-					con = ast_context_find(parking_con_dial);
-					if (!con) {
-						con = ast_context_create(NULL, parking_con_dial, registrar);
-						if (!con)
-							ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
-					}
+					con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
+					if (!con)
+						ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
 					if (con) {
 						char returnexten[AST_MAX_EXTENSION];
 						struct ast_datastore *features_datastore;
@@ -2822,7 +2817,7 @@
 		ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
 	}
 	
-	if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
+	if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) {
 		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
 		return -1;
 	}

Modified: trunk/main/pbx.c
URL: http://svn.digium.com/view/asterisk/trunk/main/pbx.c?view=diff&rev=106757&r1=106756&r2=106757
==============================================================================
--- trunk/main/pbx.c (original)
+++ trunk/main/pbx.c Fri Mar  7 12:57:57 2008
@@ -48,6 +48,7 @@
 #include "asterisk/cdr.h"
 #include "asterisk/config.h"
 #include "asterisk/term.h"
+#include "asterisk/time.h"
 #include "asterisk/manager.h"
 #include "asterisk/ast_expr.h"
 #include "asterisk/linkedlists.h"
@@ -140,8 +141,8 @@
 	void *data;			/*!< Data to use (arguments) */
 	void (*datad)(void *);		/*!< Data destructor */
 	struct ast_exten *peer;		/*!< Next higher priority with our extension */
-	struct ast_hashtab *peer_tree;    /*!< Priorities list in tree form -- only on the head of the peer list */
-	struct ast_hashtab *peer_label_tree; /*!< labeled priorities in the peer list -- only on the head of the peer list */
+	struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
+	struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
 	const char *registrar;		/*!< Registrar */
 	struct ast_exten *next;		/*!< Extension with a greater ID */
 	char stuff[0];
@@ -203,12 +204,13 @@
 struct ast_context {
 	ast_rwlock_t lock; 			/*!< A lock to prevent multiple threads from clobbering the context */
 	struct ast_exten *root;			/*!< The root of the list of extensions */
-	struct ast_hashtab *root_tree;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
+	struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
  	struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
 	struct ast_context *next;		/*!< Link them together */
 	struct ast_include *includes;		/*!< Include other contexts */
 	struct ast_ignorepat *ignorepats;	/*!< Patterns for which to continue playing dialtone */
 	const char *registrar;			/*!< Registrar */
+	int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
 	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;	/*!< Alternative switches */
 	ast_mutex_t macrolock;			/*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
 	char name[0];				/*!< Name of the context */
@@ -327,17 +329,18 @@
 static void create_match_char_tree(struct ast_context *con);
 static struct ast_exten *get_canmatch_exten(struct match_char *node);
 static void destroy_pattern_tree(struct match_char *pattern_tree);
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
-static unsigned int hashtab_hash_contexts(const void *obj);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
 static unsigned int hashtab_hash_extens(const void *obj);
 static unsigned int hashtab_hash_priority(const void *obj);
 static unsigned int hashtab_hash_labels(const void *obj);
+static void __ast_internal_context_destroy( struct ast_context *con);
 
 /* labels, contexts are case sensitive  priority numbers are ints */
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
 {
 	const struct ast_context *ac = ah_a;
 	const struct ast_context *bc = ah_b;
@@ -376,7 +379,7 @@
 	return strcmp(ac->label, bc->label);
 }
 
-static unsigned int hashtab_hash_contexts(const void *obj)
+unsigned int ast_hashtab_hash_contexts(const void *obj)
 {
 	const struct ast_context *ac = obj;
 	return ast_hashtab_hash_string(ac->name);
@@ -684,7 +687,7 @@
 };
 
 static struct ast_context *contexts;
-static struct ast_hashtab *contexts_tree = NULL;
+static struct ast_hashtab *contexts_table = NULL;
 
 AST_RWLOCK_DEFINE_STATIC(conlock); 		/*!< Lock for the ast_context list */
 
@@ -1252,11 +1255,11 @@
 	int biggest_bucket, resizes, numobjs, numbucks;
 	
 	ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
-	ast_hashtab_get_stats(con->root_tree, &biggest_bucket, &resizes, &numobjs, &numbucks);
+	ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
 	ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
 			numobjs, numbucks, biggest_bucket, resizes);
 #endif
-	t1 = ast_hashtab_start_traversal(con->root_tree);
+	t1 = ast_hashtab_start_traversal(con->root_table);
 	while( (e1 = ast_hashtab_next(t1)) ) {
 		if (e1->exten)
 			add_exten_to_pattern_tree(con, e1, 0);
@@ -1582,12 +1585,13 @@
 {
 	ast_rwlock_t lock; 			
 	struct ast_exten *root;		
-	struct ast_hashtab *root_tree;            
+	struct ast_hashtab *root_table;            
 	struct match_char *pattern_tree;       
 	struct ast_context *next;	
 	struct ast_include *includes;		
 	struct ast_ignorepat *ignorepats;	
-	const char *registrar;	
+	const char *registrar;
+	int refcount;
 	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;	
 	ast_mutex_t macrolock;		
 	char name[256];		
@@ -1599,8 +1603,8 @@
 	struct fake_context item;
 	strncpy(item.name,name,256);
 	ast_rdlock_contexts();
-	if( contexts_tree ) {
-		tmp = ast_hashtab_lookup(contexts_tree,&item);
+	if( contexts_table ) {
+		tmp = ast_hashtab_lookup(contexts_table,&item);
 	} else {
 		while ( (tmp = ast_walk_contexts(tmp)) ) {
 			if (!name || !strcasecmp(name, tmp->name))
@@ -1668,7 +1672,7 @@
 	else {	/* look in contexts */
 		struct fake_context item;
 		strncpy(item.name,context,256);
-		tmp = ast_hashtab_lookup(contexts_tree,&item);
+		tmp = ast_hashtab_lookup(contexts_table,&item);
 #ifdef NOTNOW
 		tmp = NULL;
 		while ((tmp = ast_walk_contexts(tmp)) ) {
@@ -1690,7 +1694,7 @@
 	score.total_specificity = 0;
 	score.exten = 0;
 	score.total_length = 0;
-	if (!tmp->pattern_tree && tmp->root_tree)
+	if (!tmp->pattern_tree && tmp->root_table)
 	{
 		create_match_char_tree(tmp);
 #ifdef NEED_DEBUG
@@ -1750,9 +1754,9 @@
 			if (action == E_FINDLABEL && label ) {
 				if (q->status < STATUS_NO_LABEL)
 					q->status = STATUS_NO_LABEL;
-				e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
 			} else {
-				e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
 			}
 			if (e) {	/* found a valid match */
 				q->status = STATUS_SUCCESS;
@@ -1786,9 +1790,9 @@
 			if (action == E_FINDLABEL && label ) {
 				if (q->status < STATUS_NO_LABEL)
 					q->status = STATUS_NO_LABEL;
-				e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
 			} else {
-				e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
 			}
 #ifdef NOTNOW
 			while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
@@ -2465,7 +2469,7 @@
 				vare++;
 			}
 			if (brackets)
-				ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
+				ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
 			len = vare - vars - 1;
 
 			/* Skip totally over variable string */
@@ -2552,7 +2556,7 @@
 				vare++;
 			}
 			if (brackets)
-				ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
+				ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
 			len = vare - vars - 1;
 
 			/* Skip totally over expression */
@@ -3479,14 +3483,14 @@
 	ast_mutex_lock(&maxcalllock);
 	if (option_maxcalls) {
 		if (countcalls >= option_maxcalls) {
-			ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
+			ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
 			failed = -1;
 		}
 	}
 	if (option_maxload) {
 		getloadavg(&curloadavg, 1);
 		if (curloadavg >= option_maxload) {
-			ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
+			ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
 			failed = -1;
 		}
 	}
@@ -3527,10 +3531,10 @@
 	if (e->priority == PRIORITY_HINT)
 		ast_remove_hint(e);
 
-	if (e->peer_tree)
-		ast_hashtab_destroy(e->peer_tree,0);
-	if (e->peer_label_tree)
-		ast_hashtab_destroy(e->peer_label_tree, 0);
+	if (e->peer_table)
+		ast_hashtab_destroy(e->peer_table,0);
+	if (e->peer_label_table)
+		ast_hashtab_destroy(e->peer_label_table, 0);
 	if (e->datad)
 		e->datad(e->data);
 	ast_free(e);
@@ -3627,8 +3631,7 @@
 	ast_copy_string(item.name, context, sizeof(item.name));
 
 	ast_rdlock_contexts();
-
-	c = ast_hashtab_lookup(contexts_tree,&item);
+	c = ast_hashtab_lookup(contexts_table,&item);
 
 #ifdef NOTNOW
 
@@ -3789,19 +3792,19 @@
 	/* Handle this is in the new world */
 
 #ifdef NEED_DEBUG
-	ast_log(LOG_NOTICE,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar);
+	ast_verb(3,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar);
 #endif
 	/* find this particular extension */
 	ex.exten = dummy_name;
 	ex.matchcid = 0;
 	ast_copy_string(dummy_name,extension, sizeof(dummy_name));
-	exten = ast_hashtab_lookup(con->root_tree, &ex);
+	exten = ast_hashtab_lookup(con->root_table, &ex);
 	if (exten) {
 		if (priority == 0)
 		{
-			exten2 = ast_hashtab_remove_this_object(con->root_tree, exten);
+			exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
 			if (!exten2)
-				ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_tree\n", extension, con->name);
+				ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
 			if (con->pattern_tree) {
 				
 				struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
@@ -3815,24 +3818,28 @@
 			}
 		} else {
 			ex.priority = priority;
-			exten2 = ast_hashtab_lookup(exten->peer_tree, &ex);
+			exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
 			if (exten2) {
 				
 				if (exten2->label) { /* if this exten has a label, remove that, too */
-					exten3 = ast_hashtab_remove_this_object(exten->peer_label_tree,exten2);
+					exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
 					if (!exten3)
-						ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_tree of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
+						ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
 				}
 				
-				exten3 = ast_hashtab_remove_this_object(exten->peer_tree, exten2);
+				exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
 				if (!exten3)
-					ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_tree of context %s, extension %s!\n", priority, con->name, exten2->exten);
-				if (ast_hashtab_size(exten->peer_tree) == 0) {
+					ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
+				if (exten2 == exten && exten2->peer) {
+					exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
+					ast_hashtab_insert_immediate(con->root_table, exten2->peer);
+				}
+				if (ast_hashtab_size(exten->peer_table) == 0) {
 					/* well, if the last priority of an exten is to be removed,
 					   then, the extension is removed, too! */
-					exten3 = ast_hashtab_remove_this_object(con->root_tree, exten);
+					exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
 					if (!exten3)
-						ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_tree (%s) (priority %d)\n", exten->exten, con->name, priority);
+						ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
 					if (con->pattern_tree) {
 						struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
 						if (x->exten) { /* this test for safety purposes */
@@ -3848,7 +3855,7 @@
 		}
 	} else {
 		/* hmmm? this exten is not in this pattern tree? */
-		ast_log(LOG_WARNING,"Cannot find extension %s in root_tree in context %s\n",
+		ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
 				extension, con->name);
 	}
 #ifdef NEED_DEBUG
@@ -3905,10 +3912,10 @@
 			 */
 			struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
 			if (next_node && next_node == peer->peer) {
-				next_node->peer_tree = exten->peer_tree; /* move the priority hash tabs over */
-				exten->peer_tree = 0;
-				next_node->peer_label_tree = exten->peer_label_tree;
-				exten->peer_label_tree = 0;
+				next_node->peer_table = exten->peer_table; /* move the priority hash tabs over */
+				exten->peer_table = 0;
+				next_node->peer_label_table = exten->peer_label_table;
+				exten->peer_label_table = 0;
 			}
 			if (!prev_exten) {	/* change the root... */
 				con->root = next_node;
@@ -3946,7 +3953,7 @@
 	ast_rdlock_contexts();
 
 	strncpy(item.name,context,256);
-	c = ast_hashtab_lookup(contexts_tree,&item);
+	c = ast_hashtab_lookup(contexts_table,&item);
 	if (c)
 		ret = 0;
 
@@ -3984,7 +3991,7 @@
 	ast_rdlock_contexts();
 
 	strncpy(item.name, context, 256);
-	c = ast_hashtab_lookup(contexts_tree,&item);
+	c = ast_hashtab_lookup(contexts_table,&item);
 	if (c)
 		ret = 0;
 #ifdef NOTNOW
@@ -4578,7 +4585,7 @@
 			if (exten) {
 				/* Check all includes for the requested extension */
 				if (includecount >= AST_PBX_MAX_STACK) {
-					ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
+					ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
 				} else {
 					int dupe = 0;
 					int x;
@@ -5127,42 +5134,37 @@
 	return tmp ? 0 : -1;
 }
 
-static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
 {
 	struct ast_context *tmp, **local_contexts;
 	struct fake_context search;
 	int length = sizeof(struct ast_context) + strlen(name) + 1;
 
-	if (!contexts_tree) {
-		contexts_tree = ast_hashtab_create(17,
-										   hashtab_compare_contexts, 
+	if (!contexts_table) {
+		contexts_table = ast_hashtab_create(17,
+										   ast_hashtab_compare_contexts, 
 										   ast_hashtab_resize_java,
 										   ast_hashtab_newsize_java,
-										   hashtab_hash_contexts,
+										   ast_hashtab_hash_contexts,
 										   0);
 	}
 	
+	strncpy(search.name,name,sizeof(search.name));
 	if (!extcontexts) {
 		ast_rdlock_contexts();
 		local_contexts = &contexts;
-		strncpy(search.name,name,sizeof(search.name));
-		tmp = ast_hashtab_lookup(contexts_tree, &search);
-		if (!existsokay && tmp) {
-			ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
-		}
+		tmp = ast_hashtab_lookup(contexts_table, &search);
 		ast_unlock_contexts();
-		if (tmp)
+		if (tmp) {
+			tmp->refcount++;
 			return tmp;
+		}
 	} else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
 		local_contexts = extcontexts;
-		for (tmp = *local_contexts; tmp; tmp = tmp->next) {
-			if (!strcasecmp(tmp->name, name)) {
-				if (!existsokay) {
-					ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
-					tmp = NULL;
-				}
-				return tmp;
-			}
+		tmp = ast_hashtab_lookup(exttable, &search);
+		if (tmp) {
+			tmp->refcount++;
+			return tmp;
 		}
 	}
 	
@@ -5171,19 +5173,26 @@
 		ast_mutex_init(&tmp->macrolock);
 		strcpy(tmp->name, name);
 		tmp->root = NULL;
-		tmp->root_tree = NULL;
+		tmp->root_table = NULL;
 		tmp->registrar = registrar;
 		tmp->includes = NULL;
 		tmp->ignorepats = NULL;
-	}
+		tmp->refcount = 1;
+	} else {
+		ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
+		return NULL;
+	}
+	
 	if (!extcontexts) {
 		ast_wrlock_contexts();
 		tmp->next = *local_contexts;
 		*local_contexts = tmp;
-		ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
+		ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
 		ast_unlock_contexts();
 	} else {
 		tmp->next = *local_contexts;
+		if (exttable)
+			ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
 		*local_contexts = tmp;
 	}
 	ast_debug(1, "Registered context '%s'\n", tmp->name);
@@ -5191,16 +5200,7 @@
 	return tmp;
 }
 
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-	return __ast_context_create(extcontexts, name, registrar, 0);
-}
-
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-	return __ast_context_create(extcontexts, name, registrar, 1);
-}
-void __ast_context_destroy(struct ast_context *con, const char *registrar);
+void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
 
 struct store_hint {
 	char *context;
@@ -5213,17 +5213,89 @@
 
 AST_LIST_HEAD(store_hints, store_hint);
 
+/* the purpose of this routine is to duplicate a context, with all its substructure,
+   except for any extens that have a matching registrar */
+static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
+{
+	struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
+	struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
+	struct ast_hashtab_iter *exten_iter;
+	struct ast_hashtab_iter *prio_iter;
+	int insert_count = 0;
+	
+	/* We'll traverse all the extensions/prios, and see which are not registrar'd with
+	   the current registrar, and copy them to the new context. If the new context does not
+	   exist, we'll create it "on demand". If no items are in this context to copy, then we'll
+	   only create the empty matching context if the old one meets the criteria */
+	if (context->root_table) {
+		exten_iter = ast_hashtab_start_traversal(context->root_table);
+		while ((exten_item=ast_hashtab_next(exten_iter))) {
+			if (new) {
+				new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
+			} else {
+				new_exten_item = NULL;
+			}
+			prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
+			while ((prio_item=ast_hashtab_next(prio_iter))) {
+				int res1;
+				
+				if (new_exten_item) {
+					new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
+				} else {
+					new_prio_item = NULL;
+				}
+				if (strcmp(prio_item->registrar,registrar) == 0) {
+					continue;
+				}
+				/* make sure the new context exists, so we have somewhere to stick this exten/prio */
+				if (!new) {
+					new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
+				}
+				if (!new) {
+					ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
+					return; /* no sense continuing. */
+				}
+				/* we will not replace existing entries in the new context with stuff from the old context.
+				   but, if this is because of some sort of registrar conflict, we ought to say something... */
+				res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
+										  prio_item->cidmatch, prio_item->app, prio_item->data, prio_item->datad, prio_item->registrar);
+				if (!res1 && new_exten_item && new_prio_item){
+					ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
+							context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
+				} else {
+					prio_item->data = NULL; /* we pass the priority data from the old to the new */
+					insert_count++;
+				}
+			}
+			ast_hashtab_end_traversal(prio_iter);
+		}
+		ast_hashtab_end_traversal(exten_iter);
+	}
+	
+	if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
+		  (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
+		
+		/* we could have given it the registrar of the other module who incremented the refcount,
+		   but that's not available, so we give it the registrar we know about */
+		new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
+	}
+}
+
+
 /* XXX this does not check that multiple contexts are merged */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
-{
-	struct ast_context *tmp, *lasttmp = NULL;
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
+{
+	double ft;
+	struct ast_context *tmp, *oldcontextslist;
+	struct ast_hashtab *oldtable;
 	struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
 	struct store_hint *this;
 	struct ast_hint *hint;
 	struct ast_exten *exten;
 	int length;
 	struct ast_state_cb *thiscb, *prevcb;
-
+	struct ast_hashtab_iter *iter;
+	

[... 4441 lines stripped ...]



More information about the asterisk-commits mailing list