Beispiel #1
0
static ftdm_status_t ftdm_pritap_start(ftdm_span_t *span)
{
    ftdm_status_t ret;
    pritap_t *pritap = span->signal_data;
    pritap_t *p_pritap = pritap->peerspan->signal_data;

    if (ftdm_test_flag(pritap, PRITAP_RUNNING)) {
        return FTDM_FAIL;
    }

    ftdm_mutex_create(&pritap->pcalls_lock);

    ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
    ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);

    ftdm_set_flag(pritap, PRITAP_RUNNING);
    if (p_pritap && ftdm_test_flag(p_pritap, PRITAP_RUNNING)) {
        /* our peer already started, we're the master */
        ftdm_set_flag(pritap, PRITAP_MASTER);
    }
    ret = ftdm_thread_create_detached(ftdm_pritap_run, span);

    if (ret != FTDM_SUCCESS) {
        return ret;
    }

    return ret;
}
void sngisdn_rcv_q921_ind(BdMngmt *status)
{	
	ftdm_span_t *ftdmspan;

	sngisdn_span_data_t	*signal_data = g_sngisdn_data.dchans[status->t.usta.lnkNmb].spans[1];
	
	if (!signal_data) {
		ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
		return;
	}
	ftdmspan = signal_data->ftdm_span;

	if (!ftdmspan) {
		ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
		return;
	}

	switch (status->t.usta.alarm.category) {
		case (LCM_CATEGORY_PROTOCOL):
			ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
						ftdmspan->name,
						DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
						DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
						DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);

			if (FTDM_SPAN_IS_BRI(ftdmspan) && (status->t.usta.alarm.event == PROT_ST_DN)) {
				/* Q.921 link is down - This is a line where the Q.921 stops transmitting
					after the line goes idle.

					Do not drop current calls, but set sigstatus do down so that we
					can try to re-initialize link before trying new outbound calls */

				sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN);
				sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING);
			}
			break;
		default:
			ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
						ftdmspan->name,
						DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
						DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
						DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
			
			switch (status->t.usta.alarm.event) {
				case ENTR_CONG: /* Entering Congestion */
					ftdm_log(FTDM_LOG_WARNING, "s%d: Entering Congestion\n", ftdmspan->span_id);
					ftdm_set_flag(ftdmspan, FTDM_SPAN_SUSPENDED);
					break;
				case EXIT_CONG: /* Exiting Congestion */
					ftdm_log(FTDM_LOG_WARNING, "s%d: Exiting Congestion\n", ftdmspan->span_id);
					ftdm_clear_flag(ftdmspan, FTDM_SPAN_SUSPENDED);
					break;
			}
			break;
	}
    return;
}
void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
{
	ISDN_FUNC_TRACE_ENTER(__FUNCTION__);

	int16_t suId = sngisdn_event->suId;
	uint32_t suInstId = sngisdn_event->suInstId;
	uint32_t spInstId = sngisdn_event->spInstId;
	sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
	ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
	
	DiscEvnt *discEvnt = &sngisdn_event->event.discEvnt;

	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId);

	ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n");
	switch (ftdmchan->state) {
		case FTDM_CHANNEL_STATE_RING:
		case FTDM_CHANNEL_STATE_DIALING:
		case FTDM_CHANNEL_STATE_PROGRESS:
		case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
		case FTDM_CHANNEL_STATE_UP:
			if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) {
				ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val;
			} else {
				ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "DISCONNECT did not have a cause code\n");
				ftdmchan->caller_data.hangup_cause = 0;
			}
			sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_REL);
			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
			break;
		case FTDM_CHANNEL_STATE_COLLECT:
		case FTDM_CHANNEL_STATE_GET_CALLERID:
			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
			break;
		case FTDM_CHANNEL_STATE_DOWN:
			/* somehow we are in down, nothing we can do locally */
			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT but we are in DOWN state\n");
			break;
		case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
			/* This is a race condition. We just sent a DISCONNECT, on this channel */
			/* Do nothing */
			break;
		default:
			ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT in an invalid state (%s)\n",
						  ftdm_channel_state2str(ftdmchan->state));
			/* start reset procedure */

			/* Start the release procedure */
			ftdm_set_flag(sngisdn_info, FLAG_REMOTE_REL);
			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
			break;
	}

	ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
	return;
}
void sngisdn_rcv_q921_ind(BdMngmt *status)
{	
	ftdm_span_t *ftdmspan;

	sngisdn_span_data_t	*signal_data = g_sngisdn_data.dchans[status->t.usta.lnkNmb].spans[1];
	
	if (!signal_data) {
		ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
		return;
	}
	ftdmspan = signal_data->ftdm_span;

	if (!ftdmspan) {
		ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb);
		return;
	}

	switch (status->t.usta.alarm.category) {
		case (LCM_CATEGORY_PROTOCOL):
			ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
						ftdmspan->name,
						DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
						DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
						DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
			break;
		default:
			ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n",
						ftdmspan->name,
						DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
						DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
						DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
			
			switch (status->t.usta.alarm.event) {
				case ENTR_CONG: /* Entering Congestion */
					ftdm_log(FTDM_LOG_WARNING, "s%d: Entering Congestion\n", ftdmspan->span_id);
					ftdm_set_flag(ftdmspan, FTDM_SPAN_SUSPENDED);
					break;
				case EXIT_CONG: /* Exiting Congestion */
					ftdm_log(FTDM_LOG_WARNING, "s%d: Exiting Congestion\n", ftdmspan->span_id);
					ftdm_clear_flag(ftdmspan, FTDM_SPAN_SUSPENDED);
					break;
			}
			break;
	}
    return;
}
Beispiel #5
0
static ftdm_status_t ftdm_pritap_stop(ftdm_span_t *span)
{
    pritap_t *pritap = span->signal_data;

    if (!ftdm_test_flag(pritap, PRITAP_RUNNING)) {
        return FTDM_FAIL;
    }

    ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);

    while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
        ftdm_sleep(100);
    }

    ftdm_mutex_destroy(&pritap->pcalls_lock);
    return FTDM_SUCCESS;
}
ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId)
{
	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
	if (!ftdmchan) {
		return FTDM_SUCCESS;
	}

	ftdm_set_flag(sngisdn_info, FLAG_SENT_CHAN_ID);
	
	chanId->eh.pres = PRSNT_NODEF;
	chanId->prefExc.pres = PRSNT_NODEF;
	chanId->prefExc.val = IN_PE_EXCLSVE;
	chanId->dChanInd.pres = PRSNT_NODEF;
	chanId->dChanInd.val = IN_DSI_NOTDCHAN;
	chanId->intIdentPres.pres = PRSNT_NODEF;
	chanId->intIdentPres.val = IN_IIP_IMPLICIT;

	if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
		   ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {

		/* BRI only params */
		chanId->intType.pres = PRSNT_NODEF;
		chanId->intType.val = IN_IT_BASIC;
		chanId->infoChanSel.pres = PRSNT_NODEF;
		chanId->infoChanSel.val = ftdmchan->physical_chan_id;
	} else {
		chanId->intType.pres = PRSNT_NODEF;
		chanId->intType.val = IN_IT_OTHER;
		chanId->infoChanSel.pres = PRSNT_NODEF;
		chanId->infoChanSel.val = IN_ICS_B1CHAN;
		chanId->chanMapType.pres = PRSNT_NODEF;
		chanId->chanMapType.val = IN_CMT_BCHAN;
		chanId->nmbMap.pres = PRSNT_NODEF;
		chanId->nmbMap.val = IN_NM_CHNNMB;
		chanId->codeStand1.pres = PRSNT_NODEF;
		chanId->codeStand1.val = IN_CSTD_CCITT;
		chanId->chanNmbSlotMap.pres = PRSNT_NODEF;
		chanId->chanNmbSlotMap.len = 1;
		chanId->chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
	}
	return FTDM_SUCCESS;
}
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);
}
Beispiel #8
0
int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug)
{
	int ret = -1;

	memset(spri, 0, sizeof(struct lpwrap_pri));
	
	spri->dchan = dchan;
	spri->span = span;

	if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){
		unsigned char buf[4] = { 0 };
		size_t buflen = sizeof(buf), len = 0;
		pri_set_debug(spri->pri, debug);
		ret = 0;
		ftdm_set_flag(spri, LPWRAP_PRI_READY);
		ftdm_channel_write(spri->dchan, buf, buflen, &len);
	} else {
		fprintf(stderr, "Unable to create PRI\n");
	}

	return ret;
}
Beispiel #9
0
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
{
	wat_span_config_t span_config;
	ftdm_gsm_span_data_t *gsm_data = NULL;
	ftdm_iterator_t *chaniter = NULL;
	ftdm_iterator_t *citer = NULL;
	ftdm_channel_t *ftdmchan = NULL;
	ftdm_channel_t *dchan = NULL;
	ftdm_channel_t *bchan = NULL;

	unsigned paramindex = 0;
	const char *var = NULL;
	const char *val = NULL;
	
	/* libwat is smart enough to set good default values for the timers if they are set to 0 */
	memset(&span_config, 0, sizeof(span_config));
	
	/* set some span defaults */
	span_config.moduletype = WAT_MODULE_TELIT;

	if (FTDM_SUCCESS != init_wat_lib()) {
		return FTDM_FAIL;
	}

	if (!sig_cb) {
		ftdm_log(FTDM_LOG_ERROR, "No signaling callback provided\n");
		return FTDM_FAIL;
	}

	if (span->signal_type) {
		ftdm_log(FTDM_LOG_ERROR, "Span %s is already configured for another signaling\n", span->name);
		return FTDM_FAIL;
	}

	/* verify the span has one d-channel */
	chaniter = ftdm_span_get_chan_iterator(span, NULL);
	
	if (!chaniter) {
		ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
		return FTDM_FAIL;
	}

	citer = ftdm_span_get_chan_iterator(span, chaniter);
	for ( ; citer; citer = ftdm_iterator_next(citer)) {
		ftdmchan = ftdm_iterator_current(citer);
		
		if ((NULL == dchan) && FTDM_IS_DCHAN(ftdmchan)) {
			dchan = ftdmchan;
		}
		if ((NULL == bchan) && FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
			bchan = ftdmchan;
		}

	}
	ftdm_iterator_free(chaniter);

	if (!dchan) {
		ftdm_log(FTDM_LOG_CRIT, "Could not find a d-channel for GSM span %s!\n", span->name);
		return FTDM_FAIL;
	}
	if (!bchan) {
		ftdm_log(FTDM_LOG_CRIT, "Could not find a b-channel for GSM span %s!\n", span->name);
		return FTDM_FAIL;
	}





	gsm_data = ftdm_calloc(1, sizeof(*gsm_data));
	if (!gsm_data) {
		return FTDM_FAIL;
	}
	gsm_data->dchan = dchan;
	gsm_data->bchan = bchan;

	//sprintf(gsm_data->dchan->chan_name, "%s\t\n", "GSM dchan");
	//sprintf(gsm_data->bchan->chan_name, "%s\r\n", "GSM bchan");

	for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
		var = ftdm_parameters[paramindex].var;
		val = ftdm_parameters[paramindex].val;
		if (!ftdm_strlen_zero_buf(val)) {
			ftdm_log(FTDM_LOG_WARNING, "Ignoring empty GSM parameter %s for span %s\n", var, span->name);
			continue;
		}
		ftdm_log(FTDM_LOG_DEBUG, "Reading GSM parameter %s=%s for span %s\n", var, val, span->name);
		if (!strcasecmp(var, "moduletype")) {
			span_config.moduletype = wat_str2wat_moduletype(val);
			if (span_config.moduletype == WAT_MODULE_INVALID) {
				ftdm_log(FTDM_LOG_DEBUG, "Unknown GSM module type %s for span %s\n", val, span->name);
				continue;
			}
			ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %s with moduletype %s\n", span->name, val);
		} else {
			ftdm_log(FTDM_LOG_ERROR, "Ignoring unknown GSM parameter '%s'", var);
		}
	}

	/* Bind function pointers for control operations */
	span->start = ftdm_gsm_start;
	span->stop = ftdm_gsm_stop;
	span->sig_read = NULL;
	span->sig_write = NULL;

	span->signal_cb = sig_cb;
	span->signal_type = FTDM_SIGTYPE_GSM;
	span->signal_data = gsm_data; /* Gideon, plz fill me with gsm span specific data (you allocate and free) */
	span->outgoing_call = gsm_outgoing_call;
	span->get_span_sig_status = ftdm_gsm_get_span_sig_status;
	span->set_span_sig_status = ftdm_gsm_set_span_sig_status;
	span->get_channel_sig_status = ftdm_gsm_get_channel_sig_status;
	span->set_channel_sig_status = ftdm_gsm_set_channel_sig_status;

	//printf("\r\nspan->state_map = &gsm_state_map;\r\n");
	span->state_map = &gsm_state_map;
	span->state_processor = ftdm_gsm_state_advance;

	/* use signals queue */
	ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
	ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);

	/* we can skip states (going straight from RING to UP) */
	ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);

	gsm_data->span = span;

#if 0
	/* setup the scheduler (create if needed) */
	snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
	ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
	spanpvt->sched = r2data->sched;
#endif

	
fprintf(stdout, "Configuring wat span %d %s \r\n", span->span_id, span->name);
	if (wat_span_config(span->span_id, &span_config)) {
		ftdm_log(FTDM_LOG_ERROR, "Failed to configure span %s for GSM signaling!!\n", span->name);
		return FTDM_FAIL;
	}

	{
		int codec		= FTDM_CODEC_SLIN;
		int interval	= 20;
		
		ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_NATIVE_CODEC,  &codec);
		ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_CODEC,  &codec);
		ftdm_channel_command(gsm_data->bchan, FTDM_COMMAND_SET_INTERVAL,  &interval);
	}

	return FTDM_SUCCESS;

}
static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
{
	unsigned i;
	ftdm_iterator_t *chaniter = NULL;
	ftdm_iterator_t *curr = NULL;	
	//sngisdn_dchan_data_t *dchan_data;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
	
	switch(span->trunk_type) {
		case FTDM_TRUNK_T1:
			if (!strcasecmp(switch_name, "ni2") ||
				!strcasecmp(switch_name, "national")) {
				signal_data->switchtype = SNGISDN_SWITCH_NI2;
			} else if (!strcasecmp(switch_name, "5ess")) {
				signal_data->switchtype = SNGISDN_SWITCH_5ESS;
			} else if (!strcasecmp(switch_name, "4ess")) {
				signal_data->switchtype = SNGISDN_SWITCH_4ESS;
			} else if (!strcasecmp(switch_name, "dms100")) {
				signal_data->switchtype = SNGISDN_SWITCH_DMS100;
			} else if (!strcasecmp(switch_name, "qsig")) {
				signal_data->switchtype = SNGISDN_SWITCH_QSIG;
			} else {
				ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
				return FTDM_FAIL;
			}
			break;
		case FTDM_TRUNK_E1:
			if (!strcasecmp(switch_name, "euroisdn") ||
				!strcasecmp(switch_name, "etsi")) {
				signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
			} else if (!strcasecmp(switch_name, "qsig")) {
				signal_data->switchtype = SNGISDN_SWITCH_QSIG;
			} else {
				ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
				return FTDM_FAIL;
			}
			break;
		case FTDM_TRUNK_BRI:
		case FTDM_TRUNK_BRI_PTMP:
			if (!strcasecmp(switch_name, "euroisdn") ||
				!strcasecmp(switch_name, "etsi")) {
				signal_data->switchtype = SNGISDN_SWITCH_EUROISDN;
			} else if (!strcasecmp(switch_name, "insnet") ||
						!strcasecmp(switch_name, "ntt")) {
				signal_data->switchtype = SNGISDN_SWITCH_INSNET;
			} else {
				ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported switchtype %s for trunktype:%s\n", span->name, switch_name, ftdm_trunk_type2str(span->trunk_type));
				return FTDM_FAIL;
			}
			ftdm_set_flag(span, FTDM_SPAN_USE_AV_RATE);
			ftdm_set_flag(span, FTDM_SPAN_PWR_SAVING);
			 /* can be > 1 for some BRI variants */
			break;
		default:
			ftdm_log(FTDM_LOG_ERROR, "%s:Unsupported trunktype:%s\n", span->name, ftdm_trunk_type2str(span->trunk_type));
			return FTDM_FAIL;
	}

	/* see if we have profile with this switch_type already */
	for (i = 1; i <= g_sngisdn_data.num_cc; i++) {
		if (g_sngisdn_data.ccs[i].switchtype == signal_data->switchtype &&
			g_sngisdn_data.ccs[i].trunktype == span->trunk_type) {
			break;
		}
	}

	/* need to create a new switch_type */
	if (i > g_sngisdn_data.num_cc) {
		g_sngisdn_data.num_cc++;
		g_sngisdn_data.ccs[i].switchtype = signal_data->switchtype;
		g_sngisdn_data.ccs[i].trunktype = span->trunk_type;
		ftdm_log(FTDM_LOG_DEBUG, "%s: New switchtype:%s  cc_id:%u\n", span->name, switch_name, i);
	}

	/* add this span to its ent_cc */
	signal_data->cc_id = i;

	g_sngisdn_data.spans[signal_data->link_id] = signal_data;
	
	ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d link_id:%d\n", span->name, signal_data->cc_id, signal_data->link_id);
	
	chaniter = ftdm_span_get_chan_iterator(span, NULL);
	for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
		int32_t chan_id;
		ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
		if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
			/* set the d-channel */
			signal_data->dchan = ftdmchan;
		} else {
			/* Add the channels to the span */
			chan_id = ftdmchan->physical_chan_id;
			signal_data->channels[chan_id] = (sngisdn_chan_data_t*)ftdmchan->call_data;
			signal_data->num_chans++;
		}
	}
	ftdm_iterator_free(chaniter);
	return FTDM_SUCCESS;
}
Beispiel #11
0
FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *func, int line, ftdm_channel_t *fchan)
{
	uint8_t hindex = 0;
	ftdm_time_t diff = 0;
	ftdm_channel_state_t state = fchan->state;

	if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) {
		ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, 
				"State change flag set but state is not completed\n");
		return FTDM_SUCCESS;
	}

	ftdm_usrmsg_free(&fchan->usrmsg);
	
	ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);

	if (state == FTDM_CHANNEL_STATE_PROGRESS) {
		ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
	} else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
		ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);	
		ftdm_test_and_set_media(fchan);
	} else if (state == FTDM_CHANNEL_STATE_UP) {
		ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
		ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);	
		ftdm_test_and_set_media(fchan);
	} else if (state == FTDM_CHANNEL_STATE_DIALING) {
		ftdm_sigmsg_t msg;
		memset(&msg, 0, sizeof(msg));
		msg.channel = fchan;
		msg.event_id = FTDM_SIGEVENT_DIALING;
		ftdm_span_send_signal(fchan->span, &msg);
	} else if (state == FTDM_CHANNEL_STATE_HANGUP) {
		ftdm_set_echocancel_call_end(fchan);
	}

	/* MAINTENANCE WARNING
	 * we're assuming an indication performed 
	 * via state change will involve a single state change */
	ftdm_ack_indication(fchan, fchan->indication, FTDM_SUCCESS);

	hindex = (fchan->hindex == 0) ? (ftdm_array_len(fchan->history) - 1) : (fchan->hindex - 1);
	
	ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n");

	fchan->history[hindex].end_time = ftdm_current_time_in_ms();

	fchan->state_status = FTDM_STATE_STATUS_COMPLETED;

	diff = fchan->history[hindex].end_time - fchan->history[hindex].time;

	ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Completed state change from %s to %s in %llums\n", 
			ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff);
	

	if (ftdm_test_flag(fchan, FTDM_CHANNEL_BLOCKING)) {
		ftdm_clear_flag(fchan, FTDM_CHANNEL_BLOCKING);
		ftdm_interrupt_signal(fchan->state_completed_interrupt);
	}

	return FTDM_SUCCESS;
}
Beispiel #12
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;
}
static ftdm_status_t att_courtesy_vru(ftdm_channel_t *ftdmchan, sngisdn_transfer_type_t type, char* args)
{
	char dtmf_digits[64];
	ftdm_status_t status = FTDM_FAIL;
	sngisdn_chan_data_t  *sngisdn_info = ftdmchan->call_data;
	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
	char *p = args;
	uint8_t forced_answer = 0;

	switch (signal_data->switchtype) {
		case SNGISDN_SWITCH_5ESS:
		case SNGISDN_SWITCH_4ESS:
			break;
		default:
			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "AT&T Courtesy Transfer not supported for switchtype\n");
			return FTDM_FAIL;
	}

	while (!ftdm_strlen_zero(p)) {
		if (!isdigit(*p) && *p != 'w' && *p != 'W') {
			ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot transfer to non-numeric number:%s\n", args);
			return FTDM_FAIL;
		}
		p++;
	}

	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Performing AT&T Courtesy Transfer-VRU%s to %s\n", (type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) ?"--data" : "", args);
	sprintf(dtmf_digits, "*8w%s", args);
	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending digits %s\n", dtmf_digits);

	switch (ftdmchan->last_state) {
		case FTDM_CHANNEL_STATE_PROCEED:
		case FTDM_CHANNEL_STATE_PROGRESS:
		case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
			/* Call has to be in answered state - so send a CONNECT message if we did not answer this call yet */
			forced_answer++;
			sngisdn_snd_connect(ftdmchan);
			/* fall-through */
		case FTDM_CHANNEL_STATE_UP:
			memset(&sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits, 0, sizeof(sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits));
			sngisdn_info->transfer_data.type = type;

			/* We will be polling the channel for IO so that we can receive the DTMF events,
			 * Disable user RX otherwise it is a race between who calls channel_read */
			ftdm_set_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);

			ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, NULL);
			ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, dtmf_digits);

			if (type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) {
				/* We need to save transfer data, so we can send it in the disconnect msg */
				const char *val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "transfer_data");
				if (ftdm_strlen_zero(val)) {
					ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot perform data transfer because transfer_data variable is not set\n");
					goto done;
				}
				if (strlen(val) > COURTESY_TRANSFER_MAX_DATA_SIZE) {
					ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Data exceeds max size (len:%"FTDM_SIZE_FMT" max:%d), cannot perform transfer\n", strlen(val), COURTESY_TRANSFER_MAX_DATA_SIZE);
					goto done;
				}
				memcpy(sngisdn_info->transfer_data.tdata.att_courtesy_vru.data, val, strlen(val));
			}

			ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
			if (forced_answer) {
				/* Notify the user that we answered the call */
				sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_UP);
			}
			if (signal_data->transfer_timeout) {
				ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "courtesy_transfer_timeout", signal_data->transfer_timeout, att_courtesy_transfer_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_CHAN_TIMER_ATT_TRANSFER]);
			}

			status = FTDM_SUCCESS;
			break;
		default:
			ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer in state %s\n", ftdm_channel_state2str(ftdmchan->state));
			break;

	}
done:
	return status;
}
Beispiel #14
0
static void *ftdm_pritap_run(ftdm_thread_t *me, void *obj)
{
    ftdm_span_t *span = (ftdm_span_t *) obj;
    ftdm_span_t *peer = NULL;
    pritap_t *pritap = span->signal_data;
    pritap_t *p_pritap = NULL;
    pri_event *event = NULL;
    struct pollfd dpoll[2];
    int rc = 0;

    ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread started on span %s\n", span->name);

    pritap->span = span;

    ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);

    if (ftdm_channel_open(span->span_id, pritap->dchan->chan_id, &pritap->dchan) != FTDM_SUCCESS) {
        ftdm_log(FTDM_LOG_ERROR, "Failed to open D-channel for span %s\n", span->name);
        goto done;
    }

    if ((pritap->pri = pri_new_cb(pritap->dchan->sockfd, PRI_NETWORK, PRI_SWITCH_NI2, pri_io_read, pri_io_write, pritap))) {
        pri_set_debug(pritap->pri, pritap->debug);
    } else {
        ftdm_log(FTDM_LOG_CRIT, "Failed to create tapping PRI\n");
        goto done;
    }

    /* The last span starting runs the show ...
     * This simplifies locking and avoid races by having multiple threads for a single tapped link
     * Since both threads really handle a single tapped link there is no benefit on multi-threading, just complications ... */
    peer = pritap->peerspan;
    p_pritap = peer->signal_data;
    if (!ftdm_test_flag(pritap, PRITAP_MASTER)) {
        ftdm_log(FTDM_LOG_DEBUG, "Running dummy thread on span %s\n", span->name);
        while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
            poll(NULL, 0, 100);
        }
    } else {
        memset(&dpoll, 0, sizeof(dpoll));
        dpoll[0].fd = pritap->dchan->sockfd;
        dpoll[1].fd = p_pritap->dchan->sockfd;

        ftdm_log(FTDM_LOG_DEBUG, "Master tapping thread on span %s (fd1=%d, fd2=%d)\n", span->name,
                 pritap->dchan->sockfd, p_pritap->dchan->sockfd);

        while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {

            pritap_check_state(span);
            pritap_check_state(peer);

            dpoll[0].revents = 0;
            dpoll[0].events = POLLIN;

            dpoll[1].revents = 0;
            dpoll[1].events = POLLIN;

            rc = poll(&dpoll[0], 2, 10);

            if (rc < 0) {
                if (errno == EINTR) {
                    ftdm_log(FTDM_LOG_DEBUG, "D-channel waiting interrupted, continuing ...\n");
                    continue;
                }
                ftdm_log(FTDM_LOG_ERROR, "poll failed: %s\n", strerror(errno));
                continue;
            }

            pri_schedule_run(pritap->pri);
            pri_schedule_run(p_pritap->pri);

            pritap_check_state(span);
            pritap_check_state(peer);

            if (rc) {
                if (dpoll[0].revents & POLLIN) {
                    event = pri_read_event(pritap->pri);
                    if (event) {
                        handle_pri_passive_event(pritap, event);
                        pritap_check_state(span);
                    }
                }

                if (dpoll[1].revents & POLLIN) {
                    event = pri_read_event(p_pritap->pri);
                    if (event) {
                        handle_pri_passive_event(p_pritap, event);
                        pritap_check_state(peer);
                    }
                }
            }

        }
    }


done:
    ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread ended on span %s\n", span->name);

    ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
    ftdm_clear_flag(pritap, PRITAP_RUNNING);
    ftdm_clear_flag(pritap, PRITAP_MASTER);

    return NULL;
}