From adae4181f028b7f0ba25b24e78a992bd781080ee Mon Sep 17 00:00:00 2001 From: Jeremy McNamara Date: Wed, 27 Jul 2005 04:45:11 +0000 Subject: Stomp on deadlock. Bug #4555 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6234 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_h323.c | 96 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 35 deletions(-) (limited to 'channels/chan_h323.c') diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 8d4373d9c..cb8d9cf26 100755 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -140,7 +140,9 @@ struct oh323_pvt { 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 */ + int newstate; /* Pending state change */ + int newcontrol; /* Pending control to send */ + struct oh323_pvt *next; /* Next channel in list */ } *iflist = NULL; static struct ast_user_list { @@ -233,6 +235,15 @@ static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt) c->hangupcause = pvt->hangupcause; ast_queue_hangup(c); pvt->needhangup = 0; + pvt->newstate = pvt->newcontrol = -1; + } + if (pvt->newstate >= 0) { + ast_setstate(c, pvt->newstate); + pvt->newstate = -1; + } + if (pvt->newcontrol >= 0) { + ast_queue_control(c, pvt->newcontrol); + pvt->newcontrol = -1; } } @@ -550,18 +561,22 @@ static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt) } /* Do in-band DTMF detection */ if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) { - f = ast_dsp_process(pvt->owner,pvt->vad,f); + if (!ast_mutex_trylock(&pvt->owner->lock)) { + f = ast_dsp_process(pvt->owner,pvt->vad,f); + ast_mutex_unlock(&pvt->owner->lock); + } + else + ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n"); if (f &&(f->frametype == AST_FRAME_DTMF)) { ast_log(LOG_DEBUG, "Received in-band digit %c.\n", f->subclass); - } + } } - } } return f; } -static struct ast_frame *oh323_read(struct ast_channel *c) +static struct ast_frame *oh323_read(struct ast_channel *c) { struct ast_frame *fr; struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt; @@ -595,6 +610,7 @@ static int oh323_write(struct ast_channel *c, struct ast_frame *frame) if (pvt->rtp) { res = ast_rtp_write(pvt->rtp, frame); } + __oh323_update_info(c, pvt); ast_mutex_unlock(&pvt->lock); } return res; @@ -807,6 +823,7 @@ static struct oh323_pvt *oh323_alloc(int callid) pvt->nonCodecCapability &= ~AST_RTP_DTMF; } strncpy(pvt->context, default_context, sizeof(pvt->context) - 1); + pvt->newstate = pvt->newsignal = -1; /* Add to interface list */ ast_mutex_lock(&iflock); pvt->next = iflist; @@ -841,6 +858,26 @@ static struct oh323_pvt *find_call_locked(int call_reference, const char *token) return NULL; } +static int update_state(struct oh323_pvt *pvt, int state, int signal) +{ + if (!pvt) + return 0; + if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) { + if (state >= 0) + ast_setstate(pvt->owner, state); + if (signal >= 0) + ast_queue_control(pvt->owner, signal); + return 1; + } + else { + if (state >= 0) + pvt->newstate = state; + if (signal >= 0) + pvt->newsignal = signal; + return 0; + } +} + struct oh323_user *find_user(const call_details_t *cd) { struct oh323_user *u; @@ -1116,8 +1153,6 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token return info; } -int progress(unsigned call_reference, const char *token, int inband); - /** * Definition taken from rtp.c for rtpPayloadType because we need it here. */ @@ -1156,10 +1191,16 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem pvt->owner->nativeformats = pvt->nativeformats; ast_set_read_format(pvt->owner, pvt->owner->readformat); ast_set_write_format(pvt->owner, pvt->owner->writeformat); + if (pvt->options.progress_audio) + ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS); ast_mutex_unlock(&pvt->owner->lock); } - else if (h323debug) - ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token); + else { + if (pvt->options.progress_audio) + pvt->newcontrol = AST_CONTROL_PROGRESS; + if (h323debug) + ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token); + } them.sin_family = AF_INET; /* only works for IPv4 */ @@ -1167,11 +1208,7 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem them.sin_port = htons(remotePort); 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); + ast_mutex_unlock(&pvt->lock); if (h323debug) ast_log(LOG_DEBUG, "RTP connection prepared for %s\n", token); @@ -1202,16 +1239,8 @@ void connection_made(unsigned call_reference, const char *token) 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); + if (update_state(pvt, AST_STATE_UP, AST_CONTROL_ANSWER)) + ast_mutex_unlock(&pvt->owner->lock); ast_mutex_unlock(&pvt->lock); return; } @@ -1232,9 +1261,8 @@ int progress(unsigned call_reference, const char *token, int inband) ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n"); return -1; } - ast_mutex_lock(&pvt->owner->lock); - ast_queue_control(pvt->owner, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)); - ast_mutex_unlock(&pvt->owner->lock); + if (update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING))) + ast_mutex_unlock(&pvt->owner->lock); ast_mutex_unlock(&pvt->lock); return 0; @@ -1402,20 +1430,18 @@ void chan_ringing(unsigned call_reference, const char *token) if (h323debug) ast_log(LOG_DEBUG, "Ringing on %s\n", token); - pvt = find_call_locked(call_reference, token); - if (!pvt) { - ast_log(LOG_ERROR, "Something is wrong: ringing\n"); + pvt = find_call_locked(call_reference, token); + if (!pvt) { + ast_log(LOG_ERROR, "Something is wrong: ringing\n"); + 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_RINGING); - ast_queue_control(c, AST_CONTROL_RINGING); - ast_mutex_unlock(&pvt->owner->lock); + if (update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING)) + ast_mutex_unlock(&pvt->owner->lock); ast_mutex_unlock(&pvt->lock); return; } -- cgit v1.2.3