[Asterisk-cvs] asterisk/channels chan_mgcp.c,1.89,1.90

markster at lists.digium.com markster at lists.digium.com
Sun Nov 7 16:44:26 CST 2004


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

Modified Files:
	chan_mgcp.c 
Log Message:
Major MGCP locking fixes (bug #2696)


Index: chan_mgcp.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_mgcp.c,v
retrieving revision 1.89
retrieving revision 1.90
diff -u -d -r1.89 -r1.90
--- chan_mgcp.c	26 Oct 2004 22:25:43 -0000	1.89
+++ chan_mgcp.c	7 Nov 2004 21:46:09 -0000	1.90
@@ -573,6 +573,47 @@
     }
 }
 
+static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f)
+{
+	for(;;) {
+		if (sub->owner) {
+			if (!ast_mutex_trylock(&sub->owner->lock)) {
+				ast_queue_frame(sub->owner, f);
+				ast_mutex_unlock(&sub->owner->lock);
+			} else {
+				ast_mutex_unlock(&sub->lock);
+				usleep(1);
+				ast_mutex_lock(&sub->lock);
+			}
+		} else
+			break;
+	}
+}
+
+static void mgcp_queue_hangup(struct mgcp_subchannel *sub)
+{
+	for(;;) {
+		if (sub->owner) {
+			if (!ast_mutex_trylock(&sub->owner->lock)) {
+				ast_queue_hangup(sub->owner);
+				ast_mutex_unlock(&sub->owner->lock);
+			} else {
+				ast_mutex_unlock(&sub->lock);
+				usleep(1);
+				ast_mutex_lock(&sub->lock);
+			}
+		} else
+			break;
+	}
+}
+
+static void mgcp_queue_control(struct mgcp_subchannel *sub, int control)
+{
+	struct ast_frame f = { AST_FRAME_CONTROL, };
+	f.subclass = control;
+	return mgcp_queue_frame(sub, &f);
+}
+
 static int retrans_pkt(void *data)
 {
     struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
@@ -811,7 +852,7 @@
     }
 	sub = ast->pvt->pvt;
     p = sub->parent;
-
+	ast_mutex_lock(&sub->lock);
     switch (p->hookstate) {
         case MGCP_OFFHOOK:
             tone = "L/wt";
@@ -824,6 +865,7 @@
 
 	if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
 		ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name);
+		ast_mutex_unlock(&sub->lock);
 		return -1;
 	}
 
@@ -845,7 +887,7 @@
 
 		transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
 		ast_setstate(ast, AST_STATE_RINGING);
-		ast_queue_control(ast, AST_CONTROL_RINGING);
+		mgcp_queue_control(sub, AST_CONTROL_RINGING);
 
         if (sub->next->owner && strlen(sub->next->cxident) && strlen(sub->next->callid)) {
             /* Put the connection back in sendrecv */
@@ -857,6 +899,7 @@
 		ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
 		res = -1;
 	}
+	ast_mutex_unlock(&sub->lock);
 	return res;
 }
 
@@ -1057,6 +1100,7 @@
 	int res = 0;
 	struct mgcp_subchannel *sub = ast->pvt->pvt;
 	struct mgcp_endpoint *p = sub->parent;
+	ast_mutex_lock(&sub->lock);
     sub->cxmode = MGCP_CX_SENDRECV;
     if (!sub->rtp) {
         start_rtp(sub);
@@ -1074,6 +1118,7 @@
 		transmit_notify_request(sub, "");
 		transmit_modify_request(sub);
 	}
+	ast_mutex_unlock(&sub->lock);
 	return res;
 }
 
@@ -1151,12 +1196,15 @@
 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
 	struct mgcp_subchannel *sub = newchan->pvt->pvt;
+	ast_mutex_lock(&sub->lock);
     ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
 	if (sub->owner != oldchan) {
+		ast_mutex_unlock(&sub->lock);
 		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
 		return -1;
 	}
 	sub->owner = newchan;
+	ast_mutex_unlock(&sub->lock);
 	return 0;
 }
 
@@ -1168,7 +1216,9 @@
 	tmp[1] = '/';
 	tmp[2] = digit;
 	tmp[3] = '\0';
+	ast_mutex_lock(&sub->lock);
 	transmit_notify_request(sub, tmp);
+	ast_mutex_unlock(&sub->lock);
 	return -1;
 }
 
@@ -1208,9 +1258,11 @@
 static int mgcp_indicate(struct ast_channel *ast, int ind)
 {
 	struct mgcp_subchannel *sub = ast->pvt->pvt;
+	int res = 0;
     if (mgcpdebug) {
         ast_verbose(VERBOSE_PREFIX_3 "MGCP asked to indicate %d '%s' condition on channel %s\n", ind, control2str(ind), ast->name);
     }
+	ast_mutex_lock(&sub->lock);
 	switch(ind) {
 	case AST_CONTROL_RINGING:
 #ifdef DLINK_BUGGY_FIRMWARE	
@@ -1230,9 +1282,10 @@
 		break;		
 	default:
 		ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
-		return -1;
+		res = -1;
 	}
-	return 0;
+	ast_mutex_unlock(&sub->lock);
+	return res;
 }
 
 static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
@@ -1400,7 +1453,7 @@
     return s;
 } 
 
-static struct mgcp_subchannel *find_subchannel(char *name, int msgid, struct sockaddr_in *sin)
+static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin)
 {
 	struct mgcp_endpoint *p = NULL;
 	struct mgcp_subchannel *sub = NULL;
@@ -1498,6 +1551,7 @@
                 p = p->next;
 			}
 			if (sub && found) {
+				ast_mutex_lock(&sub->lock);
 				break;
             }
 		}
@@ -2745,7 +2799,7 @@
 		p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
         if (p->sub->next->owner) {
             p->sub->next->alreadygone = 1;
-            ast_queue_hangup(p->sub->next->owner);
+            mgcp_queue_hangup(p->sub->next);
         }
 	}
 	return 0;
@@ -2775,7 +2829,7 @@
             }
             /*transmit_notify_request(sub, "aw");*/
             transmit_notify_request(sub, "");
-            ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
+            mgcp_queue_control(sub, AST_CONTROL_ANSWER);
         }
     } else {
         /* Start switch */
@@ -3030,21 +3084,25 @@
             if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
                 /* We're allowed to transfer, we have two avtive calls and */
                 /* we made at least one of the calls.  Let's try and transfer */
-                if ((res = attempt_transfer(p)) < 0) {
+				ast_mutex_lock(&p->sub->next->lock);
+				res = attempt_transfer(p);
+                if (res < 0) {
                     if (p->sub->next->owner) {
                         sub->next->alreadygone = 1;
-                        ast_queue_hangup(sub->next->owner);
+                        mgcp_queue_hangup(sub->next);
                     }
                 } else if (res) {
                     ast_log(LOG_WARNING, "Transfer attempt failed\n");
+					ast_mutex_unlock(&p->sub->next->lock);
                     return -1;
                 }
+				ast_mutex_unlock(&p->sub->next->lock);
             } else {
                 /* Hangup the current call */
                 /* If there is another active call, mgcp_hangup will ring the phone with the other call */
                 if (sub->owner) {
                     sub->alreadygone = 1;
-                    ast_queue_hangup(sub->owner);
+                    mgcp_queue_hangup(sub);
                 } else {
                     /* SC: verbose level check */
                     if (option_verbose > 2) {
@@ -3075,10 +3133,12 @@
 			f.src = "mgcp";
 			if (sub->owner) {
                 /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
-				ast_queue_frame(sub->owner, &f);
+				mgcp_queue_frame(sub, &f);
+				ast_mutex_lock(&sub->next->lock);
                 if (sub->next->owner) {
-                    ast_queue_frame(sub->next->owner, &f);
+                    mgcp_queue_frame(sub->next, &f);
                 }
+				ast_mutex_unlock(&sub->next->lock);
             }
             if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
                 memset(p->curtone, 0, sizeof(p->curtone));
@@ -3167,11 +3227,12 @@
 	if (sscanf(req.verb, "%d", &result) &&
 		sscanf(req.identifier, "%d", &ident)) {
 		/* Try to find who this message is for, if it's important */
-		sub = find_subchannel(NULL, ident, &sin);
+		sub = find_subchannel_and_lock(NULL, ident, &sin);
 		if (sub) {
             struct mgcp_gateway *gw = sub->parent->parent;
             struct mgcp_message *cur, *prev;
 
+			ast_mutex_unlock(&sub->lock);
             ast_mutex_lock(&gw->msgs_lock);
             for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
                 if (cur->seqno == ident) {
@@ -3191,7 +3252,6 @@
             }
 
             ast_mutex_unlock(&gw->msgs_lock);
-
             if (cur) {
                 handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
                 free(cur);
@@ -3209,12 +3269,13 @@
 			return 1;
 		}
 		/* Process request, with iflock held */
-		sub = find_subchannel(req.endpoint, 0, &sin);
+		sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
 		if (sub) {
 			/* look first to find a matching response in the queue */
 			if (!find_and_retrans(sub, &req))
 	            /* pass the request off to the currently mastering subchannel */
 				handle_request(sub, &req, &sin);
+			ast_mutex_unlock(&sub->lock);
 		}
 	}
 	return 1;
@@ -3362,7 +3423,7 @@
 		ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
 		return NULL;
 	}
-	sub = find_subchannel(tmp, 0, NULL);
+	sub = find_subchannel_and_lock(tmp, 0, NULL);
 	if (!sub) {
 		ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
 		*cause = AST_CAUSE_UNREGISTERED;
@@ -3386,9 +3447,11 @@
              }
          }
 		*cause = AST_CAUSE_BUSY;
+		ast_mutex_unlock(&sub->lock);
 		return NULL;
     }
 	tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
+	ast_mutex_unlock(&sub->lock);
 	if (!tmpc)
 		ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
 	restart_monitor();




More information about the svn-commits mailing list