[asterisk-commits] moy: branch moy/dahdi-tap-1.6.2 r221587 - /team/moy/dahdi-tap-1.6.2/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Oct 1 09:48:17 CDT 2009


Author: moy
Date: Thu Oct  1 09:48:12 2009
New Revision: 221587

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=221587
Log:
add proper locking to pvt and chan structures

Modified:
    team/moy/dahdi-tap-1.6.2/channels/chan_dahdi.c

Modified: team/moy/dahdi-tap-1.6.2/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/moy/dahdi-tap-1.6.2/channels/chan_dahdi.c?view=diff&rev=221587&r1=221586&r2=221587
==============================================================================
--- team/moy/dahdi-tap-1.6.2/channels/chan_dahdi.c (original)
+++ team/moy/dahdi-tap-1.6.2/channels/chan_dahdi.c Thu Oct  1 09:48:12 2009
@@ -4380,6 +4380,12 @@
 		p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
 	p->ignoredtmf = 0;
 
+	if (p->passivepeer) {
+		p->passivepeer->passivepeer = NULL;
+		p->passivepeer->owner = NULL;
+		p->passivepeer = NULL;
+	}
+
 	if (idx > -1) {
 		/* Real channel, do some fixup */
 		p->subs[idx].owner = NULL;
@@ -12432,8 +12438,10 @@
 	int chanpos, peerpos, law, layer1, transcap, res, fd;
 	struct dahdi_pcall *pcall = NULL;
 	struct ast_channel *c = NULL;
+	struct dahdi_pvt *peerpvt = NULL;
+	struct dahdi_pvt *masterpvt = NULL;
+	struct dahdi_confinfo dahdic = { 0, };
 	struct dahdi_pri *peerpri = pri->passivepeer;
-	struct dahdi_confinfo dahdic = { 0, };
 
 	if (!peerpri) {
 		ast_log(LOG_ERROR, "Ignoring passive PRI event on span %d, no peer span found!\n", pri->span);
@@ -12505,82 +12513,100 @@
 			break;
 		}
 
+		masterpvt = pri->pvts[chanpos];
+		peerpvt = peerpri->pvts[chanpos];
+
+		/* get pvt locks and do sanity checks */
+		ast_mutex_lock(&masterpvt->lock);
+		
+		/* sanity check */
+		if (masterpvt->owner) {
+			ast_log(LOG_ERROR, "Master pvt has already an owner when receiving passive call!!\n");
+			ast_mutex_unlock(&masterpvt->lock);
+			break;
+		}
+
+		ast_mutex_lock(&peerpvt->lock);
+		if (peerpvt->owner) {
+			ast_log(LOG_ERROR, "Peer pvt has already an owner when receiving passive call!!\n");
+			ast_mutex_unlock(&masterpvt->lock);
+			ast_mutex_unlock(&peerpvt->lock);
+			break;
+		}
+
 		/* save the call reference */
-		pri->pvts[chanpos]->call = e->proceeding.call;
-		peerpri->pvts[peerpos]->call = e->proceeding.call;
+		masterpvt->call = e->proceeding.call;
+		peerpvt->call = e->proceeding.call;
 
 		/* Set calling and callee information */
-		ast_copy_string(pri->pvts[chanpos]->cid_num, pcall->callingnum, sizeof(pri->pvts[chanpos]->cid_num));
-		ast_shrink_phone_number(pri->pvts[chanpos]->cid_num);
+		ast_copy_string(masterpvt->cid_num, pcall->callingnum, sizeof(masterpvt->cid_num));
+		ast_shrink_phone_number(masterpvt->cid_num);
 #ifdef PRI_ANI
 		if (!ast_strlen_zero(pcall->callingani)) {
-			ast_copy_string(pri->pvts[chanpos]->cid_ani, pcall->callingani, sizeof(pri->pvts[chanpos]->cid_ani));
-			ast_shrink_phone_number(pri->pvts[chanpos]->cid_ani);
+			ast_copy_string(masterpvt->cid_ani, pcall->callingani, sizeof(masterpvt->cid_ani));
+			ast_shrink_phone_number(masterpvt->cid_ani);
 		} else {
-			pri->pvts[chanpos]->cid_ani[0] = '\0';
-		}
-#endif
-		ast_copy_string(pri->pvts[chanpos]->cid_name, pcall->callingname, sizeof(pri->pvts[chanpos]->cid_name));
+			masterpvt->cid_ani[0] = '\0';
+		}
+#endif
+		ast_copy_string(masterpvt->cid_name, pcall->callingname, sizeof(masterpvt->cid_name));
 
 		if (!ast_strlen_zero(pcall->callednum)) {
-			ast_copy_string(pri->pvts[chanpos]->exten, pcall->callednum, sizeof(pri->pvts[chanpos]->exten));
-			ast_copy_string(pri->pvts[chanpos]->dnid, pcall->callednum, sizeof(pri->pvts[chanpos]->dnid));
+			ast_copy_string(masterpvt->exten, pcall->callednum, sizeof(masterpvt->exten));
+			ast_copy_string(masterpvt->dnid, pcall->callednum, sizeof(masterpvt->dnid));
 		} else if (pri->overlapdial)
-			pri->pvts[chanpos]->exten[0] = '\0';
+			masterpvt->exten[0] = '\0';
 		else {
 			/* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
-			pri->pvts[chanpos]->exten[0] = 's';
-			pri->pvts[chanpos]->exten[1] = '\0';
-		}
-
-		/* Set DNID on all incoming calls -- even immediate */
-		if (!ast_strlen_zero(pcall->callednum)) {
-			ast_copy_string(pri->pvts[chanpos]->dnid, pcall->callednum, sizeof(pri->pvts[chanpos]->dnid));
+			masterpvt->exten[0] = 's';
+			masterpvt->exten[1] = '\0';
 		}
 
 		/* create the actual ast_channel but dont start a pbx just yet */
 		law = layer1 == PRI_LAYER_1_ULAW ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW;
-		c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 0, SUB_REAL, law, AST_TRANS_CAP_SPEECH);
+		c = dahdi_new(masterpvt, AST_STATE_RING, 0, SUB_REAL, law, AST_TRANS_CAP_SPEECH);
 		if (!c) {
 			ast_log(LOG_ERROR, "Failed to create channel for call on channel %d/%d on span %d\n",
 				PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+			ast_mutex_unlock(&peerpvt->lock);
+			ast_mutex_unlock(&masterpvt->lock);
 			break;
 		}
 
-		res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
+		res = dahdi_setlaw(masterpvt->subs[SUB_REAL].dfd, law);
 		if (res < 0) {
-			ast_log(LOG_WARNING, "Unable to set law on channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
-		}
-		res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
+			ast_log(LOG_WARNING, "Unable to set law on channel %d: %s\n", masterpvt->channel, strerror(errno));
+		}
+		res = set_actual_gain(masterpvt->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to set gains on channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
 		}
-		res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law);
+		res = ioctl(masterpvt->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
 		}
 
-		res = dahdi_setlaw(peerpri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
+		res = dahdi_setlaw(peerpvt->subs[SUB_REAL].dfd, law);
 		if (res < 0) {
-			ast_log(LOG_WARNING, "Unable to set law on peer channel %d: %s\n", peerpri->pvts[chanpos]->channel, strerror(errno));
-		}
-		res = set_actual_gain(peerpri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, peerpri->pvts[chanpos]->rxgain, peerpri->pvts[chanpos]->txgain, law);
+			ast_log(LOG_WARNING, "Unable to set law on peer channel %d: %s\n", peerpvt->channel, strerror(errno));
+		}
+		res = set_actual_gain(peerpvt->subs[SUB_REAL].dfd, 0, peerpvt->rxgain, peerpvt->txgain, law);
 		if (res < 0) {
-			ast_log(LOG_WARNING, "Unable to set gains on peer channel %d: %s\n", peerpri->pvts[chanpos]->channel, strerror(errno));
-		}
-		res = ioctl(peerpri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law);
+			ast_log(LOG_WARNING, "Unable to set gains on peer channel %d: %s\n", peerpvt->channel, strerror(errno));
+		}
+		res = ioctl(peerpvt->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law);
 		if (res < 0) {
-			ast_log(LOG_WARNING, "Unable to set audio mode on peer channel %d to %d: %s\n", peerpri->pvts[chanpos]->channel, law, strerror(errno));
+			ast_log(LOG_WARNING, "Unable to set audio mode on peer channel %d to %d: %s\n", peerpvt->channel, law, strerror(errno));
 		}
 
 		/* the owner for the peer channel will be the same, both dahdi pvt structures will share the owner,
 		 * however Asterisk core will only know about one pvt structure, any future read will be done through
 		 * the conference descriptor
 		 * */
-		pri->pvts[chanpos]->owner = c;
-		pri->pvts[chanpos]->passivepeer = peerpri->pvts[peerpos];
-		peerpri->pvts[peerpos]->owner = c;
-		peerpri->pvts[peerpos]->passivepeer = pri->pvts[chanpos];
+		masterpvt->owner = c;
+		masterpvt->passivepeer = peerpvt;
+		peerpvt->owner = c;
+		peerpvt->passivepeer = masterpvt;
 
 		/* create the mixing conference 
 		 * some DAHDI_SETCONF interface rules to keep in mind
@@ -12592,35 +12618,41 @@
 		fd = dahdi_open("/dev/dahdi/pseudo");
 		/* TODO: what about setting DAHDI_POLICY_IMMEDIATE and buf size? DAHDI_SETLINEAR?? */
 		if (fd < 0 || ioctl(fd, DAHDI_SETCONF, &dahdic)) {
-			 ast_log(LOG_ERROR, "Unable to create dahdi conference for tapping\n");
-			 ast_hangup(c);
-			 break;
-		}
-		pri->pvts[chanpos]->passiveconf = dahdic.confno;
-		pri->pvts[chanpos]->passivefd = fd;
+			ast_log(LOG_ERROR, "Unable to create dahdi conference for tapping\n");
+			ast_mutex_unlock(&peerpvt->lock);
+			ast_mutex_unlock(&masterpvt->lock);
+			ast_hangup(c);
+			break;
+		}
+		masterpvt->passiveconf = dahdic.confno;
+		masterpvt->passivefd = fd;
 
 		/* add both parties to the conference */
 		dahdic.chan = 0;
-		dahdic.confno = pri->pvts[chanpos]->passiveconf;
+		dahdic.confno = masterpvt->passiveconf;
 		dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
-		if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_SETCONF, &dahdic)) {
+		if (ioctl(masterpvt->subs[SUB_REAL].dfd, DAHDI_SETCONF, &dahdic)) {
 			ast_log(LOG_ERROR, "Unable to add chan to conference for tapping devices: %s\n", strerror(errno));
+			ast_mutex_unlock(&peerpvt->lock);
+			ast_mutex_unlock(&masterpvt->lock);
 			ast_hangup(c);
 			break;
 		}
 		dahdic.chan = 0;
-		dahdic.confno = pri->pvts[chanpos]->passiveconf;
+		dahdic.confno = masterpvt->passiveconf;
 		dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
-		if (ioctl(peerpri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_SETCONF, &dahdic)) {
+		if (ioctl(peerpvt->subs[SUB_REAL].dfd, DAHDI_SETCONF, &dahdic)) {
 			ast_log(LOG_ERROR, "Unable to add peer chan to conference for tapping devices: %s\n", strerror(errno));
+			ast_mutex_unlock(&peerpvt->lock);
+			ast_mutex_unlock(&masterpvt->lock);
 			ast_hangup(c);
 			break;
 		}
 		ast_log(LOG_DEBUG, "Created conference %d with fd %d between dahdi chans %d and %d for ast channel %s\n", 
-				pri->pvts[chanpos]->passiveconf,
-				pri->pvts[chanpos]->passivefd,
-		      		pri->pvts[chanpos]->channel,
-		      		peerpri->pvts[peerpos]->channel,
+				masterpvt->passiveconf,
+				masterpvt->passivefd,
+		      		masterpvt->channel,
+		      		peerpvt->channel,
 				c->name);
 
 		/* from now on, reading from the conference has the mix of both tapped channels, we can now launch the pbx thread */
@@ -12628,6 +12660,8 @@
 			ast_log(LOG_ERROR, "Failed to launch PBX thread for passive channel %s\n", c->name);
 			ast_hangup(c);
 		}
+		ast_mutex_unlock(&peerpvt->lock);
+		ast_mutex_unlock(&masterpvt->lock);
 		break;
 
 	case PRI_EVENT_ANSWER:
@@ -12640,21 +12674,19 @@
 				PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
 			break;
 		}
-
-		if (!pri->pvts[chanpos]->owner) {
+		masterpvt = pri->pvts[chanpos];
+		ast_mutex_lock(&masterpvt->lock);
+		if (!masterpvt->owner) {
+			ast_mutex_unlock(&masterpvt->lock);
 			/* this may be a valid condition if the user hangup the ast channel before the tapped line is answered */
 			ast_log(LOG_NOTICE, "Ignoring answer in tapped channel number %d/%d on span %d, no owner found\n",
 				PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
 			break;
 		}
 
-		/* set the owner state as UP */
-		c = pri->pvts[chanpos]->owner;
-		ast_channel_lock(c);
-		if (c->_state == AST_STATE_RING) {
-			ast_setstate(c, AST_STATE_UP);
-		}
-		ast_channel_unlock(c);
+		/* queue needanswer */
+		masterpvt->subs[SUB_REAL].needanswer = 1;
+		ast_mutex_unlock(&masterpvt->lock);
 		break;
 
 	case PRI_EVENT_HANGUP:
@@ -12670,29 +12702,22 @@
 		 * regardless of whethere there is owner or not, this resource must be freed */
 		pri_put_pcall(pri, e->hangup.call);
 
-		if (!pri->pvts[chanpos]->owner) {
+		/* now try to hangup if needed */
+		masterpvt = pri->pvts[chanpos];
+		ast_mutex_lock(&masterpvt->lock);
+		while (masterpvt->owner && ast_channel_trylock(masterpvt->owner)) {
+			DEADLOCK_AVOIDANCE(&masterpvt->lock);
+		}
+		if (!masterpvt->owner) {
+			ast_mutex_unlock(&masterpvt->lock);
 			/* this may be a valid condition if the user hangup the ast channel before the tapped line is terminated */
 			ast_log(LOG_NOTICE, "Ignoring hangup in tapped channel number %d/%d on span %d, no owner found\n",
 				PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
 			break;
 		}
-		ast_queue_hangup(pri->pvts[chanpos]->owner);
-
-		chanpos = pri_find_principle(peerpri, e->hangup.channel);
-		if (chanpos < 0) {
-			ast_log(LOG_ERROR, "Hangup requested on odd/unavailable channel number %d/%d on peer span %d\n",
-				PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), peerpri->span);
-			break;
-		}
-
-		if (!peerpri->pvts[chanpos]->owner) {
-			/* invalid, since the owner is the same for both pvts, the owner should be here too */
-			ast_log(LOG_ERROR, "No owner on hangup in channel number %d/%d on peer span %d!!!??\n",
-				PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), peerpri->span);
-			break;
-		}
-		ast_queue_hangup(peerpri->pvts[chanpos]->owner);
-
+		ast_queue_hangup(masterpvt->owner);
+		ast_channel_unlock(masterpvt->owner);
+		ast_mutex_unlock(&masterpvt->lock);
 		break;
 
 	case PRI_EVENT_HANGUP_ACK:




More information about the asterisk-commits mailing list