Stomp on deadlock. Bug #4555
authorJeremy McNamara <jj@nufone.net>
Wed, 27 Jul 2005 04:45:11 +0000 (04:45 +0000)
committerJeremy McNamara <jj@nufone.net>
Wed, 27 Jul 2005 04:45:11 +0000 (04:45 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6234 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_h323.c

index 8d4373d..cb8d9cf 100755 (executable)
@@ -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;
 }