From 8e90425a6c67a22ceafc1326271a28acb33c7a41 Mon Sep 17 00:00:00 2001
From: Steve Murphy <murf@digium.com>
Date: Wed, 21 Nov 2007 01:09:47 +0000
Subject: [PATCH] A free in add_pri was ultimately the source of the grief we
 were having with parking. This set of changes fixes that problem, and
 introduces some more error messages, and puts debugs into ifdefs for what
 could be short-term usage. Txs to Terry W. for his help, guidance, and
 especially patience.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89474 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 main/pbx.c | 99 ++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 78 insertions(+), 21 deletions(-)

diff --git a/main/pbx.c b/main/pbx.c
index 62994c7f8b..a61d907923 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -324,6 +324,7 @@ struct match_char *already_in_tree(struct match_char *current, char *pat);
 struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly);
 struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity);
 void create_match_char_tree(struct ast_context *con);
+void log_match_char_tree(struct match_char *node, char *prefix);
 struct ast_exten *get_canmatch_exten(struct match_char *node);
 void destroy_pattern_tree(struct match_char *pattern_tree);
 static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
@@ -851,28 +852,40 @@ static void update_scoreboard(struct scoreboard *board, int length, int spec, st
 	}
 }
 
-#ifdef NEED_DEBUG
-static void log_match_char_tree(struct match_char *node, char *prefix)
+void log_match_char_tree(struct match_char *node, char *prefix)
 {
 	char my_prefix[1024];
+	char extenstr[40];
+	
+	extenstr[0] = 0;
+	if (node && node->exten && node->exten)
+		sprintf(extenstr,"(%x)",(unsigned int)node->exten);
 	
-	ast_log(LOG_DEBUG,"%s%s:%c:%d:%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->specificity, node->exten? "EXTEN":"");
+	if (strlen(node->x) > 1 )
+		ast_log(LOG_DEBUG,"%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
+	else
+		ast_log(LOG_DEBUG,"%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
 	strcpy(my_prefix,prefix);
 	strcat(my_prefix,"+       ");
 	if (node->next_char)
-		print_match_char_tree(node->next_char, my_prefix);
+		log_match_char_tree(node->next_char, my_prefix);
 	if (node->alt_char)
-		print_match_char_tree(node->alt_char, prefix);
+		log_match_char_tree(node->alt_char, prefix);
 }
-#endif
 
 static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
 {
 	char my_prefix[1024];
-	if (strlen(node->x) > 1 )
-		ast_cli(fd, "%s[%s]:%c:%d:%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "");
+	char extenstr[40];
+	
+	extenstr[0] = 0;
+	if (node && node->exten && node->exten)
+		sprintf(extenstr,"(%x)",(unsigned int)node->exten);
+	
+	if (strlen(node->x) > 1)
+		ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
 	else
-		ast_cli(fd, "%s%s:%c:%d:%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "");
+		ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:":"", node->exten ? node->exten->exten : "", extenstr);
 	strcpy(my_prefix,prefix);
 	strcat(my_prefix,"+       ");
 	if (node->next_char)
@@ -1153,9 +1166,11 @@ struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast
 		}
 		m2 = 0;
 		if (already && (m2=already_in_tree(m1,buf)) && m2->next_char) {
-			if (!(*(s1+1)))  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
+			if (!(*(s1+1))) {  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
 								a shorter pattern might win if the longer one doesn't match */
 				m2->exten = e1;
+				m2->deleted = 0;
+			}
 			m1 = m2->next_char; /* m1 points to the node to compare against */
 		} else {
 			if (m2) {
@@ -1168,8 +1183,11 @@ struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast
 				m1 = add_pattern_node(con, m1, buf, pattern, already,specif); /* m1 is the node just added */
 			}
 			
-			if (!(*(s1+1)))
+			if (!(*(s1+1))) {
+				m1->deleted = 0;
 				m1->exten = e1;
+			}
+			
 			already = 0;
 		}
 		s1++; /* advance to next char */
@@ -1565,7 +1583,9 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 
 	pattern.label = label;
 	pattern.priority = priority;
-
+#ifdef NEED_DEBUG
+	ast_log(LOG_NOTICE,"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int)action);
+#endif
 	/* Initialize status if appropriate */
 	if (q->stacklen == 0) {
 		q->status = STATUS_NO_CONTEXT;
@@ -1615,10 +1635,13 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 		create_match_char_tree(tmp);
 #ifdef NEED_DEBUG
 		ast_log(LOG_DEBUG,"Tree Created in context %s:\n", context);
-		print_match_char_tree(tmp->pattern_tree," ");
+		log_match_char_tree(tmp->pattern_tree," ");
 #endif
 	}
-	
+#ifdef NEED_DEBUG
+	ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
+	log_match_char_tree(tmp->pattern_tree, "::  ");
+#endif	
 	new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid);
 	eroot = score.exten;
 
@@ -3647,9 +3670,13 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
 	/* Handle this is in the new world */
 
 	if (con->pattern_tree) {
-		/* find this particular extension */
-		struct ast_exten ex, *exten2;
+		struct ast_exten ex, *exten2, *exten3;
 		char dummy_name[1024];
+
+#ifdef NEED_DEBUG
+		ast_log(LOG_NOTICE,"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));
@@ -3662,7 +3689,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
 				if (x->exten) { /* this test for safety purposes */
 					x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
 					x->exten = 0; /* get rid of what will become a bad pointer */
-					ast_hashtab_remove_this_object(con->root_tree, exten);
+					exten2 = ast_hashtab_remove_this_object(con->root_tree, exten);
 				} else {
 					ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
 				}
@@ -3670,9 +3697,16 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
 				ex.priority = priority;
 				exten2 = ast_hashtab_lookup(exten->peer_tree, &ex);
 				if (exten2) {
-					if (exten2->label) /* if this exten has a label, remove that, too */
-						ast_hashtab_remove_this_object(exten->peer_label_tree,exten2);
-					ast_hashtab_remove_this_object(exten->peer_tree, exten2);
+					
+					if (exten2->label) { /* if this exten has a label, remove that, too */
+						exten3 = ast_hashtab_remove_this_object(exten->peer_label_tree,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);
+					}
+							
+					exten3 = ast_hashtab_remove_this_object(exten->peer_tree, 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) {
 						/* well, if the last priority of an exten is to be removed,
 						   then, the extension is removed, too! */
@@ -3680,7 +3714,9 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
 						if (x->exten) { /* this test for safety purposes */
 							x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
 							x->exten = 0; /* get rid of what will become a bad pointer */
-							ast_hashtab_remove_this_object(con->root_tree, exten);
+							exten3 = ast_hashtab_remove_this_object(con->root_tree, 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);
 						}
 					}
 				} else {
@@ -3693,6 +3729,10 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
 			ast_log(LOG_WARNING,"Cannot find extension %s in pattern tree in context %s\n",
 					extension, con->name);
 		}
+#ifdef NEED_DEBUG
+		ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
+		log_match_char_tree(con->pattern_tree, " ");
+#endif
 	}
 	
 
@@ -5666,6 +5706,7 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 				ast_hashtab_insert_safe(eh->peer_label_tree,tmp);
 			ep->peer = tmp;
 		} else if (el) {		/* We're the first extension. Take over e's functions */
+			struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
 			tmp->peer_tree = e->peer_tree;
 			tmp->peer_label_tree = e->peer_label_tree;
 			ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
@@ -5677,7 +5718,16 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 			ast_hashtab_remove_object_via_lookup(con->root_tree, e);
 			ast_hashtab_insert_safe(con->root_tree, tmp);
 			el->next = tmp;
+			/* The pattern trie points to this exten; replace the pointer,
+			   and all will be well */
+			
+			if (x->exten) { /* this test for safety purposes */
+				x->exten = tmp; /* replace what would become a bad pointer */
+			} else {
+				ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
+			}
 		} else {			/* We're the very first extension.  */
+			struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
 			ast_hashtab_remove_object_via_lookup(con->root_tree,e);
 			ast_hashtab_insert_safe(con->root_tree,tmp);
 			tmp->peer_tree = e->peer_tree;
@@ -5691,6 +5741,13 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
 			ast_hashtab_remove_object_via_lookup(con->root_tree, e);
 			ast_hashtab_insert_safe(con->root_tree, tmp);
  			con->root = tmp;
+			/* The pattern trie points to this exten; replace the pointer,
+			   and all will be well */
+			if (x->exten) { /* this test for safety purposes */
+				x->exten = tmp; /* replace what would become a bad pointer */
+			} else {
+				ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
+			}
 		}
 		if (tmp->priority == PRIORITY_HINT)
 			ast_change_hint(e,tmp);
-- 
GitLab