? h323-dead.diff
? channels/chan_h323.c.diff
? channels/h323/ast_h323.cpp.diff
? channels/h323/ast_h323.h.diff
? channels/h323/chan_h323.h.diff
Index: channels/chan_h323.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_h323.c,v
retrieving revision 1.106
diff -u -r1.106 chan_h323.c
--- channels/chan_h323.c	17 Mar 2005 21:30:19 -0000	1.106
+++ channels/chan_h323.c	1 Apr 2005 19:08:21 -0000
@@ -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,6 +588,8 @@
         char addr[INET_ADDRSTRLEN];
         char called_addr[1024];
   
+  	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;
@@ -551,6 +625,7 @@
 		ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name);
 		return -1;
 	}
+	oh323_update_info(c);
 	return 0;
 }
 
@@ -558,9 +633,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 +657,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 +677,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 +701,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 +722,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 +748,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 +778,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 +799,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 +816,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 +919,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 +1028,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 +1298,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 +1329,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 +1359,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 +1378,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 +1389,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 +1420,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 +1444,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 +1465,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 +1522,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 +1542,6 @@
 			call_options = &user->options;
 		} 
 	}
-exit:
 	return call_options;
 }
 
@@ -1401,6 +1555,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 +1598,108 @@
         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
+		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);
+#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 +1709,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 +1750,7 @@
 			res = 1000;
 		}
 		res = ast_io_wait(io, res);
+		pthread_testcancel();
 		ast_mutex_lock(&monlock);
 		if (res >= 0) {
 			ast_sched_runq(sched);
@@ -2124,7 +2313,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");
Index: channels/h323/ast_h323.cpp
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/h323/ast_h323.cpp,v
retrieving revision 1.69
diff -u -r1.69 ast_h323.cpp
--- channels/h323/ast_h323.cpp	21 Dec 2004 00:07:56 -0000	1.69
+++ channels/h323/ast_h323.cpp	1 Apr 2005 19:08:25 -0000
@@ -70,6 +70,77 @@
 /** PWLib entry point */
 MyProcess *localProcess = NULL;
 
+class PAsteriskLog : public PObject, public iostream {
+	PCLASSINFO(PAsteriskLog, PObject);
+
+	public:
+	PAsteriskLog() : iostream(cout.rdbuf()) { init(&buffer); }
+	~PAsteriskLog() { flush(); }
+
+	private:
+	PAsteriskLog(const PAsteriskLog &) : iostream(cout.rdbuf()) { }
+	PAsteriskLog & operator=(const PAsteriskLog &) { return *this; }
+
+	class Buffer : public streambuf {
+		public:
+		virtual int overflow(int=EOF);
+		virtual int underflow();
+		virtual int sync();
+		PString string;
+	} buffer;
+	friend class Buffer;
+};
+
+static PAsteriskLog *logstream = NULL;
+
+int PAsteriskLog::Buffer::overflow(int c)
+{
+	if (pptr() >= epptr()) {
+		int ppos = pptr() - pbase();
+		char *newptr = string.GetPointer(string.GetSize() + 10);
+		setp(newptr, newptr + string.GetSize() - 1);
+		pbump(ppos);
+	}
+	if (c != EOF) {
+		*pptr() = (char)c;
+		pbump(1);
+	}
+	return 0;
+}
+
+int PAsteriskLog::Buffer::underflow()
+{
+	return EOF;
+}
+
+int PAsteriskLog::Buffer::sync()
+{
+	char *str = strdup(string);
+	char *s, *s1;
+	char c;
+
+	/* Pass each line with different ast_verbose() call */
+	for (s = str; s && *s; s = s1) {
+		s1 = strchr(s, '\n');
+		if (!s1)
+			s1 = s + strlen(s);
+		else
+			s1++;
+		c = *s1;
+		*s1 = '\0';
+		ast_verbose(s);
+		*s1 = c;
+	}
+	free(str);
+
+	string = PString();
+	char *base = string.GetPointer(10);
+	setp(base, base + string.GetSize() - 1);
+	return 0;
+}
+
+#define cout (*logstream)
+
 MyProcess::MyProcess(): PProcess("The NuFone Network's", "H.323 Channel Driver for Asterisk",
              MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
 {
@@ -81,6 +152,7 @@
 	cout << "  == Creating H.323 Endpoint" << endl;
 	endPoint = new MyH323EndPoint();
 	PTrace::Initialise(0, NULL, PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine);
+	PTrace::SetStream(logstream);
 }
 
 H323_REGISTER_CAPABILITY(H323_G7231Capability, OPAL_G7231);
@@ -504,6 +576,7 @@
 							unsigned options)
 	: H323Connection(ep, callReference, options)
 {
+	cause = -1;
 	if (h323debug) {
 		cout << "	== New H.323 Connection created." << endl;
 	}
@@ -543,7 +616,7 @@
 	}
 	on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
 
-	return TRUE;
+	return connectionState != ShuttingDownConnection;
 }
 
 H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller,
@@ -556,6 +629,9 @@
                cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
 	}
 
+	if (connectionState == ShuttingDownConnection)
+		return H323Connection::AnswerCallDenied;
+
 	if (!setupPDU.GetQ931().GetProgressIndicator(pi)) {
 		pi = 0;
 	}
@@ -612,7 +688,7 @@
 		on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
 	}
         on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
-        return TRUE;
+        return connectionState != ShuttingDownConnection;
 }
 
 BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
@@ -631,6 +707,9 @@
 		cout << ("\t--Received SETUP message\n");
 	}
 
+	if (connectionState == ShuttingDownConnection)
+		return FALSE;
+
 	sourceAliases = setupPDU.GetSourceAliases();
 	destAliases = setupPDU.GetDestinationAlias();
 			
@@ -696,6 +775,9 @@
 		cout << "	-- Sending SETUP message" << endl;
 	}
 
+	if (connectionState == ShuttingDownConnection)
+		return FALSE;
+
 	if (!ast_cid_num.IsEmpty()) {
 		setupPDU.GetQ931().SetCallingPartyNumber(ast_cid_num);
 	}
@@ -755,6 +837,8 @@
 	if (h323debug) {
 		cout << "\t-- Sending RELEASE COMPLETE" << endl;
 	}
+	if (cause > 0)
+		releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause);
 	return H323Connection::OnSendReleaseComplete(releaseCompletePDU);
 }
 
@@ -771,6 +855,8 @@
 	if (h323debug) {
 		cout <<  "\t-- Received RELEASE COMPLETE message..." << endl;
 	}
+	if (on_hangup)
+		on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
 	return H323Connection::OnReceivedReleaseComplete(pdu);
 }
 
@@ -882,7 +968,7 @@
 	if (h323debug) {
 		cout <<  "\t\t-- channelsOpen = " << channelsOpen << endl;
 	}
-	return TRUE;	
+	return connectionState != ShuttingDownConnection;
 }
 
 /* MyH323_ExternalRTPChannel */
@@ -987,6 +1073,7 @@
 void h323_end_point_create(void)
 {
 	channelsOpen = 0;
+	logstream = new PAsteriskLog();
 	localProcess = new MyProcess();	
 	localProcess->Main();
 }
@@ -1005,7 +1092,9 @@
 	endPoint->ClearAllCalls();
 	endPoint->RemoveListener(NULL);
 	delete endPoint;
+	PTrace::SetLevel(0);
 	delete localProcess;
+	delete logstream;
 }
 
 void h323_debug(int flag, unsigned level)
@@ -1028,7 +1117,8 @@
  			    send_digit_cb	dfunc,
  			    answer_call_cb	acfunc,
 			    progress_cb		pgfunc,
-			    rfc2833_cb		dtmffunc)
+			    rfc2833_cb		dtmffunc,
+			    hangup_cb		hangupfunc)
 {
 	on_incoming_call = ifunc;
 	on_outgoing_call = sfunc;
@@ -1041,6 +1131,7 @@
 	on_answer_call = acfunc;
 	on_progress = pgfunc;
 	on_set_rfc2833_payload = dtmffunc;
+	on_hangup = hangupfunc;
 }
 
 /**
@@ -1284,6 +1375,8 @@
 {
 	H225_ReleaseCompleteReason dummy;
 	H323Connection::CallEndReason r = H323Connection::EndedByLocalUser;
+	MyH323Connection *connection;
+	const PString currentToken(call_token);
 
 	if (!h323_end_point_exist()) {
 		return 1;
@@ -1293,7 +1386,12 @@
 		r = H323TranslateToCallEndReason((Q931::CauseValues)(cause), dummy);
 	}
 
-        endPoint->ClearCall(PString(call_token), r);
+	connection = (MyH323Connection *)endPoint->FindConnectionWithLock(currentToken);
+	if (connection) {
+		connection->SetCause(cause);
+		connection->Unlock();
+	}
+	endPoint->ClearCall(currentToken, r);
 	return 0;
 };
 
Index: channels/h323/ast_h323.h
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/h323/ast_h323.h,v
retrieving revision 1.31
diff -u -r1.31 ast_h323.h
--- channels/h323/ast_h323.h	16 Dec 2004 02:03:19 -0000	1.31
+++ channels/h323/ast_h323.h	1 Apr 2005 19:08:25 -0000
@@ -175,6 +175,7 @@
 	void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
 	BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
 				     H245_TerminalCapabilitySetReject &);
+	void SetCause(int _cause) { cause = _cause; };
 
 	PString sourceAliases;
 	PString destAliases;
@@ -186,6 +187,7 @@
 
 	unsigned progressSetup;
 	unsigned progressAlert;
+	int cause;
 
 	RTP_DataFrame::PayloadTypes dtmfCodec;
 
Index: channels/h323/chan_h323.h
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/h323/chan_h323.h,v
retrieving revision 1.37
diff -u -r1.37 chan_h323.h
--- channels/h323/chan_h323.h	21 Dec 2004 00:07:56 -0000	1.37
+++ channels/h323/chan_h323.h	1 Apr 2005 19:08:26 -0000
@@ -165,6 +165,9 @@
 typedef void (*rfc2833_cb)(unsigned, const char *, int);
 extern rfc2833_cb on_set_rfc2833_payload;
 
+typedef void (*hangup_cb)(unsigned, const char *, int);
+extern hangup_cb on_hangup;
+
 /* debug flag */
 extern int h323debug;
 
@@ -197,7 +200,8 @@
  				    send_digit_cb,
  				    answer_call_cb,
 				    progress_cb,
-				    rfc2833_cb);
+				    rfc2833_cb,
+				    hangup_cb);
 	int h323_set_capability(int, int);
 	int h323_set_alias(struct oh323_alias *);
 	int h323_set_gk(int, char *, char *);
