Index: channels/sig_pri.h =================================================================== --- channels/sig_pri.h (.../trunk) (revision 220627) +++ channels/sig_pri.h (.../team/moy/dahdi-tap-trunk) (revision 220627) @@ -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); Index: channels/chan_dahdi.c =================================================================== --- channels/chan_dahdi.c (.../trunk) (revision 220627) +++ channels/chan_dahdi.c (.../team/moy/dahdi-tap-trunk) (revision 220627) @@ -249,6 +249,10 @@ ***/ +#define TAP_PEER_NONE 0 +#define TAP_PEER_NEXT 1 +#define TAP_PEER_PREV 2 + #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */ static const char * const lbostr[] = { @@ -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 @@ -2307,6 +2315,19 @@ int audio; int newlaw = -1; + struct sig_pri_chan *pchan = p->sig_pvt; + struct sig_pri_pri *pri = pchan->pri; + + if (pri->tappingpeer) { + struct dahdi_pvt *pp = pchan->tappingpeer->chan_pvt; + p->tappingpeer = pp; + pp->tappingpeer = p; + audio = 1; + if (ioctl(pp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) { + ast_log(LOG_WARNING, "Unable to set audio mode on peer PRI channel %d: %s\n", pp->channel, strerror(errno)); + } + } + /* Set to audio mode at this point */ audio = 1; if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) @@ -5178,6 +5199,36 @@ idx = dahdi_get_index(ast, p, 1); + if (p->tappingpeer) { + struct dahdi_confinfo pinfo; + struct dahdi_pvt *pp = p->tappingpeer; + + /* remove pvt from the conference */ + memset(&pinfo, 0, sizeof(pinfo)); + ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF); + + /* remove peer pvt from the conference */ + memset(&pinfo, 0, sizeof(pinfo)); + ioctl(pp->subs[SUB_REAL].dfd, DAHDI_SETCONF); + + /* remove the tapping pseudo from the conference */ + memset(&pinfo, 0, sizeof(pinfo)); + ioctl(p->tappingfd, DAHDI_SETCONF); + dahdi_close(p->tappingfd); + + /* if its PRI reset data mode for the peer channel */ + if (dahdi_sig_pri_lib_handles(p->sig)) { + int paudio = 1; + if (ioctl(pp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &paudio) == -1) { + ast_log(LOG_WARNING, "Unable to set data mode on peer channel %d: %s\n", pp->channel, strerror(errno)); + } + } + p->tappingfd = -1; + p->tappingpeer = NULL; + pp->tappingpeer = NULL; + pp->owner = NULL; + } + #ifdef HAVE_PRI if (dahdi_sig_pri_lib_handles(p->sig)) { int law; @@ -7776,40 +7827,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 +8061,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 +8268,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 +8438,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 +8496,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 +11122,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 +11567,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 +16017,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->value, "prev")) { + confp->pri.pri.tappingpeerpos = TAP_PEER_PREV; + } else if (!strcasecmp(v->value, "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")) { Index: channels/sig_pri.c =================================================================== --- channels/sig_pri.c (.../trunk) (revision 220627) +++ channels/sig_pri.c (.../team/moy/dahdi-tap-trunk) (revision 220627) @@ -1227,6 +1227,306 @@ } } +/* 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) { struct sig_pri_pri *pri = 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) { @@ -2944,6 +3248,7 @@ { int x; int i; + int res; ast_mutex_init(&pri->lock); @@ -2998,7 +3303,12 @@ /* 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 (pri->tappingpeer) { + res = ast_pthread_create_background(&pri->master, NULL, pri_tapping_dchannel, pri); + } else { + res = ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri); + } + if (res) { for (i = 0; i < NUM_DCHANS; i++) { if (!pri->dchans[i]) break; Index: include/asterisk/aes.h =================================================================== --- include/asterisk/aes.h (.../trunk) (revision 220627) +++ include/asterisk/aes.h (.../team/moy/dahdi-tap-trunk) (revision 220627) @@ -49,7 +49,6 @@ /* Use the included AES implementation */ -#define AES_128 #include "aes_internal.h" typedef aes_encrypt_ctx ast_aes_encrypt_key;