[Asterisk-cvs] asterisk/channels chan_h323.c,1.106,1.107

jeremy at lists.digium.com jeremy at lists.digium.com
Mon Apr 4 11:02:03 CDT 2005


Update of /usr/cvsroot/asterisk/channels
In directory mongoose.digium.com:/tmp/cvs-serv913

Modified Files:
	chan_h323.c 
Log Message:
Better dependancy and version checking method, solve call problems when dealing with a gatekeeper, sanity check call cleanup, in hopes to avoid deadlocks (Bugs #3848 #3643, #3591)

Index: chan_h323.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_h323.c,v
retrieving revision 1.106
retrieving revision 1.107
diff -u -d -r1.106 -r1.107
--- chan_h323.c	17 Mar 2005 21:30:19 -0000	1.106
+++ chan_h323.c	4 Apr 2005 15:54:34 -0000	1.107
@@ -82,6 +82,7 @@
 answer_call_cb on_answer_call;
 progress_cb on_progress;
 rfc2833_cb on_set_rfc2833_payload;
+hangup_cb on_hangup;
 
 /* global debug flag */
 int h323debug;
@@ -137,6 +138,9 @@
 	struct ast_rtp *rtp;					/* RTP Session */
 	int dtmfmode;						/* What DTMF Mode is being used */
 	struct ast_dsp *vad;					/* Used for in-band DTMF detection */
+	int nativeformats;					/* Codec formats supported by a channel */
+	int needhangup;						/* Send hangup when Asterisk is ready */
+	int hangupcause;					/* Hangup cause from OpenH323 layer */
 	struct oh323_pvt *next;					/* Next channel in list */
 } *iflist = NULL;
 
@@ -213,6 +217,61 @@
 #endif
 };
 
+static void oh323_update_info(struct ast_channel *c)
+{
+	struct oh323_pvt *pvt = c->tech_pvt;
+
+	ast_mutex_lock(&pvt->lock);
+	if (c->nativeformats != pvt->nativeformats) {
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Preparing %s for new native format\n", c->name);
+		c->nativeformats = pvt->nativeformats;
+		ast_set_read_format(c, c->readformat);
+		ast_set_write_format(c, c->writeformat);
+	}
+	if (pvt->needhangup) {
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Process pending hangup for %s\n", c->name);
+		c->_softhangup |= AST_SOFTHANGUP_DEV;
+		c->hangupcause = pvt->hangupcause;
+		ast_queue_hangup(c);
+		pvt->needhangup = 0;
+	}
+	ast_mutex_unlock(&pvt->lock);
+}
+
+static void cleanup_call_details(call_details_t *cd) 
+{
+        if (cd->call_token) {
+                free(cd->call_token);
+                cd->call_token = NULL;
+        }
+        if (cd->call_source_aliases) {
+                free(cd->call_source_aliases);
+                cd->call_source_aliases = NULL;
+        }
+        if (cd->call_dest_alias) {
+                free(cd->call_dest_alias);
+                cd->call_dest_alias = NULL;
+	}
+        if (cd->call_source_name) { 
+                free(cd->call_source_name);
+                cd->call_source_name = NULL;
+        }
+        if (cd->call_source_e164) {
+                free(cd->call_source_e164);
+                cd->call_source_e164 = NULL;
+        }
+        if (cd->call_dest_e164) {
+                free(cd->call_dest_e164);
+                cd->call_dest_e164 = NULL;
+        }
+        if (cd->sourceIp) {
+                free(cd->sourceIp);
+                cd->sourceIp = NULL;
+        }
+}
+
 static void __oh323_destroy(struct oh323_pvt *p)
 {
 	struct oh323_pvt *cur, *prev = NULL;
@@ -221,6 +280,12 @@
 		ast_rtp_destroy(p->rtp);
 	}
 	
+	/* Free dsp used for in-band DTMF detection */
+	if (p->vad) {
+		ast_dsp_free(p->vad);
+	}
+	cleanup_call_details(&p->cd);
+
 	/* Unlink us from the owner if we have one */
 	if (p->owner) {
 		ast_mutex_lock(&p->owner->lock);
@@ -494,13 +559,20 @@
 static int oh323_digit(struct ast_channel *c, char digit)
 {
 	struct oh323_pvt *p = (struct oh323_pvt *) c->tech_pvt;
-	if (p && p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) {
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Sending digit %c on %s\n", digit, c->name);
+	if (!p)
+		return -1;
+	ast_mutex_lock(&p->lock);
+	if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) {
 		ast_rtp_senddigit(p->rtp, digit);
 	}
 	/* If in-band DTMF is desired, send that */
-	if (p && (p->dtmfmode & H323_DTMF_INBAND)) {
+	if ((p->dtmfmode & H323_DTMF_INBAND)) {
 		h323_send_tone(p->cd.call_token, digit);
 	}
+	ast_mutex_unlock(&p->lock);
+	oh323_update_info(c);
 	return 0;
 }
 
@@ -516,19 +588,31 @@
         char addr[INET_ADDRSTRLEN];
         char called_addr[1024];
   
-        if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
+  	if (h323debug) {
+  		ast_log(LOG_DEBUG, "Calling to %s on %s\n", dest, c->name);
+        }
+	if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
                 ast_log(LOG_WARNING, "Line is already in use (%s)\n", c->name);
                 return -1;
         }
-        /* Clear and then set the address to call */
-        memset(addr, 0, sizeof(addr));
         if (usingGk) {
-                memcpy(addr, dest, strlen(addr));
                 pvt->options.port = h323_signalling_port;
+                if (ast_strlen_zero(pvt->exten)) {
+	               	strncpy(called_addr, dest, sizeof(called_addr));
+                } else {
+                        snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest);
+     		}
         } else {
                 ast_inet_ntoa(addr, sizeof(addr), pvt->sa.sin_addr);
                 pvt->options.port = htons(pvt->sa.sin_port);
+                if (ast_strlen_zero(pvt->exten)) {
+                        snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, pvt->options.port);
+                } else {
+                        snprintf(called_addr, sizeof(called_addr), "%s@%s:%d", pvt->exten, addr, pvt->options.port);
+		}
 	}
+	/* make sure null terminated */
+	called_addr[sizeof(called_addr) - 1] = '\0'; 
 
 	if (c->cid.cid_num) {
 		strncpy(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num));
@@ -540,17 +624,13 @@
 	/* indicate that this is an outgoing call */
 	pvt->outgoing = 1;
 
-	if (pvt->exten) {
-		snprintf(called_addr, sizeof(called_addr), "%s@%s:%d", pvt->exten, addr, pvt->options.port);
-	} else {
-		snprintf(called_addr, sizeof(called_addr), "%s:%d",addr, pvt->options.port);
-	}
 	ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
 	res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
 	if (res) {
 		ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name);
 		return -1;
 	}
+	oh323_update_info(c);
 	return 0;
 }
 
@@ -558,9 +638,19 @@
 {
 	int res;
 	struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
+	char *token;
 
-	res = h323_answering_call(pvt->cd.call_token, 0);
-	
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Answering on %s\n", c->name);
+
+	ast_mutex_lock(&pvt->lock);
+	token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
+	ast_mutex_unlock(&pvt->lock);
+	res = h323_answering_call(token, 0);
+	if (token)
+		free(token);
+
+	oh323_update_info(c);
 	if (c->_state != AST_STATE_UP) {
 		ast_setstate(c, AST_STATE_UP);
 	}
@@ -572,6 +662,11 @@
 	struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
 	int needcancel = 0;
 	int q931cause = AST_CAUSE_NORMAL_CLEARING;
+	char *call_token;
+
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Hanging up call %s\n", c->name);
 
 	if (!c->tech_pvt) {
 		ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
@@ -587,12 +682,7 @@
 	if (!c || (c->_state != AST_STATE_UP)) {
 		needcancel = 1;
 	}
-	pvt = (struct oh323_pvt *)c->tech_pvt;
 	
-	/* Free dsp used for in-band DTMF detection */
-	if (pvt->vad) {
-		ast_dsp_free(pvt->vad);
-	}
 	pvt->owner = NULL;
 	c->tech_pvt = NULL;
 
@@ -616,12 +706,19 @@
 	}
 
 	/* Start the process if it's not already started */
-	if (!pvt->alreadygone) {
-		if (h323_clear_call((pvt->cd).call_token, q931cause)) { 
-			ast_log(LOG_DEBUG, "ClearCall failed.\n");
+	if (!pvt->alreadygone && !pvt->hangupcause) {
+		call_token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
+		if (call_token) {
+			/* Release lock to eliminate deadlock */
+			ast_mutex_unlock(&pvt->lock);
+			if (h323_clear_call(call_token, q931cause)) { 
+				ast_log(LOG_DEBUG, "ClearCall failed.\n");
+			}
+			free(call_token);
+			ast_mutex_lock(&pvt->lock);
 		}
-		pvt->needdestroy = 1;
 	} 
+	pvt->needdestroy = 1;
 
 	/* Update usage counter */
 	ast_mutex_lock(&usecnt_lock);
@@ -630,8 +727,8 @@
 		ast_log(LOG_WARNING, "Usecnt < 0\n");
 	}
 	ast_mutex_unlock(&usecnt_lock);
-	ast_update_use_count();
 	ast_mutex_unlock(&pvt->lock);
+	ast_update_use_count();
 	return 0;
 }
 
@@ -656,10 +753,17 @@
 		/* We already hold the channel lock */
 		if (f->frametype == AST_FRAME_VOICE) {
 			if (f->subclass != pvt->owner->nativeformats) {
+				/* Try to avoid deadlock */
+				if (ast_mutex_trylock(&pvt->owner->lock)) {
+					ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n");
+					return &null_frame;
+				}
 				ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
 				pvt->owner->nativeformats = f->subclass;
+				pvt->nativeformats = f->subclass;
 				ast_set_read_format(pvt->owner, pvt->owner->readformat);
 				ast_set_write_format(pvt->owner, pvt->owner->writeformat);
+				ast_mutex_unlock(&pvt->owner->lock);
 			}	
 			/* Do in-band DTMF detection */
 			if ((pvt->dtmfmode & H323_DTMF_INBAND) && pvt->vad) {
@@ -679,6 +783,7 @@
 	struct ast_frame *fr;
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
 	ast_mutex_lock(&pvt->lock);
+	oh323_update_info(c);
 	fr = oh323_rtp_read(pvt);
 	ast_mutex_unlock(&pvt->lock);
 	return fr;
@@ -699,7 +804,7 @@
 		if (!(frame->subclass & c->nativeformats)) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
 				frame->subclass, c->nativeformats, c->readformat, c->writeformat);
-			return -1;
+			return 0;
 		}
 	}
 	if (pvt) {
@@ -716,47 +821,71 @@
 {
 
 	struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
+	char *token = (char *)NULL;
 
-	ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, pvt->cd.call_token);
+	ast_mutex_lock(&pvt->lock);
+	token = (pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL);
+	ast_mutex_unlock(&pvt->lock);
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, token);
 
 	switch(condition) {
 	case AST_CONTROL_RINGING:
 		if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) {
-			h323_send_alerting(pvt->cd.call_token);
+			h323_send_alerting(token);
  			break;
  		}
+ 		if (token)
+ 			free(token);
 		return -1;
 	case AST_CONTROL_PROGRESS:
 		if (c->_state != AST_STATE_UP) {
-			h323_send_progress(pvt->cd.call_token);
+			h323_send_progress(token);
 			break;
 		}
+		if (token)
+			free(token);
 		return -1;
 
 	case AST_CONTROL_BUSY:
 		if (c->_state != AST_STATE_UP) {
-			h323_answering_call(pvt->cd.call_token, 1);
+			h323_answering_call(token, 1);
  			pvt->alreadygone = 1;
 			ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);			
 			break;
 		}
+		if (token)
+			free(token);
 		return -1;
 	case AST_CONTROL_CONGESTION:
 		if (c->_state != AST_STATE_UP) {
-			h323_answering_call(pvt->cd.call_token, 1);
+			h323_answering_call(token, 1);
 			pvt->alreadygone = 1;
 			ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
 			break;
 		}
+		if (token)
+			free(token);
 		return -1;
 	case AST_CONTROL_PROCEEDING:
 	case -1:
+		if (token)
+			free(token);
 		return -1;
 	default:
-		ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
+		ast_log(LOG_WARNING, "Don't know how to indicate condition %d on %s\n", condition, token);
+		if (token)
+			free(token);
 		return -1;
-	ast_mutex_unlock(&pvt->lock);
 	}
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "OH323: Indicated %d on %s\n", condition, token);
+	if (token)
+		free(token);
+	oh323_update_info(c);
+
 	return -1;
 }
 
@@ -795,6 +924,7 @@
 		if (!ch->nativeformats) {
 			ch->nativeformats = capability;
 		}
+		pvt->nativeformats = ch->nativeformats;
 		fmt = ast_best_codec(ch->nativeformats);
 		ch->type = type;
 		ch->fds[0] = ast_rtp_fd(pvt->rtp);
@@ -903,7 +1033,7 @@
 	ast_mutex_lock(&iflock);
         pvt = iflist; 
         while(pvt) {
-                if ((signed int)pvt->cd.call_reference == call_reference) {
+                if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) {
                         /* Found the call */             
                         if ((token != NULL) && (!strcmp(pvt->cd.call_token, token))) {
         			ast_mutex_unlock(&iflock);
@@ -1173,8 +1303,10 @@
 		ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
 		return NULL;
 	}
+	ast_mutex_lock(&pvt->lock);
 	/* figure out our local RTP port and tell the H.323 stack about it */
 	ast_rtp_get_us(pvt->rtp, &us);
+	ast_mutex_unlock(&pvt->lock);
 	/* evil hack, until I (or someone?) figures out a better way */
 	info->addr = ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr);
 	info->port = ntohs(us.sin_port);
@@ -1202,26 +1334,28 @@
 	struct oh323_pvt *pvt = NULL;
 	struct sockaddr_in them;
 	struct rtpPayloadType rtptype;
-	int fmt;
 
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token);
 	/* Find the call or allocate a private structure if call not found */
 	pvt = find_call(call_reference, token); 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: rtp\n");
 		return;
 	}
-
-	rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
-
-	fmt = ast_best_codec(pvt->owner->nativeformats);
-
 	ast_mutex_lock(&pvt->lock);
-	pvt->owner->nativeformats = rtptype.code;
-	pvt->owner->readformat = fmt;
-	pvt->owner->writeformat = fmt;
-	ast_set_read_format(pvt->owner, pvt->owner->readformat);
-	ast_set_write_format(pvt->owner, pvt->owner->writeformat);
-	ast_mutex_unlock(&pvt->lock);
+	if (pvt->alreadygone) {
+		ast_mutex_unlock(&pvt->lock);
+		return;
+	}
+	rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
+	pvt->nativeformats = rtptype.code;
+	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+		pvt->owner->nativeformats = pvt->nativeformats;
+		ast_set_read_format(pvt->owner, pvt->owner->readformat);
+		ast_set_write_format(pvt->owner, pvt->owner->writeformat);
+		ast_mutex_unlock(&pvt->owner->lock);
+	}
 
 	them.sin_family = AF_INET;
 	/* only works for IPv4 */
@@ -1230,8 +1364,13 @@
 	ast_rtp_set_peer(pvt->rtp, &them);
 
 	if (pvt->options.progress_audio) {
+		ast_mutex_unlock(&pvt->lock);
 		progress(call_reference, token, 1);
-	}
+	} else
+		ast_mutex_unlock(&pvt->lock);
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "RTP connection prepared for %s\n", token);
 
 	return;
 }
@@ -1244,6 +1383,9 @@
 {
 	struct ast_channel *c = NULL;
 	struct oh323_pvt *pvt = NULL;
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Call %s answered\n", token);
 	
 	pvt = find_call(call_reference, token); 
 	
@@ -1252,13 +1394,23 @@
 		return;
 	}
 
+	ast_mutex_lock(&pvt->lock);
+	/* Inform asterisk about remote party connected only on outgoing calls */
+	if (!pvt->outgoing) {
+		ast_mutex_unlock(&pvt->lock);
+		return;
+	}
 	if (!pvt->owner) {
+		ast_mutex_unlock(&pvt->lock);
 		ast_log(LOG_ERROR, "Channel has no owner\n");
 		return;
 	}
+	ast_mutex_lock(&pvt->owner->lock);
 	c = pvt->owner;	
 	ast_setstate(c, AST_STATE_UP);
 	ast_queue_control(c, AST_CONTROL_ANSWER);
+	ast_mutex_unlock(&pvt->owner->lock);
+	ast_mutex_unlock(&pvt->lock);
 	return;
 }
 
@@ -1273,12 +1425,16 @@
 		ast_log(LOG_ERROR, "Private structure not found in progress.\n");
 		return -1;
 	}
+	ast_mutex_lock(&p->lock);
 	if (!p->owner) {
+		ast_mutex_unlock(&p->lock);
 		ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
 		return -1;
 	}
-
+	ast_mutex_lock(&p->owner->lock);
 	ast_queue_control(p->owner, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
+	ast_mutex_unlock(&p->owner->lock);
+	ast_mutex_unlock(&p->lock);
 
 	return 0;
 }
@@ -1293,9 +1449,12 @@
 	struct oh323_pvt *pvt = NULL;
 	struct oh323_user *user = NULL;
 	struct oh323_alias *alias = NULL;
-	call_options_t *call_options = NULL;
+	call_options_t *call_options;
 	char iabuf[INET_ADDRSTRLEN];
 
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd.call_token);
+
 	/* allocate the call*/
 	pvt = oh323_alloc(cd.call_reference);
 
@@ -1311,6 +1470,7 @@
 	pvt->cd.call_source_name = strdup(cd.call_source_name);
 	pvt->cd.call_source_e164 = strdup(cd.call_source_e164);
 	pvt->cd.call_dest_e164 = strdup(cd.call_dest_e164);
+	call_options = &pvt->options;
 
 	if (h323debug) {
 		ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n");
@@ -1367,7 +1527,7 @@
 					pvt->exten[0] = 'i';
 					pvt->exten[1] = '\0';
 					ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd.sourceIp);
-					goto exit;					
+					return NULL;
 				}
 			}
 			strncpy(pvt->context, user->context, sizeof(pvt->context) - 1);
@@ -1387,7 +1547,6 @@
 			call_options = &user->options;
 		} 
 	}
-exit:
 	return call_options;
 }
 
@@ -1401,6 +1560,9 @@
 	struct oh323_pvt *pvt = NULL;
 	struct ast_channel *c = NULL;
 
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Preparing Asterisk to answer for %s\n", token);
+
 	/* Find the call or allocate a private structure if call not found */
 	pvt = find_call(call_reference, token); 
 	if (!pvt) {
@@ -1441,79 +1603,112 @@
         struct ast_channel *c = NULL;
         struct oh323_pvt *pvt = NULL;
 
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Ringing on %s\n", token);
+
         pvt = find_call(call_reference, token); 
         if (!pvt) {
                 ast_log(LOG_ERROR, "Something is wrong: ringing\n");
 	}
+	ast_mutex_lock(&pvt->lock);
         if (!pvt->owner) {
+        	ast_mutex_unlock(&pvt->lock);
                 ast_log(LOG_ERROR, "Channel has no owner\n");
                 return;
         }
+        ast_mutex_lock(&pvt->owner->lock);
         c = pvt->owner;
         ast_setstate(c, AST_STATE_RINGING);
         ast_queue_control(c, AST_CONTROL_RINGING);
+        ast_mutex_unlock(&pvt->owner->lock);
+        ast_mutex_unlock(&pvt->lock);
         return;
 }
 
-void cleanup_call_details(call_details_t cd) 
-{
-        if (cd.call_token) {
-                free(cd.call_token);
-        }
-        if (cd.call_source_aliases) {
-                free(cd.call_source_aliases);
-        }
-        if (cd.call_dest_alias) {
-                free(cd.call_dest_alias);
-	}
-        if (cd.call_source_name) { 
-                free(cd.call_source_name);
-        }
-        if (cd.call_source_e164) {
-                free(cd.call_source_e164);
-        }
-        if (cd.call_dest_e164) {
-                free(cd.call_dest_e164);
-        }
-        if (cd.sourceIp) {
-                free(cd.sourceIp);
-        }
-}
-
 /**
   * Call-back function to cleanup communication
   * Returns nothing,
   */
-void cleanup_connection(call_details_t cd)
+static void cleanup_connection(call_details_t cd)
 {	
 	struct oh323_pvt *pvt = NULL;
 	struct ast_rtp *rtp = NULL;
+
+	ast_log(LOG_DEBUG, "Cleaning connection to %s\n", cd.call_token);
 	
-	pvt = find_call(cd.call_reference, cd.call_token); 
-	if (!pvt) {
-		return;
+	while (1) {
+		pvt = find_call(cd.call_reference, cd.call_token); 
+		if (!pvt) {
+			return;
+		}
+		ast_mutex_lock(&pvt->lock);
+		if (!pvt->owner || !ast_mutex_trylock(&pvt->owner->lock))
+			break;
+#if 1
+#ifdef DEBUG_THREADS
+		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d)\n", cd.call_token, pvt->owner->lock.thread, pvt->owner->lock.reentrancy, pvt->owner->lock.func, pvt->owner->lock.file, pvt->owner->lock.lineno);
+#else
+		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", cd.call_token);
+#endif
+#endif
+		ast_mutex_unlock(&pvt->lock);
+		usleep(1);
 	}
-	ast_mutex_lock(&pvt->lock);
 	if (pvt->rtp) {
 		rtp = pvt->rtp;
 		pvt->rtp = NULL;
 		/* Immediately stop RTP */
 		ast_rtp_destroy(rtp);
 	}
-	cleanup_call_details(pvt->cd);
+	/* Free dsp used for in-band DTMF detection */
+	if (pvt->vad) {
+		ast_dsp_free(pvt->vad);
+		pvt->vad = NULL;
+	}
+	cleanup_call_details(&pvt->cd);
 	pvt->alreadygone = 1;
 	/* Send hangup */	
 	if (pvt->owner) {
+		pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 		ast_queue_hangup(pvt->owner);
-	} 
+		ast_mutex_unlock(&pvt->owner->lock);
+	}
 	ast_mutex_unlock(&pvt->lock);
 	return;	
 }
 
+static void hangup_connection(unsigned int call_reference, const char *token, int cause)
+{
+	struct oh323_pvt *pvt = NULL;
+
+	ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
+	
+	pvt = find_call(call_reference, token); 
+	if (!pvt) {
+		return;
+	}
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+		pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+		pvt->owner->hangupcause = pvt->hangupcause = cause;
+		ast_queue_hangup(pvt->owner);
+		ast_mutex_unlock(&pvt->owner->lock);
+	}
+	else {
+		pvt->needhangup = 1;
+		pvt->hangupcause = cause;
+		ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
+	}
+	ast_mutex_unlock(&pvt->lock);
+}
+
 void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
 {
 	struct oh323_pvt *pvt = NULL;
 
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting DTMF payload to %d on %s\n", payload, token);
+
 	pvt = find_call(call_reference, token);
 	if (!pvt) {
 		return;
@@ -1523,6 +1718,8 @@
 		ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event");
 	}
 	ast_mutex_unlock(&pvt->lock);
+	if (h323debug)
+		ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload);
 }
 
 static void *do_monitor(void *data)
@@ -1562,6 +1759,7 @@
 			res = 1000;
 		}
 		res = ast_io_wait(io, res);
+		pthread_testcancel();
 		ast_mutex_lock(&monlock);
 		if (res >= 0) {
 			ast_sched_runq(sched);
@@ -2124,7 +2322,8 @@
 				       send_digit,
 				       answer_call,
 				       progress,
-				       set_dtmf_payload);
+				       set_dtmf_payload,
+				       hangup_connection);
 		/* start the h.323 listener */
 		if (h323_start_listener(h323_signalling_port, bindaddr)) {
 			ast_log(LOG_ERROR, "Unable to create H323 listener.\n");




More information about the svn-commits mailing list