[asterisk-commits] rmudgett: branch 1.8 r288194 - in /branches/1.8: ./ channels/chan_iax2.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Sep 21 19:06:25 CDT 2010


Author: rmudgett
Date: Tue Sep 21 19:06:21 2010
New Revision: 288194

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=288194
Log:
Merged revisions 288193 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.6.2

................
  r288193 | rmudgett | 2010-09-21 19:03:37 -0500 (Tue, 21 Sep 2010) | 33 lines
  
  Merged revisions 288192 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r288192 | rmudgett | 2010-09-21 18:55:58 -0500 (Tue, 21 Sep 2010) | 26 lines
    
    In chan_iax2.c:schedule_delivery() calls ast_bridged_channel() on an unlocked channel.
    
    Near the beginning of schedule_delivery(), ast_bridged_channel() is called
    on iaxs[fr->callno]->owner.  However, the channel is not locked, which can
    result in ast_bridged_channel() crashing should owner->tech change to a
    technology that doesn't implement bridged_channel.
    
    I also fixed the other calls to ast_bridged_channel() in chan_iax2.c since
    the owner lock was not held there either.
    
    Converted the existing channel deadlock avoidance to use
    iax2_lock_owner().  Using the new function simplified some awkward code.
    
    In the process of fixing the locking on ast_bridged_channel(), I also
    found a memory leak in socket_process() for v1.6.2 and v1.8.  The local
    struct variable ies.vars is not freed on early/abnormal function exits.
    
    (closes issue #17919)
    Reported by: rain
    Patches:
          issue17919_v1.4.patch uploaded by rmudgett (license 664)
          issue17919_w_leak_v1.6.2.patch uploaded by rmudgett (license 664)
          issue17919_w_leak_v1.8.patch uploaded by rmudgett (license 664)
    
    Review: https://reviewboard.asterisk.org/r/926/
  ........
................

Modified:
    branches/1.8/   (props changed)
    branches/1.8/channels/chan_iax2.c

Propchange: branches/1.8/
------------------------------------------------------------------------------
Binary property 'branch-1.6.2-merged' - no diff available.

Modified: branches/1.8/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_iax2.c?view=diff&rev=288194&r1=288193&r2=288194
==============================================================================
--- branches/1.8/channels/chan_iax2.c (original)
+++ branches/1.8/channels/chan_iax2.c Tue Sep 21 19:06:21 2010
@@ -1237,6 +1237,39 @@
 	.func_channel_read = acf_channel_read,
 };
 
+/*!
+ * \internal
+ * \brief Obtain the owner channel lock if the owner exists.
+ *
+ * \param callno IAX2 call id.
+ *
+ * \note Assumes the iaxsl[callno] lock is already obtained.
+ *
+ * \note
+ * IMPORTANT NOTE!!!  Any time this function is used, even if
+ * iaxs[callno] was valid before calling it, it may no longer be
+ * valid after calling it.  This function may unlock and lock
+ * the mutex associated with this callno, meaning that another
+ * thread may grab it and destroy the call.
+ *
+ * \return Nothing
+ */
+static void iax2_lock_owner(int callno)
+{
+	for (;;) {
+		if (!iaxs[callno] || !iaxs[callno]->owner) {
+			/* There is no owner lock to get. */
+			break;
+		}
+		if (!ast_channel_trylock(iaxs[callno]->owner)) {
+			/* We got the lock */
+			break;
+		}
+		/* Avoid deadlock by pausing and trying again */
+		DEADLOCK_AVOIDANCE(&iaxsl[callno]);
+	}
+}
+
 static void mwi_event_cb(const struct ast_event *event, void *userdata)
 {
 	/* The MWI subscriptions exist just so the core knows we care about those
@@ -2890,18 +2923,10 @@
  */
 static int iax2_queue_frame(int callno, struct ast_frame *f)
 {
-	for (;;) {
-		if (iaxs[callno] && iaxs[callno]->owner) {
-			if (ast_channel_trylock(iaxs[callno]->owner)) {
-				/* Avoid deadlock by pausing and trying again */
-				DEADLOCK_AVOIDANCE(&iaxsl[callno]);
-			} else {
-				ast_queue_frame(iaxs[callno]->owner, f);
-				ast_channel_unlock(iaxs[callno]->owner);
-				break;
-			}
-		} else
-			break;
+	iax2_lock_owner(callno);
+	if (iaxs[callno] && iaxs[callno]->owner) {
+		ast_queue_frame(iaxs[callno]->owner, f);
+		ast_channel_unlock(iaxs[callno]->owner);
 	}
 	return 0;
 }
@@ -2921,18 +2946,10 @@
  */
 static int iax2_queue_hangup(int callno)
 {
-	for (;;) {
-		if (iaxs[callno] && iaxs[callno]->owner) {
-			if (ast_channel_trylock(iaxs[callno]->owner)) {
-				/* Avoid deadlock by pausing and trying again */
-				DEADLOCK_AVOIDANCE(&iaxsl[callno]);
-			} else {
-				ast_queue_hangup(iaxs[callno]->owner);
-				ast_channel_unlock(iaxs[callno]->owner);
-				break;
-			}
-		} else
-			break;
+	iax2_lock_owner(callno);
+	if (iaxs[callno] && iaxs[callno]->owner) {
+		ast_queue_hangup(iaxs[callno]->owner);
+		ast_channel_unlock(iaxs[callno]->owner);
 	}
 	return 0;
 }
@@ -2953,18 +2970,10 @@
 static int iax2_queue_control_data(int callno, 
 	enum ast_control_frame_type control, const void *data, size_t datalen)
 {
-	for (;;) {
-		if (iaxs[callno] && iaxs[callno]->owner) {
-			if (ast_channel_trylock(iaxs[callno]->owner)) {
-				/* Avoid deadlock by pausing and trying again */
-				DEADLOCK_AVOIDANCE(&iaxsl[callno]);
-			} else {
-				ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
-				ast_channel_unlock(iaxs[callno]->owner);
-				break;
-			}
-		} else
-			break;
+	iax2_lock_owner(callno);
+	if (iaxs[callno] && iaxs[callno]->owner) {
+		ast_queue_control_data(iaxs[callno]->owner, control, data, datalen);
+		ast_channel_unlock(iaxs[callno]->owner);
 	}
 	return 0;
 }
@@ -4143,6 +4152,12 @@
 		return -1;
 	}
 
+	iax2_lock_owner(fr->callno);
+	if (!iaxs[fr->callno]) {
+		/* The call dissappeared so discard this frame that we could not send. */
+		iax2_frame_free(fr);
+		return -1;
+	}
 	if ((owner = iaxs[fr->callno]->owner))
 		bridge = ast_bridged_channel(owner);
 
@@ -4150,6 +4165,8 @@
 	 * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
 	if ( (!ast_test_flag64(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) {
 		jb_frame frame;
+
+		ast_channel_unlock(owner);
 
 		/* deliver any frames in the jb */
 		while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) {
@@ -4168,6 +4185,9 @@
 			*tsout = fr->ts;
 		__do_deliver(fr);
 		return -1;
+	}
+	if (owner) {
+		ast_channel_unlock(owner);
 	}
 
 	/* insert into jitterbuffer */
@@ -9708,27 +9728,13 @@
 
 static void set_hangup_source_and_cause(int callno, unsigned char causecode)
 {
-	int locked = 0;
-	struct ast_channel *owner=NULL;
-
-	do {
-		if (ast_channel_trylock(iaxs[callno]->owner)) {
-			DEADLOCK_AVOIDANCE(&iaxsl[callno]);
-		} else {
-			locked = 1;
-			owner = iaxs[callno]->owner;
-		}
-	}
-	while (!locked && iaxs[callno] && iaxs[callno]->owner);
-
+	iax2_lock_owner(callno);
 	if (iaxs[callno] && iaxs[callno]->owner) {
 		if (causecode) {
 			iaxs[callno]->owner->hangupcause = causecode;
 		}
 		ast_set_hangupsource(iaxs[callno]->owner, iaxs[callno]->owner->name, 0);
-		ast_channel_unlock(owner);
-	} else if(locked) {
-		ast_channel_unlock(owner);
+		ast_channel_unlock(iaxs[callno]->owner);
 	}
 }
 
@@ -9845,6 +9851,7 @@
 			if (f.frametype == AST_FRAME_IAX) {
 				if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
 					ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
+					ast_variables_destroy(ies.vars);
 					return 1;
 				}
 				f.data.ptr = NULL;
@@ -9864,6 +9871,7 @@
 		if (!dcallno && iax2_allow_new(f.frametype, f.subclass.integer, 1)) {
 			/* only set NEW_ALLOW if calltoken checks out */
 			if (handle_call_token(fh, &ies, &sin, fd)) {
+				ast_variables_destroy(ies.vars);
 				return 1;
 			}
 
@@ -9881,6 +9889,7 @@
 		/* Don't know anything about it yet */
 		f.frametype = AST_FRAME_NULL;
 		f.subclass.integer = 0;
+		memset(&ies, 0, sizeof(ies));
 	}
 
 	if (!fr->callno) {
@@ -9904,6 +9913,7 @@
 			} else if (f.frametype == AST_FRAME_IAX && (f.subclass.integer == IAX_COMMAND_REGREQ || f.subclass.integer == IAX_COMMAND_REGREL)) {
 				send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
 			}
+			ast_variables_destroy(ies.vars);
 			return 1;
 		}
 	}
@@ -9926,11 +9936,13 @@
 		}
 		if (fr->callno > 0) 
 			ast_mutex_unlock(&iaxsl[fr->callno]);
+		ast_variables_destroy(ies.vars);
 		return 1;
 	}
 	if (ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED) && !decrypted) {
 		if (decrypt_frame(fr->callno, fh, &f, &res)) {
 			ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
+			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
@@ -10020,6 +10032,7 @@
 					/* Send a VNAK requesting retransmission */
 					iax2_vnak(fr->callno);
 				}
+				ast_variables_destroy(ies.vars);
 				ast_mutex_unlock(&iaxsl[fr->callno]);
 				return 1;
 			}
@@ -10083,6 +10096,7 @@
 					iaxs[fr->callno]->rseqno = fr->iseqno;
 				else {
 					/* Stop processing now */
+					ast_variables_destroy(ies.vars);
 					ast_mutex_unlock(&iaxsl[fr->callno]);
 					return 1;
 				}
@@ -10095,6 +10109,7 @@
 			 ((f.subclass.integer != IAX_COMMAND_TXACC) &&
 			  (f.subclass.integer != IAX_COMMAND_TXCNT)))) {
 			/* Only messages we accept from a transfer host are TXACC and TXCNT */
+			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
@@ -10108,6 +10123,7 @@
 			if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
 				ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
 				if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) {
+					ast_variables_destroy(ies.vars);
 					ast_mutex_unlock(&iaxsl[fr->callno]);
 					return 1;
 				}
@@ -10117,6 +10133,13 @@
 				struct ast_datastore *variablestore = NULL;
 				struct ast_variable *var, *prev = NULL;
 				AST_LIST_HEAD(, ast_var_t) *varlist;
+
+				iax2_lock_owner(fr->callno);
+				if (!iaxs[fr->callno]) {
+					ast_variables_destroy(ies.vars);
+					ast_mutex_unlock(&iaxsl[fr->callno]);
+					return 1;
+				}
 				if ((c = iaxs[fr->callno]->owner)) {
 					varlist = ast_calloc(1, sizeof(*varlist));
 					variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
@@ -10153,6 +10176,7 @@
 							ast_free(varlist);
 						}
 					}
+					ast_channel_unlock(c);
 				} else {
 					/* No channel yet, so transfer the variables directly over to the pvt,
 					 * for later inheritance. */
@@ -10182,14 +10206,11 @@
 					iaxs[fr->callno]->voiceformat = f.subclass.codec;
 					ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(f.subclass.codec));
 					if (iaxs[fr->callno]->owner) {
-						format_t orignative;
-retryowner:
-						if (ast_channel_trylock(iaxs[fr->callno]->owner)) {
-							DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
-							if (iaxs[fr->callno] && iaxs[fr->callno]->owner) goto retryowner;
-						}
+						iax2_lock_owner(fr->callno);
 						if (iaxs[fr->callno]) {
 							if (iaxs[fr->callno]->owner) {
+								format_t orignative;
+
 								orignative = iaxs[fr->callno]->owner->nativeformats;
 								iaxs[fr->callno]->owner->nativeformats = f.subclass.codec;
 								if (iaxs[fr->callno]->owner->readformat)
@@ -10261,22 +10282,32 @@
 
 					ast_set_flag64(iaxs[fr->callno], IAX_QUELCH);
 					if (ies.musiconhold) {
-						if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
+						iax2_lock_owner(fr->callno);
+						if (!iaxs[fr->callno] || !iaxs[fr->callno]->owner) {
+							break;
+						}
+						if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
 							const char *moh_suggest = iaxs[fr->callno]->mohsuggest;
+
+							/*
+							 * We already hold the owner lock so we do not
+							 * need to check iaxs[fr->callno] after it returns.
+							 */
 							iax2_queue_control_data(fr->callno, AST_CONTROL_HOLD, 
 								S_OR(moh_suggest, NULL),
 								!ast_strlen_zero(moh_suggest) ? strlen(moh_suggest) + 1 : 0);
-							if (!iaxs[fr->callno]) {
-								ast_mutex_unlock(&iaxsl[fr->callno]);
-								return 1;
-							}
 						}
+						ast_channel_unlock(iaxs[fr->callno]->owner);
 					}
 				}
 				break;
 			case IAX_COMMAND_UNQUELCH:
 				if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
-				        /* Generate Manager Unhold event, if necessary*/
+					iax2_lock_owner(fr->callno);
+					if (!iaxs[fr->callno]) {
+						break;
+					}
+					/* Generate Manager Unhold event, if necessary */
 					if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) {
 						ast_manager_event(iaxs[fr->callno]->owner, EVENT_FLAG_CALL, "Hold",
 							"Status: Off\r\n"
@@ -10287,13 +10318,17 @@
 					}
 
 					ast_clear_flag64(iaxs[fr->callno], IAX_QUELCH);
-					if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
+					if (!iaxs[fr->callno]->owner) {
+						break;
+					}
+					if (ast_bridged_channel(iaxs[fr->callno]->owner)) {
+						/*
+						 * We already hold the owner lock so we do not
+						 * need to check iaxs[fr->callno] after it returns.
+						 */
 						iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
-						if (!iaxs[fr->callno]) {
-							ast_mutex_unlock(&iaxsl[fr->callno]);
-							return 1;
-						}
 					}
+					ast_channel_unlock(iaxs[fr->callno]->owner);
 				}
 				break;
 			case IAX_COMMAND_TXACC:
@@ -10320,8 +10355,7 @@
 					check_provisioning(&sin, fd, ies.serviceident, ies.provver);
 					ast_mutex_lock(&iaxsl[fr->callno]);
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 				}
 				/* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
@@ -10358,8 +10392,7 @@
 					ast_mutex_lock(&iaxsl[fr->callno]);
 
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 				} else
 					exists = 0;
@@ -10372,8 +10405,7 @@
 						iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
 						send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 						if (!iaxs[fr->callno]) {
-							ast_mutex_unlock(&iaxsl[fr->callno]);
-							return 1;
+							break;
 						}
 						if (authdebug)
 							ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
@@ -10419,8 +10451,7 @@
 								iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 								send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 								if (!iaxs[fr->callno]) {
-									ast_mutex_unlock(&iaxsl[fr->callno]);
-									return 1;
+									break;
 								}
 								if (authdebug) {
 									char tmp[256], tmp2[256], tmp3[256];
@@ -10473,8 +10504,7 @@
 									ast_log(LOG_ERROR, "No best format in '%s'???\n", ast_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
 									send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 									if (!iaxs[fr->callno]) {
-										ast_mutex_unlock(&iaxsl[fr->callno]);
-										return 1;
+										break;
 									}
 									if (authdebug) {
 										ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
@@ -10531,10 +10561,6 @@
 					iaxs[fr->callno]->encmethods = 0;
 				if (!authenticate_request(fr->callno) && iaxs[fr->callno])
 					ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED);
-				if (!iaxs[fr->callno]) {
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					return 1;
-				}
 				break;
 			case IAX_COMMAND_DPREQ:
 				/* Request status in the dialplan */
@@ -10556,8 +10582,7 @@
 				if (iaxs[fr->callno]->owner) {
 					set_hangup_source_and_cause(fr->callno, ies.causecode);
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 				}
 
@@ -10570,8 +10595,7 @@
 				if (iaxs[fr->callno]->owner) {
 					set_hangup_source_and_cause(fr->callno, ies.causecode);
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 				}
 
@@ -10593,39 +10617,53 @@
 			case IAX_COMMAND_TRANSFER:
 			{
 				struct ast_channel *bridged_chan;
-
-				if (iaxs[fr->callno]->owner && (bridged_chan = ast_bridged_channel(iaxs[fr->callno]->owner)) && ies.called_number) {
+				struct ast_channel *owner;
+
+				iax2_lock_owner(fr->callno);
+				if (!iaxs[fr->callno]) {
+					/* Initiating call went away before we could transfer. */
+					break;
+				}
+				owner = iaxs[fr->callno]->owner;
+				bridged_chan = owner ? ast_bridged_channel(owner) : NULL;
+				if (bridged_chan && ies.called_number) {
+					ast_mutex_unlock(&iaxsl[fr->callno]);
+
 					/* Set BLINDTRANSFER channel variables */
-
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					pbx_builtin_setvar_helper(iaxs[fr->callno]->owner, "BLINDTRANSFER", bridged_chan->name);
-					ast_mutex_lock(&iaxsl[fr->callno]);
-					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
-					}
-
-					pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", iaxs[fr->callno]->owner->name);
+					pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", bridged_chan->name);
+					pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", owner->name);
+
 					if (ast_parking_ext_valid(ies.called_number, c, iaxs[fr->callno]->context)) {
-						struct ast_channel *saved_channel = iaxs[fr->callno]->owner;
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						if (iax_park(bridged_chan, saved_channel, ies.called_number)) {
-							ast_log(LOG_WARNING, "Failed to park call on '%s'\n", bridged_chan->name);
-						} else {
-							ast_debug(1, "Parked call on '%s'\n", ast_bridged_channel(iaxs[fr->callno]->owner)->name);
+						ast_debug(1, "Parking call '%s'\n", bridged_chan->name);
+						if (iax_park(bridged_chan, owner, ies.called_number)) {
+							ast_log(LOG_WARNING, "Failed to park call '%s'\n",
+								bridged_chan->name);
 						}
 						ast_mutex_lock(&iaxsl[fr->callno]);
 					} else {
-						if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context, ies.called_number, 1))
-							ast_log(LOG_WARNING, "Async goto of '%s' to '%s@%s' failed\n", bridged_chan->name, 
-								ies.called_number, iaxs[fr->callno]->context);
-						else {
-							ast_debug(1, "Async goto of '%s' to '%s@%s' started\n", bridged_chan->name, 
-								ies.called_number, iaxs[fr->callno]->context);
+						ast_mutex_lock(&iaxsl[fr->callno]);
+
+						if (iaxs[fr->callno]) {
+							if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context,
+								ies.called_number, 1)) {
+								ast_log(LOG_WARNING,
+									"Async goto of '%s' to '%s@%s' failed\n",
+									bridged_chan->name, ies.called_number,
+									iaxs[fr->callno]->context);
+							} else {
+								ast_debug(1, "Async goto of '%s' to '%s@%s' started\n",
+									bridged_chan->name, ies.called_number,
+									iaxs[fr->callno]->context);
+							}
+						} else {
+							/* Initiating call went away before we could transfer. */
 						}
 					}
 				} else {
 					ast_debug(1, "Async goto not applicable on call %d\n", fr->callno);
+				}
+				if (owner) {
+					ast_channel_unlock(owner);
 				}
 
 				break;
@@ -10655,8 +10693,7 @@
 					iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 					send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 					if (authdebug) {
 						char tmp1[256], tmp2[256];
@@ -10667,24 +10704,18 @@
 					}
 				} else {
 					ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
-					if (iaxs[fr->callno]->owner) {
+					iax2_lock_owner(fr->callno);
+					if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
 						/* Switch us to use a compatible format */
 						iaxs[fr->callno]->owner->nativeformats = iaxs[fr->callno]->peerformat;
 						ast_verb(3, "Format for call is %s\n", ast_getformatname(iaxs[fr->callno]->owner->nativeformats));
-retryowner2:
-						if (ast_channel_trylock(iaxs[fr->callno]->owner)) {
-							DEADLOCK_AVOIDANCE(&iaxsl[fr->callno]);
-							if (iaxs[fr->callno] && iaxs[fr->callno]->owner) goto retryowner2;
-						}
-						
-						if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
-							/* Setup read/write formats properly. */
-							if (iaxs[fr->callno]->owner->writeformat)
-								ast_set_write_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->writeformat);	
-							if (iaxs[fr->callno]->owner->readformat)
-								ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);	
-							ast_channel_unlock(iaxs[fr->callno]->owner);
-						}
+
+						/* Setup read/write formats properly. */
+						if (iaxs[fr->callno]->owner->writeformat)
+							ast_set_write_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->writeformat);	
+						if (iaxs[fr->callno]->owner->readformat)
+							ast_set_read_format(iaxs[fr->callno]->owner, iaxs[fr->callno]->owner->readformat);	
+						ast_channel_unlock(iaxs[fr->callno]->owner);
 					}
 				}
 				if (iaxs[fr->callno]) {
@@ -10698,10 +10729,6 @@
 			case IAX_COMMAND_POKE:
 				/* Send back a pong packet with the original timestamp */
 				send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr->ts, NULL, 0, -1);
-				if (!iaxs[fr->callno]) {
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					return 1;
-				}
 				break;
 			case IAX_COMMAND_PING:
 			{
@@ -10801,10 +10828,6 @@
 						ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
 					iax2_queue_frame(fr->callno, &hangup_fr);
 				}
-				if (!iaxs[fr->callno]) {
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					return 1;
-				}
 				break;
 			case IAX_COMMAND_AUTHREP:
 				/* For security, always ack immediately */
@@ -10835,8 +10858,7 @@
 					iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
 					send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 				} else {
 					/* Select an appropriate format */
@@ -10894,8 +10916,7 @@
 							iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 							send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 							if (!iaxs[fr->callno]) {
-								ast_mutex_unlock(&iaxsl[fr->callno]);
-								return 1;
+								break;
 							}
 						} else {
 							/* Pick one... */
@@ -10948,8 +10969,7 @@
 								iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 								send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 								if (!iaxs[fr->callno]) {
-									ast_mutex_unlock(&iaxsl[fr->callno]);
-									return 1;
+									break;
 								}
 							}
 						}
@@ -11042,8 +11062,7 @@
 						iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
 						send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
 						if (!iaxs[fr->callno]) {
-							ast_mutex_unlock(&iaxsl[fr->callno]);
-							return 1;
+							break;
 						}
 					} else {
 						char tmp[256];
@@ -11111,16 +11130,14 @@
 					send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
 				if (register_verify(fr->callno, &sin, &ies)) {
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 					/* Send delayed failure */
 					auth_fail(fr->callno, IAX_COMMAND_REGREJ);
 					break;
 				}
 				if (!iaxs[fr->callno]) {
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					return 1;
+					break;
 				}
 				if ((ast_strlen_zero(iaxs[fr->callno]->secret) && ast_strlen_zero(iaxs[fr->callno]->inkeys)) ||
 						ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED)) {
@@ -11130,25 +11147,16 @@
 					if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh))
 						ast_log(LOG_WARNING, "Registry error\n");
 					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
+						break;
 					}
 					if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
 						ast_mutex_unlock(&iaxsl[fr->callno]);
 						check_provisioning(&sin, fd, ies.serviceident, ies.provver);
 						ast_mutex_lock(&iaxsl[fr->callno]);
-						if (!iaxs[fr->callno]) {
-							ast_mutex_unlock(&iaxsl[fr->callno]);
-							return 1;
-						}
 					}
 					break;
 				}
 				registry_authrequest(fr->callno);
-				if (!iaxs[fr->callno]) {
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					return 1;
-				}
 				break;
 			case IAX_COMMAND_REGACK:
 				if (iax2_ack_registry(&ies, &sin, fr->callno)) 
@@ -11176,10 +11184,6 @@
 					iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found");
 					iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
 					send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
-					if (!iaxs[fr->callno]) {
-						ast_mutex_unlock(&iaxsl[fr->callno]);
-						return 1;
-					}
 				}
 				break;
 			case IAX_COMMAND_TXREJ:
@@ -11301,10 +11305,6 @@
 					send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
 				else
 					send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
-				if (!iaxs[fr->callno]) {
-					ast_mutex_unlock(&iaxsl[fr->callno]);
-					return 1;
-				}
 				break;
 			case IAX_COMMAND_CALLTOKEN:
 			{
@@ -11350,6 +11350,7 @@
 		else {
 			ast_log(LOG_WARNING, "Received mini frame before first full video frame\n");
 			iax2_vnak(fr->callno);
+			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
@@ -11372,12 +11373,14 @@
 		else {
 			ast_debug(1, "Received mini frame before first full voice frame\n");
 			iax2_vnak(fr->callno);
+			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
 		f.datalen = res - sizeof(struct ast_iax2_mini_hdr);
 		if (f.datalen < 0) {
 			ast_log(LOG_WARNING, "Datalen < 0?\n");
+			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
@@ -11395,6 +11398,7 @@
 	}
 	/* Don't pass any packets until we're started */
 	if (!ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
+		ast_variables_destroy(ies.vars);
 		ast_mutex_unlock(&iaxsl[fr->callno]);
 		return 1;
 	}
@@ -11403,6 +11407,7 @@
 		struct ast_party_connected_line connected;
 
 		if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) {
+			ast_variables_destroy(ies.vars);
 			ast_mutex_unlock(&iaxsl[fr->callno]);
 			return 1;
 		}
@@ -11465,6 +11470,7 @@
 	}
 
 	/* Always run again */
+	ast_variables_destroy(ies.vars);
 	ast_mutex_unlock(&iaxsl[fr->callno]);
 	return 1;
 }




More information about the asterisk-commits mailing list