[svn-commits] murf: branch 1.6.0 r130946 - in /branches/1.6.0: ./ apps/ channels/ include/a...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 15 08:14:08 CDT 2008


Author: murf
Date: Tue Jul 15 08:14:07 2008
New Revision: 130946

URL: http://svn.digium.com/view/asterisk?view=rev&rev=130946
Log:
Merged revisions 130145 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

Merging this rev from trunk to 1.6.0 was not
simple. Why? Because we've enhanced trunk to
do a [fast] merge-and-delete operation which 
also solved problems with contexts having 
entries from different registrars.
Fast as in the amount of time the contexts
are locked down. That *is* fast, but traversing
the entire dialplan looking for priorities to
delete takes more time overall.
This particular fix involved pulling in those
enhancements from trunk, along with all the
various fixes and refinements made along the
way.

Merging all this from trunk into 1.6 involved:
a. mergetrunk6 in the stuff from 130145;
b. revert all but the prop changes
c. catalog all revisions to pbx.c since 1.6.0 was forked
   (at rev 105596).
d. catalog all revisions to pbx.c in trunk since 1.6.0
   was forked, making special note of all revs that
   were not merged into 1.6.0.
e. study each rev in trunk not applied to 1.6.0, and
   determine if it was involved in the merge_and_delete
   enhancements in trunk. 25 commits were done in 1.6.0,
   all but one (106306) was a merge from trunk.
   Trunk had 22 additional changes, of which 7 were
   involved in the merge_and_delete enhancements:
    106757
    108894
    109169
    116461
    123358
    130145
    130297
f. Go to trunk and collect patches, one by one,
   of the changes made by each rev across the
   entire source tree, using svn diff -c <num> > pfile
g. Apply each patch in order to 1.6.0, and 
   resolve all failures and compilation problems
   before proceding to the next patch.
h. test the stuff.
i. profit!


........
r130145 | murf | 2008-07-11 12:24:31 -0600 (Fri, 11 Jul 2008) | 40 lines

(closes issue #13041)
Reported by: eliel
Tested by: murf

(closes issue #12960)
Reported by: mnicholson

In this 'omnibus' fix, I **think** I solved both
the problem in 13041, where unloading pbx_ael.so
caused crashes, or incomplete removal of previous
registrar'ed entries. And I added code to completely
remove all includes, switches, and ignorepats that
had a matching registrar entry, which should
appease 12960.

I also added a lot of seemingly useless brackets
around single statement if's, which helped debug 
so much that I'm leaving them there.

I added a routine to check the correlation between
the extension tree lists and the hashtab 
tables. It can be amazingly helpful when you have
lots of dialplan stuff, and need to narrow
down where a problem is occurring. It's ifdef'd
out by default.

I cleaned up the code around the new CIDmatch code.
It was leaving hanging extens with bad ptrs, getting confused
over which objects to remove, etc. I tightened
up the code and changed the call to remove_exten
in the merge_and_delete code.

I added more conditions to check for empty context
worthy of deletion. It's not empty if there are
any includes, switches, or ignorepats present.

If I've missed anything, please re-open this bug,
and be prepared to supply example dialplan code.


........

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

Propchange: branches/1.6.0/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.0/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/apps/app_dial.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/apps/app_dial.c (original)
+++ branches/1.6.0/apps/app_dial.c Tue Jul 15 08:14:07 2008
@@ -2084,9 +2084,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: branches/1.6.0/apps/app_meetme.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/apps/app_meetme.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/apps/app_meetme.c (original)
+++ branches/1.6.0/apps/app_meetme.c Tue Jul 15 08:14:07 2008
@@ -5298,7 +5298,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);
@@ -5435,7 +5435,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: branches/1.6.0/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/apps/app_queue.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/apps/app_queue.c (original)
+++ branches/1.6.0/apps/app_queue.c Tue Jul 15 08:14:07 2008
@@ -6368,9 +6368,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: branches/1.6.0/apps/app_stack.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/apps/app_stack.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/apps/app_stack.c (original)
+++ branches/1.6.0/apps/app_stack.c Tue Jul 15 08:14:07 2008
@@ -520,7 +520,7 @@
 	}
 
 	if (agi_loaded) {
-		con = ast_context_find_or_create(NULL, "app_stack_gosub_virtual_context", "app_stack");
+		con = ast_context_find_or_create(NULL, NULL, "app_stack_gosub_virtual_context", "app_stack");
 		if (!con) {
 			ast_log(LOG_ERROR, "Virtual context 'app_stack_gosub_virtual_context' does not exist and unable to create\n");
 			return AST_MODULE_LOAD_DECLINE;

Modified: branches/1.6.0/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/channels/chan_iax2.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/channels/chan_iax2.c (original)
+++ branches/1.6.0/channels/chan_iax2.c Tue Jul 15 08:14:07 2008
@@ -11023,8 +11023,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: branches/1.6.0/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/channels/chan_sip.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/channels/chan_sip.c (original)
+++ branches/1.6.0/channels/chan_sip.c Tue Jul 15 08:14:07 2008
@@ -3441,6 +3441,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
@@ -3461,11 +3462,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);
+		}
 	}
 }
 
@@ -20616,8 +20618,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: branches/1.6.0/channels/chan_skinny.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/channels/chan_skinny.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/channels/chan_skinny.c (original)
+++ branches/1.6.0/channels/chan_skinny.c Tue Jul 15 08:14:07 2008
@@ -5913,8 +5913,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: branches/1.6.0/include/asterisk/pbx.h
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/include/asterisk/pbx.h?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/include/asterisk/pbx.h (original)
+++ branches/1.6.0/include/asterisk/pbx.h Tue Jul 15 08:14:07 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)
@@ -775,6 +767,8 @@
 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip);
 const char *ast_get_switch_name(struct ast_sw *sw);
 const char *ast_get_switch_data(struct ast_sw *sw);
+int ast_get_switch_eval(struct ast_sw *sw);
+	
 /*! @} */
 
 /*! @name Other Extension stuff */
@@ -997,8 +991,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: branches/1.6.0/include/asterisk/pval.h
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/include/asterisk/pval.h?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/include/asterisk/pval.h (original)
+++ branches/1.6.0/include/asterisk/pval.h Tue Jul 15 08:14:07 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: branches/1.6.0/main/features.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/main/features.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/main/features.c (original)
+++ branches/1.6.0/main/features.c Tue Jul 15 08:14:07 2008
@@ -490,9 +490,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 */
@@ -2205,12 +2203,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;
@@ -2799,7 +2794,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: branches/1.6.0/main/pbx.c
URL: http://svn.digium.com/view/asterisk/branches/1.6.0/main/pbx.c?view=diff&rev=130946&r1=130945&r2=130946
==============================================================================
--- branches/1.6.0/main/pbx.c (original)
+++ branches/1.6.0/main/pbx.c Tue Jul 15 08:14:07 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"
@@ -142,8 +143,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];
@@ -204,12 +205,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 */
+	char *registrar;			/*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
+	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 */
@@ -329,14 +331,15 @@
 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);
 
 /* a func for qsort to use to sort a char array */
 static int compare_char(const void *a, const void *b)
@@ -352,7 +355,7 @@
 }
 
 /* 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;
@@ -365,8 +368,10 @@
 	const struct ast_exten *ac = ah_a;
 	const struct ast_exten *bc = ah_b;
 	int x = strcmp(ac->exten, bc->exten);
-	if (x) /* if exten names are diff, then return */
+	if (x) { /* if exten names are diff, then return */
 		return x;
+	}
+	
 	/* but if they are the same, do the cidmatch values match? */
 	if (ac->matchcid && bc->matchcid) {
 		return strcmp(ac->cidmatch,bc->cidmatch);
@@ -391,7 +396,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);
@@ -708,7 +713,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 */
 
@@ -725,6 +730,185 @@
 */
 static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
 struct ast_state_cb *statecbs;
+
+#ifdef CONTEXT_DEBUG
+
+/* these routines are provided for doing run-time checks
+   on the extension structures, in case you are having
+   problems, this routine might help you localize where
+   the problem is occurring. It's kinda like a debug memory
+   allocator's arena checker... It'll eat up your cpu cycles!
+   but you'll see, if you call it in the right places,
+   right where your problems began...
+*/
+
+/* you can break on the check_contexts_trouble()
+routine in your debugger to stop at the moment
+there's a problem */
+void check_contexts_trouble(void);
+
+void check_contexts_trouble(void)
+{
+	int x = 1;
+	x = 2;
+}
+
+static struct ast_context *find_context_locked(const char *context);
+int check_contexts(char *, int);
+
+int check_contexts(char *file, int line )
+{
+	struct ast_hashtab_iter *t1;
+	struct ast_context *c1, *c2;
+	int found = 0;
+	struct ast_exten *e1, *e2, *e3;
+	struct ast_exten ex;
+	
+	/* try to find inconsistencies */
+	/* is every context in the context table in the context list and vice-versa ? */
+	
+	if (!contexts_table) {
+		ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
+		usleep(500000);
+	}
+
+	t1 = ast_hashtab_start_traversal(contexts_table);
+	while( (c1 = ast_hashtab_next(t1))) {
+		for(c2=contexts;c2;c2=c2->next) {
+			if (!strcmp(c1->name, c2->name)) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
+			check_contexts_trouble();
+		}
+	}
+	ast_hashtab_end_traversal(t1);
+	for(c2=contexts;c2;c2=c2->next) {
+		c1 = find_context_locked(c2->name);
+		if (!c1) {
+			ast_log(LOG_NOTICE,"Could not find the %s context in the hashtab\n", c2->name);
+			check_contexts_trouble();
+		} else
+			ast_unlock_contexts();
+	}
+
+	/* loop thru all contexts, and verify the exten structure compares to the 
+	   hashtab structure */
+	for(c2=contexts;c2;c2=c2->next) {
+		c1 = find_context_locked(c2->name);
+		if (c1)
+		{
+
+			ast_unlock_contexts();
+
+			/* is every entry in the root list also in the root_table? */
+			for(e1 = c1->root; e1; e1=e1->next)
+			{
+				char dummy_name[1024];
+				ex.exten = dummy_name;
+				ex.matchcid = e1->matchcid;
+				ex.cidmatch = e1->cidmatch;
+				ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
+				e2 = ast_hashtab_lookup(c1->root_table, &ex);
+				if (!e2) {
+					if (e1->matchcid) {
+						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
+					} else {
+						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
+					}
+					check_contexts_trouble();
+				}
+			}
+			
+			/* is every entry in the root_table also in the root list? */ 
+			if (!c2->root_table) {
+				if (c2->root) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
+					usleep(500000);
+				}
+			} else {
+				t1 = ast_hashtab_start_traversal(c2->root_table);
+				while( (e2 = ast_hashtab_next(t1)) ) {
+					for(e1=c2->root;e1;e1=e1->next) {
+						if (!strcmp(e1->exten, e2->exten)) {
+							found = 1;
+							break;
+						}
+					}
+					if (!found) {
+						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
+						check_contexts_trouble();
+					}
+					
+				}
+				ast_hashtab_end_traversal(t1);
+			}
+		}
+		/* is every priority reflected in the peer_table at the head of the list? */
+		
+		/* is every entry in the root list also in the root_table? */
+		/* are the per-extension peer_tables in the right place? */
+
+		for(e1 = c2->root; e1; e1 = e1->next) {
+			
+			for(e2=e1;e2;e2=e2->peer) {
+				ex.priority = e2->priority;
+				if (e2 != e1 && e2->peer_table) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+				if (e2 != e1 && e2->peer_label_table) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+				if (e2 == e1 && !e2->peer_table){
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+				if (e2 == e1 && !e2->peer_label_table) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+				
+
+				e3 = ast_hashtab_lookup(e1->peer_table, &ex);
+				if (!e3) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+			}
+			
+			if (!e1->peer_table){
+				ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
+				usleep(500000);
+			}
+			
+			/* is every entry in the peer_table also in the peer list? */ 
+			t1 = ast_hashtab_start_traversal(e1->peer_table);
+			while( (e2 = ast_hashtab_next(t1)) ) {
+				for(e3=e1;e3;e3=e3->peer) {
+					if (e3->priority == e2->priority) {
+						found = 1;
+						break;
+					}
+				}
+				if (!found) {
+					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
+					check_contexts_trouble();
+				}
+			}
+			ast_hashtab_end_traversal(t1);
+		}
+	}
+	return 0;
+}
+#endif
 
 /*
    \note This function is special. It saves the stack so that no matter
@@ -1044,7 +1228,7 @@
 						update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);                 \
 						if (!p->deleted) {                                                                                           \
 							if (action == E_FINDLABEL) {                                                                             \
-								if (ast_hashtab_lookup(score->exten->peer_label_tree, &pattern)) {                                   \
+								if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) {                                   \
 									ast_debug(4, "Found label in preferred extension\n");                                            \
 									return;                                                                                          \
 								}                                                                                                    \
@@ -1392,11 +1576,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);
@@ -1787,12 +1971,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];		
@@ -1804,8 +1989,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))
@@ -1874,7 +2059,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)) ) {
@@ -1896,7 +2081,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
@@ -1966,9 +2151,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;
@@ -2002,9 +2187,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)) ) {
@@ -2686,7 +2871,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 */
@@ -2773,7 +2958,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 */
@@ -3689,14 +3874,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;
 		}
 	}
@@ -3737,10 +3922,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);
@@ -3837,8 +4022,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
 
@@ -4017,18 +4201,20 @@
 #ifdef NEED_DEBUG
 	ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcid ? "/" : "", matchcid ? callerid : "", registrar);
 #endif
+#ifdef CONTEXT_DEBUG
+	check_contexts(__FILE__, __LINE__);
+#endif
 	/* find this particular extension */
 	ex.exten = dummy_name;
-	ex.matchcid = matchcid;
+	ex.matchcid = matchcid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
 	ex.cidmatch = callerid;
 	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);
+		if (priority == 0) {
+			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);
@@ -4042,24 +4228,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 */
@@ -4075,7 +4265,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
@@ -4088,7 +4278,8 @@
 	/* scan the extension list to find first matching extension-registrar */
 	for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
 		if (!strcmp(exten->exten, extension) &&
-			(!registrar || !strcmp(exten->registrar, registrar)))
+			(!registrar || !strcmp(exten->registrar, registrar)) &&
+			(!matchcid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
 			break;
 	}
 	if (!exten) {
@@ -4100,7 +4291,7 @@
 
 	/* scan the priority list to remove extension with exten->priority == priority */
 	for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;

[... 4843 lines stripped ...]



More information about the svn-commits mailing list