FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan)
{
	const char *state;
	ftdm_channel_lock(ftdmchan);
	state = ftdm_channel_state2str(ftdmchan->last_state);
	ftdm_channel_unlock(ftdmchan);
	return state;
}
FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan)
{
	int last_state;
	ftdm_channel_lock(ftdmchan);
	last_state = ftdmchan->last_state;
	ftdm_channel_unlock(ftdmchan);
	return last_state;
}
Exemple #3
0
static __inline__ void pritap_check_state(ftdm_span_t *span)
{
    if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
        uint32_t j;
        ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
        for(j = 1; j <= span->chan_count; j++) {
            ftdm_channel_lock(span->channels[j]);
            ftdm_channel_advance_states(span->channels[j]);
            ftdm_channel_unlock(span->channels[j]);
        }
    }
}
Exemple #4
0
static __inline__ ftdm_channel_t *tap_pri_get_fchan(pritap_t *pritap, passive_call_t *pcall, int channel)
{
    ftdm_channel_t *fchan = NULL;
    int err = 0;
    int chanpos = PRI_CHANNEL(channel);
    if (!chanpos || chanpos > pritap->span->chan_count) {
        ftdm_log(FTDM_LOG_CRIT, "Invalid pri tap channel %d requested in span %s\n", channel, pritap->span->name);
        return NULL;
    }

    fchan = pritap->span->channels[PRI_CHANNEL(channel)];

    ftdm_channel_lock(fchan);

    if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
        ftdm_log(FTDM_LOG_ERROR, "Channel %d requested in span %s is already in use!\n", channel, pritap->span->name);
        err = 1;
        goto done;
    }

    if (ftdm_channel_open_chan(fchan) != FTDM_SUCCESS) {
        ftdm_log(FTDM_LOG_ERROR, "Could not open tap channel %d requested in span %s\n", channel, pritap->span->name);
        err = 1;
        goto done;
    }

    memset(&fchan->caller_data, 0, sizeof(fchan->caller_data));

    ftdm_set_string(fchan->caller_data.cid_num.digits, pcall->callingnum.digits);
    if (!ftdm_strlen_zero(pcall->callingname)) {
        ftdm_set_string(fchan->caller_data.cid_name, pcall->callingname);
    } else {
        ftdm_set_string(fchan->caller_data.cid_name, pcall->callingnum.digits);
    }
    ftdm_set_string(fchan->caller_data.ani.digits, pcall->callingani.digits);
    ftdm_set_string(fchan->caller_data.dnis.digits, pcall->callednum.digits);

done:
    if (fchan) {
        ftdm_channel_unlock(fchan);
    }

    if (err) {
        return NULL;
    }

    return fchan;
}
static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found)
{
    sngisdn_chan_data_t *sngisdn_info;
    ftdm_channel_t *ftdmchan = NULL;
    ftdm_iterator_t *chaniter = NULL;
    ftdm_iterator_t *curr = NULL;
    ftdm_status_t status = FTDM_FAIL;
    uint8_t outbound_call = 0;

    if ((!frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_OUTGOING) ||
            (frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_INCOMING)) {

        /* If this is an outgoing frame and this frame was sent by the originating side
        	of the call (frame_info.call_ref_flag == 0), then this is an outbound call */
        outbound_call = 1;
    } else {
        outbound_call = 0;
    }

    switch (frame_info.msgtype) {
    case PROT_Q931_MSGTYPE_SETUP:
        /* We initiated this outgoing call try to match the call reference with our internal call-id*/
        if (!frame_info.bchan_no) {
            /* We were not able to determine the bchannel on this call, so we will not be able to match it anyway */
            status = FTDM_FAIL;
        }

        chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
        for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
            ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr));
            ftdm_channel_lock(ftdmchan);

            if (outbound_call) {
                sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
                if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
                    if (ftdmchan->caller_data.call_id && ftdmchan->physical_chan_id == frame_info.bchan_no) {

                        sngisdn_info->call_ref = frame_info.call_ref;
                        *found = ftdmchan;
                        status = FTDM_SUCCESS;
                    }
                }
            } else {
                if (ftdmchan->physical_chan_id == frame_info.bchan_no) {
                    *found = ftdmchan;
                    status = FTDM_SUCCESS;
                }
            }
            ftdm_channel_unlock(ftdmchan);
        }
        ftdm_iterator_free(chaniter);
        break;
    case PROT_Q931_MSGTYPE_ALERTING:
    case PROT_Q931_MSGTYPE_PROCEEDING:
    case PROT_Q931_MSGTYPE_PROGRESS:
    case PROT_Q931_MSGTYPE_CONNECT:
    case PROT_Q931_MSGTYPE_SETUP_ACK:
    case PROT_Q931_MSGTYPE_CONNECT_ACK:
    case PROT_Q931_MSGTYPE_USER_INFO:
    case PROT_Q931_MSGTYPE_DISCONNECT:
    case PROT_Q931_MSGTYPE_RELEASE:
    case PROT_Q931_MSGTYPE_RELEASE_ACK:
    case PROT_Q931_MSGTYPE_RELEASE_COMPLETE:
    case PROT_Q931_MSGTYPE_FACILITY:
    case PROT_Q931_MSGTYPE_NOTIFY:
    case PROT_Q931_MSGTYPE_STATUS_ENQUIRY:
    case PROT_Q931_MSGTYPE_INFORMATION:
    case PROT_Q931_MSGTYPE_STATUS:
        /* Look for an outbound call on that span and and try to match the call-id */
        chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
        for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
            ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr));
            ftdm_channel_lock(ftdmchan);
            sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
            if (outbound_call) {
                if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
                    if (sngisdn_info->call_ref == frame_info.call_ref) {

                        *found = ftdmchan;
                        status = FTDM_SUCCESS;
                    }
                }
            } else {
                if (sngisdn_info && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
                    if (sngisdn_info->call_ref && sngisdn_info->call_ref == frame_info.call_ref) {

                        *found = ftdmchan;
                        status = FTDM_SUCCESS;
                    }
                }
            }
            ftdm_channel_unlock(ftdmchan);
        }
        ftdm_iterator_free(chaniter);
        break;
    default:
        /* This frame is not call specific, ignore */
        break;
    }
    if (status == FTDM_SUCCESS) {
        ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Mapped %s with Call Ref:%04x to call-id:%d\n", get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref, (*found)->caller_data.call_id);
    } else {
        /* We could not map this frame to a call-id */
        ftdm_log(FTDM_LOG_DEBUG, "Failed to map %s with Call Ref:%04x to local call\n",
                 get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref);
    }

    return status;
}
Exemple #6
0
static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj)
{

	ftdm_log(FTDM_LOG_INFO,"ftdm_gsm_run\r\n");

	ftdm_channel_t *ftdmchan = NULL;
	ftdm_span_t *span = (ftdm_span_t *) obj;
	ftdm_gsm_span_data_t *gsm_data = NULL;
	ftdm_interrupt_t *data_sources[2] = {NULL, NULL};
	int waitms = 0;
	
	gsm_data = span->signal_data;

	ftdm_assert_return(gsm_data != NULL, NULL, "No gsm data attached to span\n");

	ftdm_log(FTDM_LOG_DEBUG, "GSM monitor thread for span %s started\n", span->name);
	if (!gsm_data->dchan || ftdm_channel_open_chan(gsm_data->dchan) != FTDM_SUCCESS) {
		ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open GSM d-channel of span %s!\n", span->name);
		gsm_data->dchan = NULL;
		goto done;
	}




	while (ftdm_running()) {

		wat_span_run(span->span_id);

		waitms = wat_span_schedule_next(span->span_id);
		if (waitms > GSM_POLL_INTERVAL_MS) {
			waitms = GSM_POLL_INTERVAL_MS;
		}

/////////////////////
		

		{
			ftdm_wait_flag_t flags = FTDM_READ | FTDM_EVENTS;
			ftdm_status_t status = ftdm_channel_wait(gsm_data->dchan, &flags, waitms);
			
	
			/* double check that this channel has a state change pending */
			ftdm_channel_lock(gsm_data->bchan);
			ftdm_channel_advance_states(gsm_data->bchan);
					
			if(FTDM_SUCCESS == status ) {
		
				if(flags &FTDM_READ ) {
					char buffer[1025];
					int n = 0, m = 0;
					memset(buffer, 0, sizeof(buffer));

					n = read_channel(gsm_data->dchan, buffer, sizeof(buffer)-1);
					m = strlen(buffer);	
					wat_span_process_read(span->span_id, buffer, m);
#if 	 LOG_SIG_DATA
						printf("<<======================= incomming data len = %d, %s\r\n", n, buffer);
#endif

				}
			}
			
			ftdm_channel_advance_states(gsm_data->bchan);
			
			ftdm_channel_unlock(gsm_data->bchan);
			

		}


		

		ftdm_span_trigger_signals(span);


	}

done:
	if (data_sources[0]) {
		ftdm_interrupt_destroy(&data_sources[0]);
	}

	ftdm_log(FTDM_LOG_DEBUG, "GSM thread ending.\n");

	return NULL;
}
Exemple #7
0
static void handle_pri_passive_event(pritap_t *pritap, pri_event *e)
{
    passive_call_t *pcall = NULL;
    passive_call_t *peerpcall = NULL;
    ftdm_channel_t *fchan = NULL;
    ftdm_channel_t *peerfchan = NULL;
    int layer1, transcap = 0;
    int crv = 0;
    pritap_t *peertap = pritap->peerspan->signal_data;

    switch (e->e) {

    case PRI_EVENT_RING:
        /* we cannot use ftdm_channel_t because we still dont know which channel will be used
         * (ie, flexible channel was requested), thus, we need our own list of call references */
        crv = tap_pri_get_crv(pritap->pri, e->ring.call);
        ftdm_log(FTDM_LOG_DEBUG, "Ring on channel %s:%d:%d with callref %d\n",
                 pritap->span->name, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), crv);
        pcall = tap_pri_get_pcall_bycrv(pritap, crv);
        if (pcall) {
            ftdm_log(FTDM_LOG_WARNING, "There is a call with callref %d already, ignoring duplicated ring event\n", crv);
            break;
        }

        /* Try to get a recycled call (ie, e->ring.call is a call that the PRI stack allocated previously and then
         * re-used for the next RING event because we did not destroy it fast enough) */
        pcall = tap_pri_get_pcall(pritap, e->ring.call);
        if (!pcall) {
            /* ok so the call is really not known to us, let's get a new one */
            pcall = tap_pri_get_pcall(pritap, NULL);
            if (!pcall) {
                ftdm_log(FTDM_LOG_ERROR, "Failed to get a free passive PRI call slot for callref %d, this is a bug!\n", crv);
                break;
            }
        }
        pcall->callref = e->ring.call;
        ftdm_set_string(pcall->callingnum.digits, e->ring.callingnum);
        ftdm_set_string(pcall->callingani.digits, e->ring.callingani);
        ftdm_set_string(pcall->callednum.digits, e->ring.callednum);
        ftdm_set_string(pcall->callingname, e->ring.callingname);
        break;

    case PRI_EVENT_PROGRESS:
        crv = tap_pri_get_crv(pritap->pri, e->proceeding.call);
        ftdm_log(FTDM_LOG_DEBUG, "Progress on channel %s:%d:%d with callref %d\n",
                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
        break;

    case PRI_EVENT_PROCEEDING:
        crv = tap_pri_get_crv(pritap->pri, e->proceeding.call);
        /* at this point we should know the real b chan that will be used and can therefore proceed to notify about the call, but
         * only if a couple of call tests are passed first */
        ftdm_log(FTDM_LOG_DEBUG, "Proceeding on channel %s:%d:%d with callref %d\n",
                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);

        /* check that we already know about this call in the peer PRI (which was the one receiving the PRI_EVENT_RING event) */
        if (!(pcall = tap_pri_get_pcall_bycrv(peertap, crv))) {
            ftdm_log(FTDM_LOG_DEBUG,
                     "ignoring proceeding in channel %s:%d:%d for callref %d since we don't know about it\n",
                     pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
            break;
        }
        if (pcall->proceeding) {
            ftdm_log(FTDM_LOG_DEBUG, "Ignoring duplicated proceeding with callref %d\n", crv);
            break;
        }
        pcall->proceeding = 1;

        /* This call should not be known to this PRI yet ... */
        if ((peerpcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
            ftdm_log(FTDM_LOG_ERROR,
                     "ignoring proceeding in channel %s:%d:%d for callref %d, dup???\n",
                     pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
            break;
        }

        /* Check if the call pointer is being recycled */
        peerpcall = tap_pri_get_pcall(pritap, e->proceeding.call);
        if (!peerpcall) {
            peerpcall = tap_pri_get_pcall(pritap, NULL);
            if (!peerpcall) {
                ftdm_log(FTDM_LOG_ERROR, "Failed to get a free peer PRI passive call slot for callref %d in span %s, this is a bug!\n",
                         crv, pritap->span->name);
                break;
            }
            peerpcall->callref = e->proceeding.call;
        }

        /* check that the layer 1 and trans capability are supported */
        layer1 = pri_get_layer1(peertap->pri, pcall->callref);
        transcap = pri_get_transcap(peertap->pri, pcall->callref);

        if (PRI_LAYER_1_ULAW != layer1 && PRI_LAYER_1_ALAW != layer1) {
            ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported layer 1 format %d\n", crv, layer1);
            break;
        }

        if (transcap != PRI_TRANS_CAP_SPEECH && transcap != PRI_TRANS_CAP_3_1K_AUDIO && transcap != PRI_TRANS_CAP_7K_AUDIO) {
            ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported capability %d\n", crv, transcap);
            break;
        }

        fchan = tap_pri_get_fchan(pritap, pcall, e->proceeding.channel);
        if (!fchan) {
            ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n",
                     pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
            break;
        }

        peerfchan = tap_pri_get_fchan(peertap, pcall, e->proceeding.channel);
        if (!peerfchan) {
            ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n",
                     peertap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
            break;
        }
        pcall->fchan = fchan;
        peerpcall->fchan = fchan;

        ftdm_log_chan(fchan, FTDM_LOG_NOTICE, "Starting new tapped call with callref %d\n", crv);

        ftdm_channel_lock(fchan);
        fchan->call_data = peerfchan;
        ftdm_set_state(fchan, FTDM_CHANNEL_STATE_RING);
        ftdm_channel_unlock(fchan);

        ftdm_channel_lock(peerfchan);
        peerfchan->call_data = fchan;
        ftdm_channel_unlock(peerfchan);

        break;

    case PRI_EVENT_ANSWER:
        crv = tap_pri_get_crv(pritap->pri, e->answer.call);
        ftdm_log(FTDM_LOG_DEBUG, "Answer on channel %s:%d:%d with callref %d\n",
                 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
        if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
            ftdm_log(FTDM_LOG_DEBUG,
                     "ignoring answer in channel %s:%d:%d for callref %d since we don't know about it\n",
                     pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->proceeding.channel), crv);
            break;
        }
        if (!pcall->fchan) {
            ftdm_log(FTDM_LOG_ERROR,
                     "Received answer in channel %s:%d:%d for callref %d but we never got a channel\n",
                     pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
            break;
        }
        ftdm_channel_lock(pcall->fchan);
        ftdm_log_chan(pcall->fchan, FTDM_LOG_NOTICE, "Tapped call was answered in state %s\n", ftdm_channel_state2str(pcall->fchan->state));
        ftdm_set_pflag(pcall->fchan, PRITAP_NETWORK_ANSWER);
        ftdm_set_state(pcall->fchan, FTDM_CHANNEL_STATE_UP);
        ftdm_channel_unlock(pcall->fchan);
        break;

    case PRI_EVENT_HANGUP_REQ:
        crv = tap_pri_get_crv(pritap->pri, e->hangup.call);

        ftdm_log(FTDM_LOG_DEBUG, "Hangup on channel %s:%d:%d with callref %d\n",
                 pritap->span->name, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), crv);

        if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
            ftdm_log(FTDM_LOG_DEBUG,
                     "ignoring hangup in channel %s:%d:%d for callref %d since we don't know about it",
                     pritap->span->name, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), crv);
            break;
        }

        if (pcall->fchan) {
            fchan = pcall->fchan;
            ftdm_channel_lock(fchan);
            if (fchan->state < FTDM_CHANNEL_STATE_TERMINATING) {
                ftdm_set_state(fchan, FTDM_CHANNEL_STATE_TERMINATING);
            }
            pcall->fchan = NULL; /* after this event we're not supposed to need to do anything with the channel anymore */
            ftdm_channel_unlock(fchan);
        }

        tap_pri_put_pcall(pritap, e->hangup.call);
        tap_pri_put_pcall(peertap, e->hangup.call);
        break;

    case PRI_EVENT_HANGUP_ACK:
        crv = tap_pri_get_crv(pritap->pri, e->hangup.call);
        ftdm_log(FTDM_LOG_DEBUG, "Hangup ack on channel %s:%d:%d with callref %d\n",
                 pritap->span->name, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), crv);
        tap_pri_put_pcall(pritap, e->hangup.call);
        tap_pri_put_pcall(peertap, e->hangup.call);
        break;

    default:
        ftdm_log(FTDM_LOG_DEBUG, "Ignoring passive event %s on span %s\n", pri_event2str(e->gen.e), pritap->span->name);
        break;

    }
}
Exemple #8
0
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
    ftdm_status_t status;
    ftdm_sigmsg_t sig;
    pritap_t *pritap = ftdmchan->span->signal_data;
    pritap_t *peer_pritap = pritap->peerspan->signal_data;

    ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state %s\n", ftdm_channel_state2str(ftdmchan->state));

    memset(&sig, 0, sizeof(sig));
    sig.chan_id = ftdmchan->chan_id;
    sig.span_id = ftdmchan->span_id;
    sig.channel = ftdmchan;

    ftdm_channel_complete_state(ftdmchan);

    switch (ftdmchan->state) {
    case FTDM_CHANNEL_STATE_DOWN:
    {
        ftdm_channel_t *fchan = ftdmchan;

        /* Destroy the peer data first */
        if (fchan->call_data) {
            ftdm_channel_t *peerchan = fchan->call_data;
            ftdm_channel_t *pchan = peerchan;

            ftdm_channel_lock(peerchan);

            pchan->call_data = NULL;
            pchan->pflags = 0;
            ftdm_channel_close(&pchan);

            ftdm_channel_unlock(peerchan);
        } else {
            ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "No call data?\n");
        }

        ftdmchan->call_data = NULL;
        ftdmchan->pflags = 0;
        ftdm_channel_close(&fchan);
    }
    break;

    case FTDM_CHANNEL_STATE_PROGRESS:
    case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
    case FTDM_CHANNEL_STATE_HANGUP:
        break;

    case FTDM_CHANNEL_STATE_UP:
    {
        if (ftdm_test_pflag(ftdmchan, PRITAP_NETWORK_ANSWER)) {
            ftdm_clear_pflag(ftdmchan, PRITAP_NETWORK_ANSWER);
            sig.event_id = FTDM_SIGEVENT_UP;
            ftdm_span_send_signal(ftdmchan->span, &sig);
        }
    }
    break;

    case FTDM_CHANNEL_STATE_RING:
    {
        sig.event_id = FTDM_SIGEVENT_START;
        /* The ring interface (where the setup was received) is the peer, since we RING the channel
         * where PROCEED/PROGRESS is received */
        ftdm_sigmsg_add_var(&sig, "pritap_ring_interface", PRITAP_GET_INTERFACE(peer_pritap->iface));
        if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
            ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
        }
    }
    break;

    case FTDM_CHANNEL_STATE_TERMINATING:
    {
        if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP) {
            sig.event_id = FTDM_SIGEVENT_STOP;
            status = ftdm_span_send_signal(ftdmchan->span, &sig);
        }
        ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
    }
    break;

    default:
    {
        ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ignoring state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(ftdmchan->state));
    }
    break;
    }

    return FTDM_SUCCESS;
}