[asterisk-commits] twilson: trunk r114084 - in /trunk: ./ channels/chan_iax2.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Apr 11 17:48:52 CDT 2008


Author: twilson
Date: Fri Apr 11 17:48:52 2008
New Revision: 114084

URL: http://svn.digium.com/view/asterisk?view=rev&rev=114084
Log:
Merged revisions 114083 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r114083 | twilson | 2008-04-11 17:32:51 -0500 (Fri, 11 Apr 2008) | 7 lines

Several places in the code called find_callno() (which releases the lock on the pvt structure) and then immediately locked the call and did things with it. Unfortunately, the call can disappear between the find_callno and the lock, causing Bad Stuff(tm) to happen.

Added find_callno_locked() function to return the callno withtout unlocking for instances that it is needed.

(issue #12400)
Reported by: ztel

........

Modified:
    trunk/   (props changed)
    trunk/channels/chan_iax2.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Modified: trunk/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_iax2.c?view=diff&rev=114084&r1=114083&r2=114084
==============================================================================
--- trunk/channels/chan_iax2.c (original)
+++ trunk/channels/chan_iax2.c Fri Apr 11 17:48:52 2008
@@ -1484,7 +1484,7 @@
  *
  * \note Calling this function while holding another pvt lock can cause a deadlock.
  */
-static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd)
+static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked)
 {
 	int res = 0;
 	int x;
@@ -1560,10 +1560,21 @@
 			ast_mutex_unlock(&iaxsl[x]);
 			return 0;
 		}
-		ast_mutex_unlock(&iaxsl[x]);
+		if (!return_locked)
+			ast_mutex_unlock(&iaxsl[x]);
 		res = x;
 	}
 	return res;
+}
+
+static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) {
+
+	return __find_callno(callno, dcallno, sin, new, sockfd, 0);
+}
+
+static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) {
+
+	return __find_callno(callno, dcallno, sin, new, sockfd, 1);
 }
 
 static void iax2_frame_free(struct iax_frame *fr)
@@ -3888,6 +3899,13 @@
 	ast_mutex_unlock(&iaxsl[callno]);
 	tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
 	ast_mutex_lock(&iaxsl[callno]);
+	if (!iaxs[callno]) {
+		if (tmp) {
+			ast_channel_free(tmp);
+		}
+		ast_mutex_unlock(&iaxsl[callno]);
+		return NULL;
+	}
 	iax2_ami_channelupdate(i);
 	if (!tmp)
 		return NULL;
@@ -7589,11 +7607,9 @@
 		/* Stop if we don't have enough data */
 		if (len > packet_len)
 			break;
-		fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd);
+		fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd);
 		if (!fr->callno)
 			continue;
-
-		ast_mutex_lock(&iaxsl[fr->callno]);
 
 		/* If it's a valid call, deliver the contents.  If not, we
 		   drop it, since we don't have a scallno to use for an INVAL */
@@ -7973,7 +7989,9 @@
 					if (call_to_destroy) {
 						if (iaxdebug)
 							ast_debug(1, "Really destroying %d, having been acked on final message\n", call_to_destroy);
+						ast_mutex_lock(&iaxsl[call_to_destroy]);
 						iax2_destroy(call_to_destroy);
+						ast_mutex_unlock(&iaxsl[call_to_destroy]);
 					}
 				}
 				/* Note how much we've received acknowledgement for */
@@ -9389,13 +9407,14 @@
 
 	if (!reg->callno) {
 		ast_debug(1, "Allocate call number\n");
-		reg->callno = find_callno(0, 0, &reg->addr, NEW_FORCE, defaultsockfd);
+		reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd);
 		if (reg->callno < 1) {
 			ast_log(LOG_WARNING, "Unable to create call for registration\n");
 			return -1;
 		} else
 			ast_debug(1, "Registration created on call %d\n", reg->callno);
 		iaxs[reg->callno]->reg = reg;
+		ast_mutex_unlock(&iaxsl[reg->callno]);
 	}
 	/* Setup the next registration a little early */
 	reg->expire = iax2_sched_replace(reg->expire, sched, 
@@ -9439,11 +9458,10 @@
 	memset(&ied, 0, sizeof(ied));
 	iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);
 
-	callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd);
+	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
 	if (!callno)
 		return -1;
 
-	ast_mutex_lock(&iaxsl[callno]);
 	if (iaxs[callno]) {
 		/* Schedule autodestruct in case they don't ever give us anything back */
 		iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, 
@@ -9675,14 +9693,12 @@
 	if (pds.port)
 		sin.sin_port = htons(atoi(pds.port));
 
-	callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd);
+	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
 	if (callno < 1) {
 		ast_log(LOG_WARNING, "Unable to create call\n");
 		*cause = AST_CAUSE_CONGESTION;
 		return NULL;
 	}
-
-	ast_mutex_lock(&iaxsl[callno]);
 
 	/* If this is a trunk, update it now */
 	ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);	
@@ -11044,13 +11060,12 @@
 	ast_debug(1, "peer: %s, username: %s, password: %s, context: %s\n",
 		pds.peer, pds.username, pds.password, pds.context);
 
-	callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd);
+	callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
 	if (callno < 1) {
 		ast_log(LOG_WARNING, "Unable to create call\n");
 		return -1;
 	}
 
-	ast_mutex_lock(&iaxsl[callno]);
 	ast_string_field_set(iaxs[callno], dproot, data);
 	iaxs[callno]->capability = IAX_CAPABILITY_FULLBANDWIDTH;
 




More information about the asterisk-commits mailing list