[asterisk-commits] murf: branch murf/bug11210 r94807 - /team/murf/bug11210/channels/chan_sip.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Dec 26 14:24:28 CST 2007


Author: murf
Date: Wed Dec 26 14:24:27 2007
New Revision: 94807

URL: http://svn.digium.com/view/asterisk?view=rev&rev=94807
Log:
Seems only practical that this code survive a 'sip reload' without a crash. And, I temporarily rewrote find_call to use rizzo's callback-linear-search approach when pedantic is turned on.

Modified:
    team/murf/bug11210/channels/chan_sip.c

Modified: team/murf/bug11210/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/channels/chan_sip.c?view=diff&rev=94807&r1=94806&r2=94807
==============================================================================
--- team/murf/bug11210/channels/chan_sip.c (original)
+++ team/murf/bug11210/channels/chan_sip.c Wed Dec 26 14:24:27 2007
@@ -3256,7 +3256,6 @@
 	if (peer->dnsmgr)
 		ast_dnsmgr_release(peer->dnsmgr);
 	clear_peer_mailboxes(peer);
-	ast_free(peer);
 }
 
 /*! \brief Update peer data in database (if used) */
@@ -3557,7 +3556,6 @@
 		ruserobjs--;
 	else
 		suserobjs--;
-	ast_free(user);
 }
 
 /*! \brief Load user from realtime storage
@@ -4084,7 +4082,7 @@
 		p->packets = p->packets->next;
 		if (cp->retransid > -1) {
 			ast_log(LOG_WARNING,"About to sched_del retransid(%d) in __sip_destroy\n", cp->retransid);
-			ast_sched_del(sched, cp->retransid); /* HUH??? */
+			ast_sched_del(sched, cp->retransid); /* HUH??? well, ok, sip_pkt's are not refcounted objects */
 		}
 		
 		cp->owner = dialog_unref(cp->owner,"free cp->owner dialog before freeing the pkt");
@@ -4099,8 +4097,6 @@
 	ast_string_field_free_memory(p);
 	
 	ast_log(LOG_NOTICE,"Destroying dialog;\n");
-	
-	ast_free(p);
 }
 
 /*! \brief  update_call_counter: Handle call_limit for SIP users 
@@ -5523,6 +5519,57 @@
 	return p;
 }
 
+/*! \brief argument to the helper function to identify a call */
+struct find_call_cb_arg {
+	enum sipmethod method;
+	const char *callid;
+	const char *fromtag;
+	const char *totag;
+	const char *tag;
+};
+
+/*!
+ * code to determine whether this is the pvt that we are looking for.
+ * Return FALSE if not found, true otherwise. p is unlocked.
+ */
+static int find_call_cb(void *__p, void *__arg, int flags)
+{
+	struct sip_pvt *p = __p;
+	struct find_call_cb_arg *arg = __arg;
+	/* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
+	int found = FALSE;
+	static int prof_id = -1;
+	if (prof_id == -1)
+		prof_id = ast_add_profile("find_call_cb", 0);
+	
+	ast_mark(prof_id, 1);
+	if (!ast_strlen_zero(p->callid)) { /* XXX double check, do we allow match on empty p->callid ? */
+		if (arg->method == SIP_REGISTER)
+ 	  	  	found = (!strcmp(p->callid, arg->callid));
+		else
+ 	  	  	found = (!strcmp(p->callid, arg->callid) &&
+					 (!pedanticsipchecking || !arg->tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, arg->tag))) ;
+		
+		ast_debug(5, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
+		
+		/* If we get a new request within an existing to-tag - check the to tag as well */
+		if (pedanticsipchecking && found && arg->method != SIP_RESPONSE) { /* SIP Request */
+ 	  	  	if (p->tag[0] == '\0' && arg->totag[0]) {
+				/* We have no to tag, but they have. Wrong dialog */
+				found = FALSE;
+  	  	  	} else if (arg->totag[0]) { /* Both have tags, compare them */
+				if (strcmp(arg->totag, p->tag)) {
+					found = FALSE; /* This is not our packet */
+				}
+			}
+			if (!found)
+				ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, arg->totag, sip_methods[arg->method].text);
+		}
+	}
+	ast_mark(prof_id, 0);
+ 	return found;
+}
+
 /*! \brief find or create a dialog structure for an incoming SIP message.
  * Connect incoming SIP message to current dialog or create new dialog structure
  * Returns a reference to the sip_pvt object, remember to give it back once done.
@@ -5534,17 +5581,38 @@
 	char *tag = "";	/* note, tag is never NULL */
 	char totag[128];
 	char fromtag[128];
+	struct find_call_cb_arg arg;
 	const char *callid = get_header(req, "Call-ID");
 	const char *from = get_header(req, "From");
 	const char *to = get_header(req, "To");
 	const char *cseq = get_header(req, "Cseq");
 	struct sip_pvt tmp_dialog, *sip_pvt_ptr;
 
+	static int prof_head = -1, prof_find = -1, prof_tail = -1;
+	if (prof_head == -1) {
+		prof_head = ast_add_profile("find_call-headers", 0);
+		prof_find = ast_add_profile("find_call-find", 0);
+		prof_tail = ast_add_profile("find_call-tail", 0);
+	}
+	ast_mark(prof_head, 1);
+
+	callid = get_header(req, "Call-ID");
+	from = get_header(req, "From");
+	to = get_header(req, "To");
+	cseq = get_header(req, "Cseq");
+	ast_mark(prof_head, 0);
+
 	/* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
 	/* get_header always returns non-NULL so we must use ast_strlen_zero() */
 	if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
 			ast_strlen_zero(from) || ast_strlen_zero(cseq))
 		return NULL;	/* Invalid packet */
+
+	arg.method = req->method;
+	arg.callid = callid;
+	arg.fromtag = fromtag;
+	arg.totag = totag;
+	arg.tag = ""; /* make sure tag is never NULL */
 
 	if (pedanticsipchecking) {
 		/* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
@@ -5572,67 +5640,53 @@
 			return NULL;
 		}
 	}
+
+	ast_mark(prof_find, 1);
+
+	if (!pedanticsipchecking) {
+		if (!ast_string_field_init(&tmp_dialog, 100)) {
+			int rc;
+			ast_string_field_set(&tmp_dialog, callid, callid);
+			
+			sip_pvt_ptr = ao2_find(dialogs, &tmp_dialog, OBJ_POINTER, "ao2_find in dialogs");
+			if (sip_pvt_ptr) {
+				rc = ao2_ref(sip_pvt_ptr,0,"");
+				ast_log(LOG_NOTICE,"Found CALL dialog %s, refcount = %d\n", tmp_dialog.callid, rc);
+			}
+			
+			if (!sip_pvt_ptr) {
+				struct ao2_iterator i;
+				struct sip_pvt *d2;
+				
+				ast_log(LOG_NOTICE,"Dialog %s not found\n", callid);
+				i = ao2_iterator_init(dialogs, 0);
+				
+				while ((d2 = ao2_iterator_next(&i,"iterate thru dialogs "))) {
+					ast_log(LOG_NOTICE, "Dialogs:  %s\n", d2->callid);
+					ao2_ref(d2,-1,"done with d2 pointer");
+				}
+			}
+			ast_string_field_free_memory(&tmp_dialog);
+			if (sip_pvt_ptr) {  /* well, if we don't find it-- what IS in there? */
+				/* Found the call */
+				sip_pvt_lock(sip_pvt_ptr);
+				dialoglist_unlock();
+				return sip_pvt_ptr;
+			}
+		} else { /* in pedantic mode! -- do the fancy linear search */
+			p = ao2_callback(dialogs, 0 /* single, data */, find_call_cb, &arg, "pedantic linear search for dialog");
+			if (p) {
+                sip_pvt_lock(p);
+                ast_mark(prof_find, 0);
+                return p;
+			}
+		}
+		
+	}
+	ast_mark(prof_find, 0);
 	
-	dialoglist_lock();
-	if (!ast_string_field_init(&tmp_dialog, 100)) {
-		int rc;
-		ast_string_field_set(&tmp_dialog, callid, callid);
-	
-		sip_pvt_ptr = ao2_find(dialogs, &tmp_dialog, OBJ_POINTER, "ao2_find in dialogs");
-		if (sip_pvt_ptr) {
-			rc = ao2_ref(sip_pvt_ptr,0,"");
-			ast_log(LOG_NOTICE,"Found CALL dialog %s, refcount = %d\n", tmp_dialog.callid, rc);
-			if (!(!pedanticsipchecking || !tag || ast_strlen_zero(sip_pvt_ptr->theirtag) || !strcmp(sip_pvt_ptr->theirtag, tag)))
-			{
-				ast_log(LOG_NOTICE,"Pedantic Zero of dialog %s (1)\n", callid);
-				
-				ao2_ref(sip_pvt_ptr,-1,"pedantic failure, pointer erase"); /* basically, if the extra pedanticssipchecking constraints don't pan out,
-											the the match is defeated. There should be no other entry that matches
-											the callid */
-				sip_pvt_ptr = NULL;
-			}
-			/* If we get a new request within an existing to-tag - check the to tag as well */
-			if (pedanticsipchecking && sip_pvt_ptr  && req->method != SIP_RESPONSE) {	/* SIP Request */
-				if (sip_pvt_ptr->tag[0] == '\0' && totag[0]) {
-					/* We have no to tag, but they have. Wrong dialog */
-					ao2_ref(sip_pvt_ptr,-1,"pedantic failure, pointer erased 2");
-					sip_pvt_ptr = NULL;
-					ast_log(LOG_NOTICE,"Pedantic Zero of dialog %s (2)\n", callid);
-				} else if (totag[0]) {			/* Both have tags, compare them */
-					if (strcmp(totag, sip_pvt_ptr->tag)) {
-						ao2_ref(sip_pvt_ptr,-1, "pedantic totag failure, pointer erased 3");
-						sip_pvt_ptr = NULL;		/* This is not our packet */
-						ast_log(LOG_NOTICE,"Pedantic Zero of dialog %s (3)\n", callid);
-					}
-				}
-				if (!sip_pvt_ptr)
-					ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", sip_pvt_ptr->callid, totag, sip_methods[req->method].text);
-			}
-		}
-		
-		ast_string_field_free_memory(&tmp_dialog);
-		if (!sip_pvt_ptr) {
-			struct ao2_iterator i;
-			struct sip_pvt *d2;
-			
-			ast_log(LOG_NOTICE,"Dialog %s not found\n", callid);
-			i = ao2_iterator_init(dialogs, 0);
-	
-			while ((d2 = ao2_iterator_next(&i,"iterate thru dialogs "))) {
-				ast_log(LOG_NOTICE, "Dialogs:  %s\n", d2->callid);
-				ao2_ref(d2,-1,"done with d2 pointer");
-			}
-		}
-		
-		if (sip_pvt_ptr) {
-			/* Found the call */
-			sip_pvt_lock(sip_pvt_ptr);
-			dialoglist_unlock();
-			return sip_pvt_ptr;
-		}
-	}
-	dialoglist_unlock();
-
+	ast_mark(prof_tail, 1);
+ 
 	/* See if the method is capable of creating a dialog */
 	if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
 		if (intended_method == SIP_REFER) {
@@ -5660,6 +5714,7 @@
 				ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
 			}
 		}
+		ast_mark(prof_tail, 0);
 		return p; /* can be NULL */
 	} else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
 		/* A method we do not support, let's take it on the volley */
@@ -5675,7 +5730,8 @@
 	if (intended_method == SIP_RESPONSE)
 		ast_debug(2, "That's odd...  Got a response on a call we dont know about. Callid %s\n", callid ? callid : "<unknown>");
 
-	return p; /* most likely null if returning here */
+	ast_mark(prof_tail, 0);
+	return NULL;
 }
 
 /*! \brief Parse register=> line in sip.conf and add to registry */
@@ -9138,7 +9194,6 @@
 {
 	struct sip_peer *peer = (struct sip_peer *)data;
 
-	ast_log(LOG_NOTICE,"SCHED:  sip_poke_peer_s called---\n");
 	peer->pokeexpire = -1;
 	sip_poke_peer(peer);
 	return 0;
@@ -11836,7 +11891,7 @@
 				if (!ast_test_flag(&user->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
 					ast_cli(a->fd, "User '%s' is not a Realtime user, cannot be pruned.\n", name);
 					/* put it back! */
-					ao2_link(users, user, "link user into users table");
+					ao2_link(users, user, "link unlinked  user back into users table");
 				} else
 					ast_cli(a->fd, "User '%s' pruned.\n", name);
 				unref_user(user,"unref_user: Tossing temp user ptr");
@@ -18328,7 +18383,6 @@
 {
 	struct sip_user *user;
 	int format;
-	struct ast_ha *oldha = NULL;
 	struct ast_flags userflags[2] = {{(0)}};
 	struct ast_flags mask[2] = {{(0)}};
 
@@ -18339,7 +18393,6 @@
 		
 	suserobjs++;
 	ast_copy_string(user->name, name, sizeof(user->name));
-	oldha = user->ha;
 	user->ha = NULL;
 	ast_copy_flags(&user->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&user->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
@@ -18436,7 +18489,6 @@
 	ast_copy_flags(&user->flags[1], &userflags[1], mask[1].flags);
 	if (ast_test_flag(&user->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))
 		global_allowsubscribe = TRUE;	/* No global ban any more */
-	ast_free_ha(oldha);
 	return user;
 }
 
@@ -18864,6 +18916,8 @@
 	struct sockaddr_in old_bindaddr = bindaddr;
 	int registry_count = 0, peer_count = 0, user_count = 0;
 
+	ast_log(LOG_NOTICE,"reload_config begun...\n");
+	
 	cfg = ast_config_load(config, config_flags);
 
 	/* We *must* have a config file otherwise stop immediately */
@@ -18882,6 +18936,7 @@
 		ucfg = ast_config_load("users.conf", config_flags);
 	}
 
+	ast_log(LOG_NOTICE,"reload_config 2...\n");
 	if (reason != CHANNEL_MODULE_LOAD) {
 		ast_debug(4, "--------------- SIP reload started\n");
 
@@ -18911,8 +18966,11 @@
 		ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
 		ast_debug(4, "--------------- Done destroying registry list\n");
 		ao2_callback(peers, OBJ_NODATA, peer_markall_func, 0, "callback to mark all peers");
-	}
-
+		/* reinstate the user table */
+		users = ao2_container_alloc(hash_user_size, user_hash_cb, user_cmp_cb,"allocate users");
+	}
+
+	ast_log(LOG_NOTICE,"reload_config 3...\n");
 	/* Initialize copy of current global_regcontext for later use in removing stale contexts */
 	ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts));
 	oldregcontext = oldcontexts;
@@ -18951,6 +19009,7 @@
 	externexpire = 0;			/* Expiration for DNS re-issuing */
 	externrefresh = 10;
 
+	ast_log(LOG_NOTICE,"reload_config 4...\n");
 	/* Reset channel settings to default before re-configuring */
 	allow_external_domains = DEFAULT_ALLOW_EXT_DOM;				/* Allow external invites */
 	global_regcontext[0] = '\0';
@@ -19020,6 +19079,7 @@
 	ast_clear_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT);
 	ast_clear_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT);
 
+	ast_log(LOG_NOTICE,"reload_config 5...\n");
 	/* Read the [general] config section of sip.conf (or from realtime config) */
 	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
 		if (handle_common_options(&global_flags[0], &dummy[0], v))
@@ -19316,6 +19376,7 @@
 		allow_external_domains = 1;
 	}
 	
+	ast_log(LOG_NOTICE,"reload_config 6...\n");
 	/* Build list of authentication to various SIP realms, i.e. service providers */
  	for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
  		/* Format for authentication is auth = username:password at realm */
@@ -19376,6 +19437,7 @@
 	}
 	
 
+	ast_log(LOG_NOTICE,"reload_config 7...\n");
 	/* Load peers, users and friends */
 	cat = NULL;
 	while ( (cat = ast_category_browse(cfg, cat)) ) {
@@ -19417,6 +19479,7 @@
 			}
 		}
 	}
+	ast_log(LOG_NOTICE,"reload_config 8...\n");
 	bindaddr.sin_family = AF_INET;
 	internip = bindaddr;
 	if (ast_find_ourip(&internip.sin_addr, bindaddr)) {
@@ -19466,6 +19529,7 @@
 		ast_debug(1, "STUN sees us at %s:%d\n", 
 			ast_inet_ntoa(externip.sin_addr) , ntohs(externip.sin_port));
 	}
+	ast_log(LOG_NOTICE,"reload_config 9...\n");
 	ast_mutex_unlock(&netlock);
 
 	/* Add default domains - host name, IP address and IP:port */
@@ -19494,16 +19558,20 @@
 			add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
 	}
 
+	ast_log(LOG_NOTICE,"reload_config 10...\n");
 	/* Release configuration from memory */
 	ast_config_destroy(cfg);
 
+	ast_log(LOG_NOTICE,"reload_config 11...\n");
 	/* Load the list of manual NOTIFY types to support */
 	if (notify_types)
 		ast_config_destroy(notify_types);
 	notify_types = ast_config_load(notify_config, config_flags);
 
+	ast_log(LOG_NOTICE,"reload_config 12...\n");
 	/* Done, tell the manager */
 	manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\nUser_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count, user_count);
+	ast_log(LOG_NOTICE,"reload_config done...\n");
 
 	return 0;
 }




More information about the asterisk-commits mailing list