Beispiel #1
0
static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
{
	int chanid = ftdm_channel_get_ph_id(sigmsg->channel);
	ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
	switch (sigmsg->event_id) {
	case FTDM_SIGEVENT_START:
		{
			ftdm_mutex_lock(the_mutex);
			if (!fchan) {
				fchan = sigmsg->channel;
				indication = FTDM_CHANNEL_INDICATE_PROCEED;
			}
			ftdm_mutex_unlock(the_mutex);
		}
		break;
	case FTDM_SIGEVENT_INDICATION_COMPLETED:
		{
			ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
			if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROCEED) {
				ftdm_log(FTDM_LOG_DEBUG, "Proceed indication result = %d\n", sigmsg->ev_data.indication_completed.status);
				ind = FTDM_CHANNEL_INDICATE_PROGRESS;
			} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS) {
				ftdm_log(FTDM_LOG_DEBUG, "Progress indication result = %d\n", sigmsg->ev_data.indication_completed.status);
				ind = FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA;
			} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA) {
				ftdm_log(FTDM_LOG_DEBUG, "Progress media indication result = %d\n", sigmsg->ev_data.indication_completed.status);
				ind = FTDM_CHANNEL_INDICATE_ANSWER;
			} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_ANSWER) {
				ftdm_log(FTDM_LOG_DEBUG, "Answer indication result = %d\n", sigmsg->ev_data.indication_completed.status);
			} else {
				ftdm_log(FTDM_LOG_DEBUG, "Unexpected indication, result = %d\n", sigmsg->ev_data.indication_completed.status);
				exit(1);
			}
			ftdm_mutex_lock(the_mutex);
			if (fchan) {
				indication = ind;
			}
			ftdm_mutex_unlock(the_mutex);
		}
		break;
	case FTDM_SIGEVENT_STOP:
		{
			ftdm_channel_call_hangup(sigmsg->channel);
		}
		break;
	case FTDM_SIGEVENT_RELEASED:
		{
			ftdm_mutex_lock(the_mutex);
			if (fchan && fchan == sigmsg->channel) {
				fchan = NULL;
			}
			ftdm_mutex_unlock(the_mutex);
		}
		break;
	default:
		break;
	}
	return FTDM_SUCCESS;
}
Beispiel #2
0
FT_DECLARE(ftdm_status_t) ftdm_sched_destroy(ftdm_sched_t **insched)
{
	ftdm_sched_t *sched = NULL;
	ftdm_timer_t *timer;
	ftdm_timer_t *deltimer;
	ftdm_assert_return(insched != NULL, FTDM_EINVAL, "sched is null!\n");
	ftdm_assert_return(*insched != NULL, FTDM_EINVAL, "sched is null!\n");

	sched = *insched;

	/* since destroying a sched may affect the global list, we gotta check */	
	ftdm_mutex_lock(sched_globals.mutex);

	/* if we're head, replace head with our next (whatever our next is, even null will do) */
	if (sched == sched_globals.freeruns) {
		sched_globals.freeruns = sched->next;
	}
	/* if we have a previous member (then we were not head) set our previous next to our next */
	if (sched->prev) {
		sched->prev->next = sched->next;
	}
	/* if we have a next then set their prev to our prev (if we were head prev will be null and sched->next is already the new head) */
	if (sched->next) {
		sched->next->prev = sched->prev;
	}

	ftdm_mutex_unlock(sched_globals.mutex);

	/* now grab the sched mutex */
	ftdm_mutex_lock(sched->mutex);

	timer = sched->timers;
	while (timer) {
		deltimer = timer;
		timer = timer->next;
		ftdm_safe_free(deltimer);
	}

	ftdm_log(FTDM_LOG_DEBUG, "Destroying schedule %s\n", sched->name);

	ftdm_mutex_unlock(sched->mutex);

	ftdm_mutex_destroy(&sched->mutex);

	ftdm_safe_free(sched);

	*insched = NULL;
	return FTDM_SUCCESS;
}
Beispiel #3
0
static void tap_pri_put_pcall(pritap_t *pritap, void *callref)
{
    int i;
    int crv;
    int tstcrv;

    if (!callref) {
        ftdm_log(FTDM_LOG_ERROR, "Cannot put pcall for null callref in span %s\n", pritap->span->name);
        return;
    }

    ftdm_mutex_lock(pritap->pcalls_lock);

    crv = tap_pri_get_crv(pritap->pri, callref);
    for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
        if (!pritap->pcalls[i].callref) {
            continue;
        }
        tstcrv = tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref);
        if (tstcrv == crv) {
            if (pritap->pcalls[i].inuse) {
                ftdm_log(FTDM_LOG_DEBUG, "releasing slot %d in span %s used by callref %d/%p\n", i,
                         pritap->span->name, crv, pritap->pcalls[i].callref);
                pritap->pcalls[i].inuse = 0;
            }
        }
    }

    ftdm_mutex_unlock(pritap->pcalls_lock);
}
Beispiel #4
0
static void handle_SIGINT(int sig)
{
	ftdm_mutex_lock(mutex);
	R = 0;
	ftdm_mutex_unlock(mutex);
	return;
}
Beispiel #5
0
/* FUNCTIONS ******************************************************************/
void handle_isup_t35(void *userdata)
{
    SS7_FUNC_TRACE_ENTER(__FUNCTION__);

    sngss7_timer_data_t *timer = userdata;
    sngss7_chan_data_t  *sngss7_info = timer->sngss7_info;
    ftdm_channel_t      *ftdmchan = sngss7_info->ftdmchan;

    /* now that we have the right channel...put a lock on it so no-one else can use it */
    ftdm_mutex_lock(ftdmchan->mutex);

    SS7_ERROR("[Call-Control] Timer 35 expired on CIC = %d\n", sngss7_info->circuit->cic);

    /* set the flag to indicate this hangup is started from the local side */
    sngss7_set_ckt_flag(sngss7_info, FLAG_LOCAL_REL);

    /* hang up on timer expiry */
    ftdmchan->caller_data.hangup_cause = 28;

    /* end the call */
    ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);

    /*unlock*/
    ftdm_mutex_unlock(ftdmchan->mutex);

    SS7_FUNC_TRACE_EXIT(__FUNCTION__);
    return;
}
void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces)
{
	uint8_t bchan_no = 0;
	sngisdn_chan_data_t *sngisdn_info = NULL;
	sngisdn_event_data_t *sngisdn_event = NULL;

	ISDN_FUNC_TRACE_ENTER(__FUNCTION__);

	ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n");
	ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n");
		
	if (conEvnt->chanId.eh.pres != PRSNT_NODEF) {
		/* TODO: Implement me */
		ftdm_log(FTDM_LOG_ERROR, "Incoming call without Channel Id not supported yet\n");
		ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
		return;
	}

	if (conEvnt->chanId.chanNmbSlotMap.pres) {
		bchan_no = conEvnt->chanId.chanNmbSlotMap.val[0];
	} else if (conEvnt->chanId.infoChanSel.pres) {
		bchan_no = conEvnt->chanId.infoChanSel.val;
	}

	if (!bchan_no) {
		ftdm_log(FTDM_LOG_ERROR, "Failed to obtain b-channel number from SETUP message\n");
		ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
		return;
	}

	if (g_sngisdn_data.dchans[dChan].channels[bchan_no] == NULL) {
		ftdm_log(FTDM_LOG_ERROR, "Incoming call on unconfigured b-channel:%d\n", bchan_no);
		ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
		return;
	}

	sngisdn_info = g_sngisdn_data.dchans[dChan].channels[bchan_no];

	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId);
	
	sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event));
	ftdm_assert(sngisdn_event, "Failed to allocate memory\n");
	memset(sngisdn_event, 0, sizeof(*sngisdn_event));

	sngisdn_event->event_id = SNGISDN_EVENT_CON_IND;
	sngisdn_event->sngisdn_info = sngisdn_info;
	sngisdn_event->suId = suId;
	sngisdn_event->spInstId = spInstId;
	sngisdn_event->dChan = dChan;
	sngisdn_event->ces = ces;

	ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex);
	g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;	
	ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex);

	memcpy(&sngisdn_event->event.conEvnt, conEvnt, sizeof(*conEvnt));

	ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event);
	ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
}
Beispiel #7
0
static passive_call_t *tap_pri_get_pcall_bycrv(pritap_t *pritap, int crv)
{
    int i;
    int tstcrv;

    ftdm_mutex_lock(pritap->pcalls_lock);

    for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
        tstcrv = pritap->pcalls[i].callref ? tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref) : 0;
        if (pritap->pcalls[i].callref && tstcrv == crv) {
            if (pritap->pcalls[i].inuse) {
                ftdm_mutex_unlock(pritap->pcalls_lock);
                return &pritap->pcalls[i];
            }
            /* This just means the crv is being re-used in another call before this one was destroyed */
            ftdm_log(FTDM_LOG_DEBUG, "Found crv %d in slot %d of span %s with call %p but is no longer in use\n",
                     crv, i, pritap->span->name, pritap->pcalls[i].callref);
        }
    }

    ftdm_log(FTDM_LOG_DEBUG, "crv %d was not found active in span %s\n", crv, pritap->span->name);

    ftdm_mutex_unlock(pritap->pcalls_lock);

    return NULL;
}
Beispiel #8
0
FT_DECLARE(ftdm_status_t) ftdm_sched_get_time_to_next_timer(const ftdm_sched_t *sched, int32_t *timeto)
{
	ftdm_status_t status = FTDM_FAIL;
	int res = -1;
	int ms = 0;
	struct timeval currtime;
	ftdm_timer_t *current = NULL;
	ftdm_timer_t *winner = NULL;
	
	/* forever by default */
	*timeto = -1;

	ftdm_mutex_lock(sched->mutex);

	res = gettimeofday(&currtime, NULL);
	if (-1 == res) {
		ftdm_log(FTDM_LOG_ERROR, "Failed to get next event time\n");
		goto done;
	}
	status = FTDM_SUCCESS;
	current = sched->timers;
	while (current) {
		/* if no winner, set this as winner */
		if (!winner) {
			winner = current;
		}
		current = current->next;
		/* if no more timers, return the winner */
		if (!current) {
			ms = (((winner->time.tv_sec - currtime.tv_sec) * 1000) + 
			     ((winner->time.tv_usec - currtime.tv_usec) / 1000));

			/* if the timer is expired already, return 0 to attend immediately */
			if (ms < 0) {
				*timeto = 0;
				break;
			}
			*timeto = ms;
			break;
		}

		/* if the winner timer is after the current timer, then we have a new winner */
		if (winner->time.tv_sec > current->time.tv_sec
		    || (winner->time.tv_sec == current->time.tv_sec &&
		       winner->time.tv_usec > current->time.tv_usec)) {
			winner = current;
		}
	}

done:
	ftdm_mutex_unlock(sched->mutex);
#ifdef __WINDOWS__
	UNREFERENCED_PARAMETER(timeto);
	UNREFERENCED_PARAMETER(sched);
#endif

	return status;
}
Beispiel #9
0
static void *run_main_schedule(ftdm_thread_t *thread, void *data)
{
	int32_t timeto;
	int32_t sleepms;
	ftdm_status_t status;
	ftdm_sched_t *current = NULL;
#ifdef __WINDOWS__
	UNREFERENCED_PARAMETER(data);
	UNREFERENCED_PARAMETER(thread);
#endif
	while (ftdm_running()) {
		
		sleepms = SCHED_MAX_SLEEP;

		ftdm_mutex_lock(sched_globals.mutex);

		if (!sched_globals.freeruns) {
		
			/* there are no free runs, wait a bit and check again (FIXME: use ftdm_interrupt_t for this) */
			ftdm_mutex_unlock(sched_globals.mutex);

			if (ftdm_running()) {
				ftdm_sleep(sleepms);
			}
		}

		for (current = sched_globals.freeruns; current; current = current->next) {
			if (!ftdm_running()) {
				break;
			}

			/* first run the schedule */
			ftdm_sched_run(current);

			/* now find out how much time to sleep until running them again */
			status = ftdm_sched_get_time_to_next_timer(current, &timeto);
			if (status != FTDM_SUCCESS) {
				ftdm_log(FTDM_LOG_WARNING, "Failed to get time to next timer for schedule %s, skipping\n", current->name);	
				continue;
			}

			/* if timeto == -1 we don't want to sleep forever, so keep the last sleepms */
			if (timeto != -1 && sleepms > timeto) {
				sleepms = timeto;
			}
		}

		ftdm_mutex_unlock(sched_globals.mutex);

		if (ftdm_running()) {
			ftdm_sleep(sleepms);
		}
	}
	ftdm_log(FTDM_LOG_NOTICE, "Main scheduling thread going out ...\n");
	sched_globals.running = 0;
	return NULL;
}
Beispiel #10
0
FT_DECLARE(ftdm_status_t) ftdm_sched_free_run(ftdm_sched_t *sched)
{
	ftdm_status_t status = FTDM_FAIL;
	ftdm_assert_return(sched != NULL, FTDM_EINVAL, "invalid pointer\n");

	ftdm_mutex_lock(sched->mutex);

	ftdm_mutex_lock(sched_globals.mutex);

	if (sched->freerun) {
		ftdm_log(FTDM_LOG_ERROR, "Schedule %s is already running in free run\n", sched->name);
		goto done;
	}
	sched->freerun = 1;

	if (sched_globals.running == FTDM_FALSE) {
		ftdm_log(FTDM_LOG_NOTICE, "Launching main schedule thread\n");
		status = ftdm_thread_create_detached(run_main_schedule, NULL);
		if (status != FTDM_SUCCESS) {
			ftdm_log(FTDM_LOG_CRIT, "Failed to launch main schedule thread\n");
			goto done;
		} 
		sched_globals.running = FTDM_TRUE;
	}

	ftdm_log(FTDM_LOG_DEBUG, "Running schedule %s in the main schedule thread\n", sched->name);
	status = FTDM_SUCCESS;
	
	/* Add the schedule to the global list of free runs */
	if (!sched_globals.freeruns) {
		sched_globals.freeruns = sched;
	}  else {
		sched->next = sched_globals.freeruns;
		sched_globals.freeruns->prev = sched;
		sched_globals.freeruns = sched;
	}

done:
	ftdm_mutex_unlock(sched_globals.mutex);

	ftdm_mutex_unlock(sched->mutex);
	return status;
}
void sngisdn_delayed_setup(void* p_sngisdn_info)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;

	ftdm_mutex_lock(ftdmchan->mutex);
	sngisdn_snd_setup(ftdmchan);
	ftdm_mutex_unlock(ftdmchan->mutex);
	return;
}
Beispiel #12
0
int main(int argc, char *argv[])
{
	ftdm_span_t *span;
	ftdm_mutex_create(&mutex);

	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);

	if (argc < 2) {
		printf("umm no\n");
		exit(-1);
	}

	if (ftdm_global_init() != FTDM_SUCCESS) {
		fprintf(stderr, "Error loading FreeTDM\n");
		exit(-1);
	}

	printf("FreeTDM loaded\n");

	if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
		fprintf(stderr, "Error finding FreeTDM span\n");
		goto done;
	}
	


	if (ftdm_configure_span("r2", span, on_r2_signal,
						   "variant", "mx",
						   "max_ani", 10,
						   "max_dnis", 4,
						   "logging", "all",
						   TAG_END) == FTDM_SUCCESS) {
						   

		ftdm_span_start(span);
	} else {
		fprintf(stderr, "Error starting R2 span\n");
		goto done;
	}

	signal(SIGINT, handle_SIGINT);
	ftdm_mutex_lock(mutex);
	R = 1;
	ftdm_mutex_unlock(mutex);
	while(R) {
		ftdm_sleep(1 * 1000);
	}

 done:

	ftdm_global_destroy();

	return 1;

}
void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, int16_t dChan, uint8_t ces)
{	
	sngisdn_chan_data_t *sngisdn_info = NULL;
	sngisdn_event_data_t *sngisdn_event = NULL;
	
	ISDN_FUNC_TRACE_ENTER(__FUNCTION__);

	ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Cnst Ind on unconfigured cc\n");
	ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Cnst Ind on unconfigured dchan\n");

	if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) {
		ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId);
		ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
		return;
	}

	if (!sngisdn_info->spInstId) {
		ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex);

		sngisdn_info->spInstId = spInstId;
		g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
		ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex);
	}

	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received %s (suId:%u suInstId:%u spInstId:%u ces:%d)\n",
													(evntType == MI_ALERTING)?"ALERT":
													(evntType == MI_CALLPROC)?"PROCEED":
													(evntType == MI_PROGRESS)?"PROGRESS":
													(evntType == MI_SETUPACK)?"SETUP ACK":
													(evntType == MI_NOTIFY)?"NOTIFY":
													(evntType == MI_INFO)?"INFO":"UNKNOWN",
															suId, suInstId, spInstId, ces);

	sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event));
	ftdm_assert(sngisdn_event, "Failed to allocate memory\n");
	memset(sngisdn_event, 0, sizeof(*sngisdn_event));

	sngisdn_event->event_id = SNGISDN_EVENT_CNST_IND;
	sngisdn_event->sngisdn_info = sngisdn_info;
	sngisdn_event->suId = suId;
	sngisdn_event->suInstId = suInstId;
	sngisdn_event->spInstId = spInstId;
	sngisdn_event->dChan = dChan;
	sngisdn_event->ces = ces;
	sngisdn_event->evntType = evntType;

	memcpy(&sngisdn_event->event.cnStEvnt, cnStEvnt, sizeof(*cnStEvnt));
	
	ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event);
	ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
}
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
{
	ConEvnt conEvnt;
	sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
	ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};	

	ftdm_assert((!sngisdn_info->suInstId && !sngisdn_info->spInstId), "Trying to call out, but call data was not cleared\n");
	
	sngisdn_info->suInstId = get_unique_suInstId(signal_data->cc_id);
	sngisdn_info->spInstId = 0;

	ftdm_mutex_lock(g_sngisdn_data.ccs[signal_data->cc_id].mutex);
	g_sngisdn_data.ccs[signal_data->cc_id].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info;
	ftdm_mutex_unlock(g_sngisdn_data.ccs[signal_data->cc_id].mutex);

	memset(&conEvnt, 0, sizeof(conEvnt));
	if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN || signal_data->force_sending_complete == SNGISDN_OPT_TRUE) {
		conEvnt.sndCmplt.eh.pres = PRSNT_NODEF;
	}
	
	if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
		signal_data->signalling == SNGISDN_SIGNALING_NET) {
		sngisdn_info->ces = CES_MNGMNT;
	}
	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Outgoing call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits);

	set_chan_id_ie(ftdmchan, &conEvnt.chanId);	
	set_bear_cap_ie(ftdmchan, &conEvnt.bearCap[0]);
	set_called_num(ftdmchan, &conEvnt.cdPtyNmb);
	set_calling_num(ftdmchan, &conEvnt.cgPtyNmb);
	set_calling_num2(ftdmchan, &conEvnt.cgPtyNmb2);
	set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad);
	set_called_subaddr(ftdmchan, &conEvnt.cdPtySad);
	set_redir_num(ftdmchan, &conEvnt.redirNmb);
	set_calling_name(ftdmchan, &conEvnt);
	set_network_specific_fac(ftdmchan, &conEvnt.netFac[0]);

	/* set_facility_ie will overwrite Calling Name for NI-2 if user specifies custom Facility IE */
	set_facility_ie(ftdmchan, &conEvnt.facilityStr);
	set_prog_ind_ie(ftdmchan, &conEvnt.progInd, prog_ind);

	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces);

	if (sng_isdn_con_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, sngisdn_dchan(signal_data)->link_id, sngisdn_info->ces)) {
		ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused SETUP request\n");
	}

	return;
}
void sngisdn_delayed_connect(void* p_sngisdn_info)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;	
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;	

	ftdm_mutex_lock(ftdmchan->mutex);
	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending delayed CONNECT (suId:%d suInstId:%u spInstId:%u)\n",
								signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId);

	sngisdn_snd_connect(ftdmchan);
	ftdm_mutex_unlock(ftdmchan->mutex);
	return;
}
void clear_call_data(sngisdn_chan_data_t *sngisdn_info)
{
	uint32_t cc_id = ((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->cc_id;

	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Clearing call data (suId:%u suInstId:%u spInstId:%u)\n", cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
	ftdm_mutex_lock(g_sngisdn_data.ccs[cc_id].mutex);
	g_sngisdn_data.ccs[cc_id].active_spInstIds[sngisdn_info->spInstId]=NULL;
	g_sngisdn_data.ccs[cc_id].active_suInstIds[sngisdn_info->suInstId]=NULL;
	ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex);
	
	sngisdn_info->suInstId = 0;
	sngisdn_info->spInstId = 0;
	sngisdn_info->globalFlg = 0;
	sngisdn_info->flags = 0;
	return;
}
void sngisdn_facility_timeout(void* p_sngisdn_info)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;	

	ftdm_mutex_lock(ftdmchan->mutex);
	if (ftdmchan->state == FTDM_CHANNEL_STATE_GET_CALLERID) {
		ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Facility timeout reached proceeding with call (suId:%d suInstId:%u spInstId:%u)\n",
					  signal_data->cc_id, sngisdn_info->spInstId, sngisdn_info->suInstId);
		
		ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
	}
	
	ftdm_mutex_unlock(ftdmchan->mutex);
	return;
}
void att_courtesy_transfer_timeout(void* p_sngisdn_info)
{
	sngisdn_chan_data_t  *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;

	ftdm_mutex_lock(ftdmchan->mutex);
	if (sngisdn_info->transfer_data.type == SNGISDN_TRANSFER_NONE) {
		/* Call was already cleared */
		ftdm_mutex_unlock(ftdmchan->mutex);
		return;
	}

	ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "AT&T Courtesy Transfer timeout (%d)\n", signal_data->transfer_timeout);
	att_courtesy_transfer_complete(sngisdn_info, FTDM_TRANSFER_RESPONSE_TIMEOUT);
	ftdm_mutex_unlock(ftdmchan->mutex);
	return;
}
void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, int16_t dChan, uint8_t ces)
{
	sngisdn_chan_data_t *sngisdn_info = NULL;
	sngisdn_event_data_t *sngisdn_event = NULL;

	ISDN_FUNC_TRACE_ENTER(__FUNCTION__);

	ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Cfm on unconfigured cc\n");
	ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Cfm on unconfigured dchan\n");

	if (get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) != FTDM_SUCCESS) {
		ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId);
		ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
		return;
	}

	if (!sngisdn_info->spInstId) {
		ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex);

		sngisdn_info->spInstId = spInstId;
		g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info;
		ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex);
	}

	
	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received CONNECT/CONNECT ACK (suId:%u suInstId:%u spInstId:%u ces:%d)\n", suId, suInstId, spInstId, ces);
	
	sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event));
	ftdm_assert(sngisdn_event, "Failed to allocate memory\n");
	memset(sngisdn_event, 0, sizeof(*sngisdn_event));

	sngisdn_event->event_id = SNGISDN_EVENT_CON_CFM;
	sngisdn_event->sngisdn_info = sngisdn_info;
	sngisdn_event->suId = suId;
	sngisdn_event->suInstId = suInstId;
	sngisdn_event->spInstId = spInstId;
	sngisdn_event->dChan = dChan;
	sngisdn_event->ces = ces;
	memcpy(&sngisdn_event->event.cnStEvnt, cnStEvnt, sizeof(*cnStEvnt));
	
	ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event);
	ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
}
Beispiel #20
0
/*
 * This is a tricky function with some side effects, some explanation needed ...
 *
 * The libpri stack process HDLC frames, then finds Q921 frames and Q931 events, each time
 * it finds a new Q931 event, checks if the crv of that event matches a known call in the internal
 * list found in the PRI control block (for us, one control block per span), if it does not find
 * the call, allocates a new one and then sends the event up to the user (us, ftmod_pritap in this case)
 *
 * The user is then expected to destroy the call when done with it (on hangup), but things get tricky here
 * because in ftmod_pritap we do not destroy the call right away to be sure we only destroy it when no one
 * else needs that pointer, therefore we decide to delay the destruction of the call pointer until later
 * when a new call comes which triggers the garbage collecting code in this function
 *
 * Now, what happens if a new call arrives right away with the same crv than the last call? the pri stack
 * does *not* allocate a new call pointer because is still a known call and we must therefore re-use the
 * same call pointer
 *
 * This function accepts a pointer to a callref, even a NULL one. When callref is NULL we search for an
 * available slot so the caller of this function can use it to store a new callref pointer. In the process
 * we also scan for slots that still have a callref pointer but are no longer in use (inuse=0) and we
 * destroy that callref and clear the slot (memset). The trick is, we only do this if the callref to
 * be garbage collected is NOT the one provided by the parameter callref, of course! otherwise we may
 * be freeing a pointer to a callref for a new call that used an old (recycled) callref!
 */
static passive_call_t *tap_pri_get_pcall(pritap_t *pritap, void *callref)
{
    int i;
    int crv;

    ftdm_mutex_lock(pritap->pcalls_lock);

    for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
        /* If this slot has a call reference
         * and it is different than the *callref provided to us
         * and is no longer in use,
         * then it is time to garbage collect it ... */
        if (pritap->pcalls[i].callref  && callref != pritap->pcalls[i].callref && !pritap->pcalls[i].inuse) {
            crv = tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref);
            /* garbage collection */
            ftdm_log(FTDM_LOG_DEBUG, "Garbage collecting callref %d/%p from span %s in slot %d\n",
                     crv, pritap->pcalls[i].callref, pritap->span->name, i);
            pri_passive_destroycall(pritap->pri, pritap->pcalls[i].callref);
            memset(&pritap->pcalls[i], 0, sizeof(pritap->pcalls[0]));
        }
        if (callref == pritap->pcalls[i].callref) {
            if (callref == NULL) {
                pritap->pcalls[i].inuse = 1;
                ftdm_log(FTDM_LOG_DEBUG, "Enabling callref slot %d in span %s\n", i, pritap->span->name);
            } else if (!pritap->pcalls[i].inuse) {
                crv = tap_pri_get_crv(pritap->pri, callref);
                ftdm_log(FTDM_LOG_DEBUG, "Recyclying callref slot %d in span %s for callref %d/%p\n",
                         i, pritap->span->name, crv, callref);
                memset(&pritap->pcalls[i], 0, sizeof(pritap->pcalls[0]));
                pritap->pcalls[i].callref = callref;
                pritap->pcalls[i].inuse = 1;
            }

            ftdm_mutex_unlock(pritap->pcalls_lock);

            return &pritap->pcalls[i];
        }
    }

    ftdm_mutex_unlock(pritap->pcalls_lock);

    return NULL;
}
uint32_t get_unique_suInstId(uint8_t cc_id)
{
	uint32_t suInstId;
	ftdm_mutex_lock(g_sngisdn_data.ccs[cc_id].request_mutex);
	suInstId = g_sngisdn_data.ccs[cc_id].last_suInstId;

	while(1) {
		if (++suInstId == MAX_INSTID) {
			suInstId = 1;
		}
		if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) {
			g_sngisdn_data.ccs[cc_id].last_suInstId = suInstId;
			ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].request_mutex);
			return suInstId;
		}
	}
	/* Should never reach here */
	ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].request_mutex);
	return 0;
}
uint32_t get_unique_suInstId(int16_t cc_id)
{
	uint32_t suInstId;
	ftdm_assert_return((cc_id > 0 && cc_id <=MAX_VARIANTS), FTDM_FAIL, "Invalid cc_id\n");
	ftdm_mutex_lock(g_sngisdn_data.ccs[cc_id].mutex);
	suInstId = g_sngisdn_data.ccs[cc_id].last_suInstId;

	while(1) {
		if (++suInstId == MAX_INSTID) {
			suInstId = 1;
		}
		if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) {
			g_sngisdn_data.ccs[cc_id].last_suInstId = suInstId;
			ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex);
			return suInstId;
		}
	}
	/* Should never reach here */
	ftdm_mutex_unlock(g_sngisdn_data.ccs[cc_id].mutex);
	return 0;
}
void sngisdn_t3_timeout(void* p_sngisdn_info)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;

	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Timer T3 expired (suId:%d suInstId:%u spInstId:%u)\n",
				  signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId);
	ftdm_mutex_lock(ftdmchan->mutex);
	if (ftdm_test_flag(sngisdn_info, FLAG_ACTIVATING)){
		/* PHY layer timed-out, need to clear the call */
		ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Failed to Wake-Up line (suId:%d suInstId:%u spInstId:%u)\n",
					  signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId);

		ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NO_ROUTE_DESTINATION;
		ftdm_clear_flag(sngisdn_info, FLAG_ACTIVATING);
		ftdm_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
		ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
	}	
	ftdm_mutex_unlock(ftdmchan->mutex);
}
void sngisdn_delayed_disconnect(void* p_sngisdn_info)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;	
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;	

	ftdm_mutex_lock(ftdmchan->mutex);
	if (ftdmchan->caller_data.hangup_cause == IN_CCNORTTODEST || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
		ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending delayed DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n",
									signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId);

 		sngisdn_snd_disconnect(ftdmchan);
		if (ftdmchan->caller_data.hangup_cause == IN_CCNORTTODEST) {
			ftdm_channel_t *close_chan = ftdmchan;
			ftdm_channel_close(&close_chan);
		}
	}

	ftdm_mutex_unlock(ftdmchan->mutex);
	return;
}
void sngisdn_delayed_release(void* p_sngisdn_info)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;	
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;	

	ftdm_mutex_lock(ftdmchan->mutex);
	
	if (ftdm_test_flag(sngisdn_info, FLAG_DELAYED_REL)) {
		ftdm_clear_flag(sngisdn_info, FLAG_DELAYED_REL);
		ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending delayed RELEASE (suId:%d suInstId:%u spInstId:%u)\n",
								signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId);

		sngisdn_snd_release(ftdmchan, 1);
		clear_call_glare_data(sngisdn_info);
	} else {
		ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Call was already released (suId:%d suInstId:%u spInstId:%u)\n",
								signal_data->cc_id, sngisdn_info->glare.spInstId, sngisdn_info->glare.suInstId);
	}
	ftdm_mutex_unlock(ftdmchan->mutex);
	return;
}
void clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info)
{
	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Clearing glare data (suId:%d suInstId:%u spInstId:%u actv-suInstId:%u  actv-spInstId:%u)\n",
										sngisdn_info->glare.suId,
										sngisdn_info->glare.suInstId, sngisdn_info->glare.spInstId,
										sngisdn_info->suInstId, sngisdn_info->spInstId);

	ftdm_mutex_lock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex);	
	if (sngisdn_info->glare.spInstId != sngisdn_info->spInstId) {
		g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_spInstIds[sngisdn_info->glare.spInstId]=NULL;
	}
	g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_suInstIds[sngisdn_info->glare.suInstId]=NULL;
	ftdm_mutex_unlock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex);

	ftdm_clear_flag(sngisdn_info, FLAG_GLARE);
	memset(&sngisdn_info->glare.setup, 0, sizeof(ConEvnt));
	sngisdn_info->glare.suId = 0;
	sngisdn_info->glare.suInstId = 0;
	sngisdn_info->glare.spInstId = 0;
	sngisdn_info->glare.dChan = 0;
	sngisdn_info->glare.ces = 0;
	return;
}
void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt)
{
	sngisdn_chan_data_t  *sngisdn_info;
	sngisdn_event_data_t *sngisdn_event = NULL;

	ISDN_FUNC_TRACE_ENTER(__FUNCTION__);

	/* We sometimes receive a STA CFM after receiving a RELEASE/RELEASE COMPLETE, so we need to lock
		here in case we are calling clear_call_data at the same time this function is called */

	ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex);	
	if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) &&
		!(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) {

		ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId);
		ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex);
		return;
	}

	ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received STATUS CONFIRM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId);
	
	sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event));
	ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n");
	memset(sngisdn_event, 0, sizeof(*sngisdn_event));

	sngisdn_event->event_id = SNGISDN_EVENT_STA_CFM;
	sngisdn_event->sngisdn_info = sngisdn_info;
	sngisdn_event->suId = suId;
	sngisdn_event->suInstId = suInstId;
	sngisdn_event->spInstId = spInstId;

	memcpy(&sngisdn_event->event.staEvnt, staEvnt, sizeof(*staEvnt));

 	ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event);
	ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex);
	ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
}
Beispiel #28
0
FT_DECLARE(ftdm_status_t) ftdm_sched_cancel_timer(ftdm_sched_t *sched, ftdm_timer_id_t timerid)
{
	ftdm_status_t status = FTDM_FAIL;
	ftdm_timer_t *timer;

	ftdm_assert_return(sched != NULL, FTDM_EINVAL, "sched is null!\n");

	if (!timerid) {
		return FTDM_SUCCESS;
	}

	ftdm_mutex_lock(sched->mutex);

	/* look for the timer and destroy it */
	for (timer = sched->timers; timer; timer = timer->next) {
		if (timer->id == timerid) {
			if (timer == sched->timers) {
				/* it's the head timer, put a new head */
				sched->timers = timer->next;
			}
			if (timer->prev) {
				timer->prev->next = timer->next;
			}
			if (timer->next) {
				timer->next->prev = timer->prev;
			}
			ftdm_safe_free(timer);
			status = FTDM_SUCCESS;
			break;
		}
	}

	ftdm_mutex_unlock(sched->mutex);

	return status;
}
Beispiel #29
0
static ftdm_status_t ftdm_core_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq)
{
	ftdm_status_t status;
	int ok = 1;
	int waitms = DEFAULT_WAIT_TIME;	

	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n",
				ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
		return FTDM_FAIL;
	}

	if (ftdmchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, 
		"Ignored state change request from %s to %s, the previous state change has not been processed yet (status = %s)\n",
		ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state),
		ftdm_state_status2str(ftdmchan->state_status));
		return FTDM_FAIL;
	}

	if (ftdmchan->state == state) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
		return FTDM_FAIL;
	}

	if (!ftdmchan->state_completed_interrupt) {
		status = ftdm_interrupt_create(&ftdmchan->state_completed_interrupt, FTDM_INVALID_SOCKET);
		if (status != FTDM_SUCCESS) {
			ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_CRIT, 
					"Failed to create state change interrupt when moving from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
			return status;
		}
	}


	if (ftdmchan->span->state_map) {
		ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
		goto end;
	}

	/* basic core state validation (by-passed if the signaling module provides a state_map) */
	switch(ftdmchan->state) {
	case FTDM_CHANNEL_STATE_HANGUP:
	case FTDM_CHANNEL_STATE_TERMINATING:
		{
			ok = 0;
			switch(state) {
			case FTDM_CHANNEL_STATE_DOWN:
			case FTDM_CHANNEL_STATE_BUSY:
			case FTDM_CHANNEL_STATE_RESTART:
				ok = 1;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_UP:
		{
			ok = 1;
			switch(state) {
			case FTDM_CHANNEL_STATE_PROGRESS:
			case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
			case FTDM_CHANNEL_STATE_RING:
				ok = 0;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_DOWN:
		{
			ok = 0;
			
			switch(state) {
			case FTDM_CHANNEL_STATE_DIALTONE:
			case FTDM_CHANNEL_STATE_COLLECT:
			case FTDM_CHANNEL_STATE_DIALING:
			case FTDM_CHANNEL_STATE_RING:
			case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
			case FTDM_CHANNEL_STATE_PROGRESS:				
			case FTDM_CHANNEL_STATE_IDLE:				
			case FTDM_CHANNEL_STATE_GET_CALLERID:
			case FTDM_CHANNEL_STATE_GENRING:
				ok = 1;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_BUSY:
		{
			switch(state) {
			case FTDM_CHANNEL_STATE_UP:
				ok = 0;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_RING:
		{
			switch(state) {
			case FTDM_CHANNEL_STATE_UP:
				ok = 1;
				break;
			default:
				break;
			}
		}
		break;
	default:
		break;
	}

end:

	if (!ok) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
		goto done;
	}

	ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
	ftdmchan->last_state = ftdmchan->state; 
	ftdmchan->state = state;
	ftdmchan->state_status = FTDM_STATE_STATUS_NEW;
	ftdmchan->history[ftdmchan->hindex].file = file;
	ftdmchan->history[ftdmchan->hindex].func = func;
	ftdmchan->history[ftdmchan->hindex].line = line;
	ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state;
	ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state;
	ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms();
	ftdmchan->history[ftdmchan->hindex].end_time = 0;
	ftdmchan->hindex++;
	if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) {
		ftdmchan->hindex = 0;
	}
	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);

	ftdm_mutex_lock(ftdmchan->span->mutex);
	ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
	if (ftdmchan->span->pendingchans) {
		ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
	}
	ftdm_mutex_unlock(ftdmchan->span->mutex);

	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) {
		/* the channel should not block waiting for state processing */
		goto done;
	}

	if (!waitrq) {
		/* no waiting was requested */
		goto done;
	}

	/* let's wait for the state change to be completed by the signaling stack */
	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);

	ftdm_mutex_unlock(ftdmchan->mutex);

	status = ftdm_interrupt_wait(ftdmchan->state_completed_interrupt, waitms);

	ftdm_mutex_lock(ftdmchan->mutex);

	if (status != FTDM_SUCCESS) {
		ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
		ftdm_log_chan_ex(ftdmchan, file, func, line, 
				FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not completed after aprox %dms\n",
				ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
		ok = 0;
		goto done;
	}
done:
	return ok ? FTDM_SUCCESS : FTDM_FAIL;
}
Beispiel #30
0
int main(int argc, char *argv[])
{
	ftdm_span_t *span;
	ftdm_conf_parameter_t parameters[20];
	
	ftdm_mutex_create(&the_mutex);

	if (argc < 2) {
		printf("umm no\n");
		exit(1);
	}

	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);

	if (ftdm_global_init() != FTDM_SUCCESS) {
		fprintf(stderr, "Error loading FreeTDM\n");
		exit(1);
	}

	ftdm_global_configuration();

	printf("FreeTDM loaded\n");

	if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
		fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
		goto done;
	}
	
	/* testing non-blocking operation */
	//ftdm_span_set_blocking_mode(span, FTDM_FALSE);

	parameters[0].var = "variant";
	parameters[0].val = "br";

	parameters[1].var = "max_ani";
	parameters[1].val = "4";

	parameters[2].var = "max_dnis";
	parameters[2].val = "4";

	parameters[3].var = "logging";
	parameters[3].val = "all";

	parameters[4].var = NULL;
	parameters[4].val = NULL;

	if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, parameters) == FTDM_SUCCESS) {
		ftdm_span_start(span);
	} else {
		fprintf(stderr, "Error starting R2 span\n");
		goto done;
	}

	running = 1;
	signal(SIGINT, stop_test);
	while(running) {
		ftdm_sleep(20);
		if (fchan && indication != FTDM_CHANNEL_INDICATE_NONE) {
			ftdm_channel_t *lchan = NULL;
			ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
			ftdm_time_t start, stop, diff;

			ftdm_mutex_lock(the_mutex);
			ind = indication;
			indication = FTDM_CHANNEL_INDICATE_NONE;
			lchan = fchan;
			ftdm_mutex_unlock(the_mutex);

			start = ftdm_current_time_in_ms();
			ftdm_channel_call_indicate(lchan, ind);
			stop = ftdm_current_time_in_ms();
			diff = stop - start;
			ftdm_log(FTDM_LOG_DEBUG, "Setting indication %s took %"FTDM_TIME_FMT" ms\n",
					ftdm_channel_indication2str(ind), diff);
		}
	}

done:

	ftdm_global_destroy();

	return 0;
}