[asterisk-commits] moy: branch moy/dahdi-tap-trunk r220585 - /team/moy/dahdi-tap-trunk/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Sep 26 02:13:41 CDT 2009


Author: moy
Date: Sat Sep 26 02:13:37 2009
New Revision: 220585

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=220585
Log:
initial code to support tapping channels

Modified:
    team/moy/dahdi-tap-trunk/channels/chan_dahdi.c
    team/moy/dahdi-tap-trunk/channels/sig_pri.c
    team/moy/dahdi-tap-trunk/channels/sig_pri.h

Modified: team/moy/dahdi-tap-trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/moy/dahdi-tap-trunk/channels/chan_dahdi.c?view=diff&rev=220585&r1=220584&r2=220585
==============================================================================
--- team/moy/dahdi-tap-trunk/channels/chan_dahdi.c (original)
+++ team/moy/dahdi-tap-trunk/channels/chan_dahdi.c Sat Sep 26 02:13:37 2009
@@ -248,6 +248,10 @@
 		</description>
 	</manager>
  ***/
+
+#define TAP_PEER_NONE 0
+#define TAP_PEER_NEXT 1
+#define TAP_PEER_PREV 2
 
 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
 
@@ -1253,6 +1257,9 @@
 	/*! \brief TRUE if confrence is muted. */
 	int muting;
 	void *sig_pvt;
+	struct dahdi_pvt *tappingpeer;       /*!< Peer channel that has the other side of the call audio */
+	int tappingconf;                     /*!< DAHDI Conference number used for tapping */
+	int tappingfd;                       /*!< DAHDI Conference fd the mixed audio is read from */
 };
 
 static struct dahdi_pvt *iflist = NULL;	/*!< Main interface list start */
@@ -1316,6 +1323,7 @@
 			.privateprefix = "",
 			.unknownprefix = "",
 			.resetinterval = -1,
+			.tappingpeerpos = TAP_PEER_NONE,
 		},
 #endif
 #ifdef HAVE_SS7
@@ -2306,6 +2314,14 @@
 	struct dahdi_pvt *p = pvt;
 	int audio;
 	int newlaw = -1;
+
+	struct sig_pri_chan *pchan = p->sig_pvt;
+	struct sig_pri_pri *pri = pchan->pri;
+
+	if (pri->tappingpeer) {
+		p->tappingpeer = pchan->tappingpeer->chan_pvt;
+		((struct dahdi_pvt *)pchan->tappingpeer->chan_pvt)->tappingpeer = p;
+	}
 
 	/* Set to audio mode at this point */
 	audio = 1;
@@ -5208,6 +5224,21 @@
 	if (p->sig == SIG_SS7) {
 		x = 1;
 		ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
+	}
+
+	if (p->tappingpeer) {
+		struct dahdi_confinfo pinfo;
+		memset(&pinfo, 0, sizeof(pinfo));
+		ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF);
+		memset(&pinfo, 0, sizeof(pinfo));
+		ioctl(p->tappingpeer->subs[SUB_REAL].dfd, DAHDI_SETCONF);
+		memset(&pinfo, 0, sizeof(pinfo));
+		ioctl(p->tappingfd, DAHDI_SETCONF);
+		dahdi_close(p->tappingfd);
+		p->tappingfd = -1;
+		p->tappingpeer->tappingpeer = NULL;
+		p->tappingpeer->owner = NULL;
+		p->tappingpeer = NULL;
 	}
 
 	x = 0;
@@ -7776,40 +7807,54 @@
 	}
 	readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
 	CHECK_BLOCKING(ast);
-	res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
+#define CHECK_READ_RESULT(res) if (res < 0) { \
+		f = NULL; \
+		if (res == -1) { \
+			if (errno == EAGAIN) { \
+				/* Return "NULL" frame if there is nobody there */ \
+				ast_mutex_unlock(&p->lock); \
+				return &p->subs[idx].f; \
+			} else if (errno == ELAST) { \
+				if (analog_lib_handles(p->sig, p->radio, p->oprmode)) { \
+					struct analog_pvt *analog_p = p->sig_pvt; \
+					f = analog_exception(analog_p, ast); \
+				} else { \
+					f = __dahdi_exception(ast); \
+				} \
+			} else \
+				ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno)); \
+		} \
+		ast_mutex_unlock(&p->lock); \
+		return f; \
+	} \
+	if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) { \
+		ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE); \
+		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) { \
+			struct analog_pvt *analog_p = p->sig_pvt; \
+			f = analog_exception(analog_p, ast); \
+		} else { \
+			f = __dahdi_exception(ast); \
+		} \
+		ast_mutex_unlock(&p->lock); \
+		return f; \
+	}
+	/* if we have a tap peer we must read the mixed audio */
+	if (p->tappingpeer) {
+		/* passive channel reading */
+		/* first read from the 2 involved dahdi channels just to consume their frames */
+		res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
+		CHECK_READ_RESULT(res);
+		res = read(p->tappingpeer->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
+		CHECK_READ_RESULT(res);
+		/* now read the mixed audio that will be returned to the core */
+		res = read(p->tappingfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
+	} else {
+		/* no tapping peer, normal reading */
+		res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
+	}
 	ast_clear_flag(ast, AST_FLAG_BLOCKING);
 	/* Check for hangup */
-	if (res < 0) {
-		f = NULL;
-		if (res == -1) {
-			if (errno == EAGAIN) {
-				/* Return "NULL" frame if there is nobody there */
-				ast_mutex_unlock(&p->lock);
-				return &p->subs[idx].f;
-			} else if (errno == ELAST) {
-				if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
-					struct analog_pvt *analog_p = p->sig_pvt;
-					f = analog_exception(analog_p, ast);
-				} else {
-					f = __dahdi_exception(ast);
-				}
-			} else
-				ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
-		}
-		ast_mutex_unlock(&p->lock);
-		return f;
-	}
-	if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
-		ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-		if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
-			struct analog_pvt *analog_p = p->sig_pvt;
-			f = analog_exception(analog_p, ast);
-		} else {
-			f = __dahdi_exception(ast);
-		}
-		ast_mutex_unlock(&p->lock);
-		return f;
-	}
+	CHECK_READ_RESULT(res);
 	if (p->tdd) { /* if in TDD mode, see if we receive that */
 		int c;
 
@@ -7996,6 +8041,11 @@
 		return -1;
 	}
 
+	/* ignore writes to tapping channels */
+	if (p->tappingpeer) {
+		return 0;
+	}
+
 	/* Write a frame of (presumably voice) data */
 	if (frame->frametype != AST_FRAME_VOICE) {
 		if (frame->frametype != AST_FRAME_IMAGE)
@@ -8198,7 +8248,7 @@
 	struct ast_channel *tmp;
 	int deflaw;
 	int res;
-	int x,y;
+	int x,y,fd;
 	int features;
 	struct ast_str *chan_name;
 	struct ast_variable *v;
@@ -8368,6 +8418,54 @@
 	for (v = i->vars ; v ; v = v->next)
 		pbx_builtin_setvar_helper(tmp, v->name, v->value);
 
+	if (i->tappingpeer) {
+		struct dahdi_confinfo dahdic = { 0, };
+		/* create the mixing conference 
+		 * some DAHDI_SETCONF interface rules to keep in mind
+		 * confno == -1 means create new conference with the given confmode
+		 * confno and confmode == 0 means remove the channel from its conference */
+		dahdic.chan = 0; /* means use current channel (the one the fd belongs to)*/
+		dahdic.confno = -1; /* -1 means create new conference */
+		dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER | DAHDI_CONF_PSEUDO_LISTENER;
+		fd = dahdi_open("/dev/dahdi/pseudo");
+		if (fd < 0 || ioctl(fd, DAHDI_SETCONF, &dahdic)) {
+			ast_log(LOG_ERROR, "Unable to create dahdi conference for tapping\n");
+			ast_hangup(tmp);
+			i->owner = NULL;
+			return NULL;
+		}
+		i->tappingconf = dahdic.confno;
+		i->tappingfd = fd;
+
+		/* add both parties to the conference */
+		dahdic.chan = 0;
+		dahdic.confno = i->tappingconf;
+		dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
+		if (ioctl(i->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_hangup(tmp);
+			i->owner = NULL;
+			return NULL;
+		}
+		dahdic.chan = 0;
+		dahdic.confno = i->tappingconf;
+		dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
+		if (ioctl(i->tappingpeer->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_hangup(tmp);
+			i->owner = NULL;
+			return NULL;
+		}
+		ast_log(LOG_DEBUG, "Created tapping conference %d with fd %d between dahdi chans %d and %d for ast channel %s\n", 
+				i->tappingconf,
+				i->tappingfd,
+		      		i->channel,
+		      		i->tappingpeer->channel,
+				tmp->name);
+		i->tappingpeer->owner = i->owner;
+
+	}
+
 	if (startpbx) {
 #ifdef HAVE_OPENR2
 		if (i->mfcr2call) {
@@ -8378,6 +8476,9 @@
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
 			ast_hangup(tmp);
 			i->owner = NULL;
+			if (i->tappingpeer) {
+				i->tappingpeer->owner = NULL;
+			}
 			return NULL;
 		}
 	}
@@ -11001,6 +11102,23 @@
 						pris[span].pri.overlapdial = conf->pri.pri.overlapdial;
 						pris[span].pri.qsigchannelmapping = conf->pri.pri.qsigchannelmapping;
 						pris[span].pri.discardremoteholdretrieval = conf->pri.pri.discardremoteholdretrieval;
+						if (conf->pri.pri.tappingpeerpos == TAP_PEER_NEXT) {
+							if (span < (ARRAY_LEN(pris) - 1)) {
+								pris[span].pri.tappingpeerpos = TAP_PEER_NEXT;
+								pris[span].pri.tappingpeer = &pris[span+1].pri;
+								pris[span+1].pri.tappingpeer = &pris[span].pri;
+							} else {
+								ast_log(LOG_ERROR, "Ignoring tappingpeerpos 'next' for span %d, max spans exceeded.\n", span + 1);
+							}
+						} else if (conf->pri.pri.tappingpeerpos == TAP_PEER_PREV) {
+							if (span > 0) {
+								ast_log(LOG_ERROR, "Ignoring tappingpeerpos 'prev' for span %d, there is no previous span.\n", span + 1);
+							} else {
+								pris[span].pri.tappingpeerpos = TAP_PEER_PREV;
+								pris[span].pri.tappingpeer = &pris[span-1].pri;
+								pris[span-1].pri.tappingpeer = &pris[span].pri;
+							}
+						}
 #ifdef HAVE_PRI_SERVICE_MESSAGES
 						pris[span].pri.enable_service_message_support = conf->pri.pri.enable_service_message_support;
 #endif
@@ -11429,7 +11547,7 @@
 		*channelmatched = 1;
 	}
 
-	if (p->inalarm)
+	if (p->inalarm || p->tappingpeer)
 		return 0;
 
 	if (analog_lib_handles(p->sig, p->radio, p->oprmode))
@@ -15879,6 +15997,17 @@
 #endif /* PRI_GETSET_TIMERS */
 			} else if (!strcasecmp(v->name, "facilityenable")) {
 				confp->pri.pri.facilityenable = ast_true(v->value);
+			} else if (!strcasecmp(v->name, "tappingpeerpos")) {
+				if (!strcasecmp(v->name, "prev")) {
+					confp->pri.pri.tappingpeerpos = TAP_PEER_PREV;
+				} else if (!strcasecmp(v->name, "next")) {
+					confp->pri.pri.tappingpeerpos = TAP_PEER_NEXT;
+				} else {
+					confp->pri.pri.tappingpeerpos = TAP_PEER_NONE;
+					ast_log(LOG_ERROR, "'%s' is not a valid tappingpeerpos value at line %d. "
+							"(tappingpeerpos must be either 'prev' or 'next')\n",
+							v->value, v->lineno);
+				}
 #endif /* HAVE_PRI */
 #ifdef HAVE_SS7
 			} else if (!strcasecmp(v->name, "ss7type")) {

Modified: team/moy/dahdi-tap-trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/moy/dahdi-tap-trunk/channels/sig_pri.c?view=diff&rev=220585&r1=220584&r2=220585
==============================================================================
--- team/moy/dahdi-tap-trunk/channels/sig_pri.c (original)
+++ team/moy/dahdi-tap-trunk/channels/sig_pri.c Sat Sep 26 02:13:37 2009
@@ -1225,6 +1225,306 @@
 			break;
 		}
 	}
+}
+
+/* Not thread-safe, we assume nobody else is looking for a tap call slot at the same time in this pri */
+static struct dahdi_tapcall *pri_get_tap_call(struct sig_pri_pri *pri, void *callref)
+{
+	int i;
+	for (i = 0; i < ARRAY_LEN(pri->tapcalls); i++) {
+		if (callref == pri->tapcalls[i].callref) {
+			return &pri->tapcalls[i];
+		}
+	}
+	return NULL;
+}
+
+static struct dahdi_tapcall *pri_get_tap_call_by_crv(struct sig_pri_pri *pri, int crv)
+{
+	int i;
+	int tstcrv;
+	for (i = 0; i < ARRAY_LEN(pri->tapcalls); i++) {
+		tstcrv = pri->tapcalls[i].callref ? pri_get_crv(pri->pri, pri->tapcalls[i].callref, NULL) : 0;
+		if (pri->tapcalls[i].callref && tstcrv == crv) {
+			return &pri->tapcalls[i];
+		}
+	}
+	return NULL;
+}
+
+static void pri_put_pcall(struct sig_pri_pri *pri, void *callref)
+{
+	int i;
+	for (i = 0; i < ARRAY_LEN(pri->tapcalls); i++) {
+		if (callref == pri->tapcalls[i].callref) {
+			memset(&pri->tapcalls[i], 0, sizeof(pri->tapcalls[0]));
+		}
+	}
+}
+
+static void handle_pri_tapping_event(struct sig_pri_pri *pri, pri_event *e)
+{
+	int chanpos, peerpos, law, layer1, transcap;
+	struct dahdi_tapcall *tapcall = NULL;
+	struct ast_channel *c = NULL;
+	struct sig_pri_pri *peerpri = pri->tappingpeer;
+
+	if (!peerpri) {
+		ast_log(LOG_ERROR, "Ignoring tap PRI event on span %d, no peer span found!\n", pri->span);
+		return;
+	}
+
+	switch (e->e) {
+
+	case PRI_EVENT_RING:
+		ast_log(LOG_DEBUG, "Ring on channel %d of span %d with callref %d\n", e->ring.channel, pri->span, e->ring.cref);
+		/* we cannot use any pri->pvts data structure because we still dont know which channel will be used and therefore cant get
+		 * chanpos (ie, flexible channel was requested), thus, we need our own list of call references */
+		tapcall = pri_get_tap_call(pri, NULL);
+		if (!tapcall) {
+			ast_log(LOG_ERROR, "Failed to get a free PRI tap call slot, this is a bug!\n");
+			break;
+		}
+		tapcall->callref = e->ring.call;
+		ast_copy_string(tapcall->callingnum, e->ring.callingnum, sizeof(tapcall->callingnum));
+		ast_copy_string(tapcall->callingani, e->ring.callingani, sizeof(tapcall->callingani));
+		ast_copy_string(tapcall->callingname, e->ring.callingname, sizeof(tapcall->callingname));
+		ast_copy_string(tapcall->callednum, e->ring.callednum, sizeof(tapcall->callednum));
+		break;
+
+	case PRI_EVENT_PROGRESS:
+		ast_log(LOG_DEBUG, "Progress on channel %d of span %d\n", e->proceeding.channel, pri->span);
+		break;
+
+	case PRI_EVENT_PROCEEDING:
+		ast_log(LOG_DEBUG, "Proceed on channel %d of span %d\n", e->proceeding.channel, pri->span);
+		/* at this point we should know the real b chan that will be used and can therefore proceed to setup the ast channels, but
+		 * only if a couple of call tests are passed */
+
+		/* check that we already know about this call in the peer PRI (which was the one receiving the PRI_EVENT_RING event) */
+		if (!(tapcall = pri_get_tap_call_by_crv(peerpri, pri_get_crv(pri->pri, e->proceeding.call, NULL)))) {
+			ast_log(LOG_ERROR, 
+				"BUG, we got proceeding in channel number %d/%d on span %d for call reference %d "
+				"but we never got PRI_EVENT_RING for that call on peer span %d?\n", 
+				PRI_SPAN(e->proceeding.channel), 
+				PRI_CHANNEL(e->proceeding.channel),
+				pri->span, e->proceeding.cref, peerpri->span);
+			break;
+		}
+		/* check that the layer 1 and trans capability are supported */
+		layer1 = pri_get_layer1(peerpri->pri, tapcall->callref);
+		transcap = pri_get_transcap(peerpri->pri, tapcall->callref);
+
+		if (PRI_LAYER_1_ULAW != layer1 && PRI_LAYER_1_ALAW != layer1) {
+			ast_log(LOG_NOTICE, "Not monitoring call with unsupported layer 1 format %d\n", layer1);
+			break;
+		}
+		if (transcap != PRI_TRANS_CAP_SPEECH) {
+			ast_log(LOG_NOTICE, "Not monitoring call with unsupported capability %d\n", transcap);
+			break;
+		}
+
+		/* check for valid channels in both the current span and the peer span */
+		chanpos = pri_find_principle(pri, e->proceeding.channel);
+		if (chanpos < 0) {
+			ast_log(LOG_ERROR, "Proceeding requested on odd/unavailable channel number %d/%d on span %d\n",
+				PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), pri->span);
+			break;
+		}
+
+		peerpos = pri_find_principle(peerpri, e->proceeding.channel);
+		if (peerpos < 0) {
+			ast_log(LOG_ERROR, "Proceeding requested on odd/unavailable peer channel number %d/%d on span %d\n",
+				PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), pri->span);
+			break;
+		}
+
+		/* save the call reference */
+		pri->pvts[chanpos]->call = e->proceeding.call;
+		peerpri->pvts[peerpos]->call = e->proceeding.call;
+
+		/* Set calling and callee information */
+		ast_copy_string(pri->pvts[chanpos]->cid_num, tapcall->callingnum, sizeof(pri->pvts[chanpos]->cid_num));
+		ast_shrink_phone_number(pri->pvts[chanpos]->cid_num);
+#ifdef PRI_ANI
+		if (!ast_strlen_zero(tapcall->callingani)) {
+			ast_copy_string(pri->pvts[chanpos]->cid_ani, tapcall->callingani, sizeof(pri->pvts[chanpos]->cid_ani));
+			ast_shrink_phone_number(pri->pvts[chanpos]->cid_ani);
+		} else {
+			pri->pvts[chanpos]->cid_ani[0] = '\0';
+		}
+#endif
+		ast_copy_string(pri->pvts[chanpos]->cid_name, tapcall->callingname, sizeof(pri->pvts[chanpos]->cid_name));
+
+		if (!ast_strlen_zero(tapcall->callednum)) {
+			ast_copy_string(pri->pvts[chanpos]->exten, tapcall->callednum, sizeof(pri->pvts[chanpos]->exten));
+		} else if (pri->overlapdial)
+			pri->pvts[chanpos]->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 the tapping peers in both pri pvts */
+		peerpri->pvts[peerpos]->tappingpeer = pri->pvts[chanpos];
+		pri->pvts[chanpos]->tappingpeer = peerpri->pvts[peerpos];
+
+		/* create the actual ast_channel but dont start a pbx just yet */
+		law = layer1 == PRI_LAYER_1_ULAW ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW;
+		ast_mutex_unlock(&pri->lock);
+		c = sig_pri_new_ast_channel(pri->pvts[chanpos], AST_STATE_RING, 0, law, AST_TRANS_CAP_SPEECH, pri->pvts[chanpos]->exten, NULL);
+		ast_mutex_lock(&pri->lock);
+		if (!c) {
+			ast_log(LOG_ERROR, "Failed to create channel for PRI call on channel %d/%d on span %d\n",
+				PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
+			peerpri->pvts[peerpos]->tappingpeer = NULL;
+			pri->pvts[chanpos]->tappingpeer = NULL;
+			break;
+		}
+		/* the owner for the peer channel will be the same, both dahdi pvt structures will share the owner */
+		peerpri->pvts[peerpos]->owner = c;
+
+		/* from now on, reading from the conference has the mix of both tapped channels, we can now launch the pbx thread */
+		if (ast_pbx_start(c) != AST_PBX_SUCCESS) {
+			ast_log(LOG_ERROR, "Failed to launch PBX thread for passive channel %s\n", c->name);
+			ast_hangup(c);
+		}
+		break;
+
+	case PRI_EVENT_ANSWER:
+		ast_log(LOG_DEBUG, "Answer on channel %d of span %d\n", e->proceeding.channel, pri->span);
+
+		/* get the chan pos for the answered channel and check we have an owner already */
+		chanpos = pri_find_principle(pri, e->answer.channel);
+		if (chanpos < 0) {
+			ast_log(LOG_ERROR, "Answer requested on odd/unavailable channel number %d/%d on span %d\n",
+				PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
+			break;
+		}
+
+		if (!pri->pvts[chanpos]->owner) {
+			/* 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);
+		break;
+
+	case PRI_EVENT_HANGUP:
+
+		ast_log(LOG_DEBUG, "Hangup on channel %d of span %d\n", e->hangup.channel, pri->span);
+		chanpos = pri_find_principle(pri, e->hangup.channel);
+		if (chanpos < 0) {
+			ast_log(LOG_ERROR, "Hangup requested on odd/unavailable channel number %d/%d on span %d\n",
+				PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
+			break;
+		}
+		/* first put back the passive call slot, if any was used, since 
+		 * 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) {
+			/* 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);
+
+		break;
+
+	case PRI_EVENT_HANGUP_ACK:
+
+		ast_log(LOG_DEBUG, "Hangup ack on channel %d of span %d\n", e->hangup.channel, pri->span);
+		/* put back the passive call slot, if any was used */
+		pri_put_pcall(pri, e->hangup.call);
+		break;
+
+	default:
+		ast_log(LOG_NOTICE, "Ignoring passive event %s on span %d\n", pri_event2str(e->gen.e), pri->span);
+		break;
+	}
+}
+
+static void *pri_tapping_dchannel(void *vpri)
+{
+	struct sig_pri_pri *pri = vpri;
+	pri_event *e;
+	struct pollfd fds[NUM_DCHANS];
+	int res, i, numdchans, which;
+
+	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+	for (;;) {
+		for (i = 0; i < NUM_DCHANS; i++) {
+			if (!pri->dchans[i])
+				break;
+			fds[i].fd = pri->fds[i];
+			fds[i].events = POLLIN | POLLPRI;
+			fds[i].revents = 0;
+		}
+		numdchans = i;
+
+		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+		pthread_testcancel();
+		e = NULL;
+		res = poll(fds, numdchans, -1);
+		pthread_testcancel();
+		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+		if (res == -1 && errno != EINTR) {
+			ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
+			break;
+		} else if (res == -1) {
+			ast_log(LOG_DEBUG, "pri_event got EINT, continuing ...\n");
+			continue;
+		}
+
+		ast_mutex_lock(&pri->lock);
+		for (which = 0; which < NUM_DCHANS; which++) {
+			if (!pri->dchans[which]) {
+				break;
+			}
+			if (fds[which].revents & POLLPRI) {
+				sig_pri_handle_dchan_exception(pri, which);
+			} else if (fds[which].revents & POLLIN) {
+				e = pri_read_event(pri->dchans[which]);
+				if (e && pri->debug) {
+					pri_dump_event(pri->dchans[which], e);
+				}
+				if (e) {
+					handle_pri_tapping_event(pri, e);
+				}
+			}
+		}
+		ast_mutex_unlock(&pri->lock);
+	}
+	ast_log(LOG_NOTICE, "Finishing tapping PRI loop for span %d\n", pri->span);
+	return NULL;
 }
 
 static void *pri_dchannel(void *vpri)
@@ -2407,6 +2707,10 @@
 	p->alerting = 0;
 	p->setup_ack = 0;
 	p->exten[0] = '\0';
+	if (p->tappingpeer) {
+		p->tappingpeer->tappingpeer = NULL;
+		p->tappingpeer = NULL;
+	}
 	sig_pri_set_dialing(p, 0);
 
 	if (!p->call) {
@@ -2998,7 +3302,7 @@
 	/* Assume primary is the one we use */
 	pri->pri = pri->dchans[0];
 	pri->resetpos = -1;
-	if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
+	if (ast_pthread_create_background(&pri->master, NULL, pri->tappingpeer ? pri_tapping_dchannel : pri_dchannel, pri)) {
 		for (i = 0; i < NUM_DCHANS; i++) {
 			if (!pri->dchans[i])
 				break;

Modified: team/moy/dahdi-tap-trunk/channels/sig_pri.h
URL: http://svnview.digium.com/svn/asterisk/team/moy/dahdi-tap-trunk/channels/sig_pri.h?view=diff&rev=220585&r1=220584&r2=220585
==============================================================================
--- team/moy/dahdi-tap-trunk/channels/sig_pri.h (original)
+++ team/moy/dahdi-tap-trunk/channels/sig_pri.h Sat Sep 26 02:13:37 2009
@@ -116,6 +116,16 @@
 static const char dahdi_db[] = "dahdi/registry";
 #endif
 
+/* Passive call structure.
+ * As of now just valid for pri but eventually may be reused for other protocols with monitoring support */
+struct dahdi_tapcall {
+	void *callref;
+	char callingnum[AST_MAX_EXTENSION];
+	char callingani[AST_MAX_EXTENSION];
+	char callingname[AST_MAX_EXTENSION];
+	char callednum[AST_MAX_EXTENSION];
+};
+
 struct sig_pri_chan {
 	/* Options to be set by user */
 	unsigned int hidecallerid:1;
@@ -170,6 +180,7 @@
 #if defined(HAVE_PRI_REVERSE_CHARGE)
 	int reverse_charging_indication;
 #endif
+	struct sig_pri_chan *tappingpeer;               /*!<  Peer tapping pri chan structure */
 };
 
 struct sig_pri_pri {
@@ -222,6 +233,10 @@
 	ast_mutex_t lock;							/*!< libpri access Mutex */
 	time_t lastreset;							/*!< time when unused channels were last reset */
 	struct sig_pri_callback *calls;
+	/* TODO: allocate this structures on demand only when the pri is flagged as passive */
+	struct dahdi_tapcall tapcalls[MAX_CHANNELS];		        /*!< Tap calls if any. */
+	struct sig_pri_pri *tappingpeer;                                /*!< Peer PRI tapping structure. */
+	int tappingpeerpos;                                             /*!< Relative tapping peer position. */
 };
 
 int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, int timeout, int layer1);




More information about the asterisk-commits mailing list