예제 #1
0
int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path)
{
	FILE *f;
	const char *path = NULL;
	char path_buf[1024];

	if (file_path[0] == '/') {
		path = file_path;
	} else {
		snprintf(path_buf, sizeof(path_buf), "%s%s%s", g_ftdm_config_dir, FTDM_PATH_SEPARATOR, file_path);
		path = path_buf;
	}

	if (!path) {
		return 0;
	}

	memset(cfg, 0, sizeof(*cfg));
	cfg->lockto = -1;
	ftdm_log(FTDM_LOG_DEBUG, "Configuration file is %s\n", path);
	f = fopen(path, "r");

	if (!f) {
		if (file_path[0] != '/') {
			int last = -1;
			char *var, *val;

			snprintf(path_buf, sizeof(path_buf), "%s%sfreetdm.conf", g_ftdm_config_dir, FTDM_PATH_SEPARATOR);
			path = path_buf;

			if ((f = fopen(path, "r")) == 0) {
				return 0;
			}

			cfg->file = f;
			ftdm_set_string(cfg->path, path);

			while (ftdm_config_next_pair(cfg, &var, &val)) {
				if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) {
					cfg->lockto = cfg->sectno;
					return 1;
				}
			}

			ftdm_config_close_file(cfg);
			memset(cfg, 0, sizeof(*cfg));
			return 0;
		}

		return 0;
	} else {
		cfg->file = f;
		ftdm_set_string(cfg->path, path);
		return 1;
	}
}
예제 #2
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;
}
예제 #3
0
FT_DECLARE(ftdm_status_t) ftdm_sched_create(ftdm_sched_t **sched, const char *name)
{
	ftdm_sched_t *newsched = NULL;

	ftdm_assert_return(sched != NULL, FTDM_EINVAL, "invalid pointer\n");
	ftdm_assert_return(name != NULL, FTDM_EINVAL, "invalid sched name\n");

	*sched = NULL;

	newsched = ftdm_calloc(1, sizeof(*newsched));
	if (!newsched) {
		return FTDM_MEMERR;
	}

	if (ftdm_mutex_create(&newsched->mutex) != FTDM_SUCCESS) {
		goto failed;
	}

	ftdm_set_string(newsched->name, name);
	newsched->currid = 1;

	*sched = newsched;
	ftdm_log(FTDM_LOG_DEBUG, "Created schedule %s\n", name);
	return FTDM_SUCCESS;

failed:
	ftdm_log(FTDM_LOG_CRIT, "Failed to create schedule\n");

	if (newsched) {
		if (newsched->mutex) {
			ftdm_mutex_destroy(&newsched->mutex);
		}
		ftdm_safe_free(newsched);
	}
	return FTDM_FAIL;
}
예제 #4
0
static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan)
{

	ftdm_log_chan(ftdmchan, STATE_ADVANCE_LOG_LEVEL , "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
	
	ftdm_channel_complete_state(ftdmchan);

		switch (ftdmchan->state) {

		/* starting an incoming call */
		case FTDM_CHANNEL_STATE_COLLECT: 
			{
				
				
			}
			break;

			/* starting an outgoing call */
		case FTDM_CHANNEL_STATE_DIALING:
			{
				uint32_t interval = 0;
				
				ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting outgoing call with interval %d\n", interval);

				{

					ftdm_gsm_span_data_t *gsm_data;
					gsm_data = ftdmchan->span->signal_data;
					gsm_data->call_id = g_outbound_call_id++;				
					wat_con_event_t con_event;
					memset(&con_event, 0, sizeof(con_event));
					ftdm_set_string(con_event.called_num.digits, ftdmchan->caller_data.dnis.digits);
					ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s\n", con_event.called_num.digits);
					wat_con_req(ftdmchan->span->span_id, gsm_data->call_id , &con_event);
 
					SEND_STATE_SIGNAL(FTDM_SIGEVENT_DIALING);
					
					
				}

				
			}
			break;

			/* incoming call was offered */
		case FTDM_CHANNEL_STATE_RING:

			/* notify the user about the new call */

			ftdm_log(FTDM_LOG_INFO, "Answering Incomming Call\r\n");
			SEND_STATE_SIGNAL(FTDM_SIGEVENT_START);
			
			break;

			/* the call is making progress */
		case FTDM_CHANNEL_STATE_PROGRESS:
		case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
			{
				SEND_STATE_SIGNAL(FTDM_SIGEVENT_PROGRESS_MEDIA);
				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
			}
			break;

			/* the call was answered */
		case FTDM_CHANNEL_STATE_UP:
			{
				if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
				
					SEND_STATE_SIGNAL(FTDM_SIGEVENT_UP);
				}
				else {
						ftdm_gsm_span_data_t *gsm_data;
						gsm_data = ftdmchan->span->signal_data;
						wat_con_cfm(ftdmchan->span->span_id, gsm_data->call_id); 
				}
				
				
			}
			break;

			/* just got hangup */
		case FTDM_CHANNEL_STATE_HANGUP:
			{
				ftdm_gsm_span_data_t *gsm_data;
				gsm_data = ftdmchan->span->signal_data;
				wat_rel_req(ftdmchan->span->span_id, gsm_data->call_id);
				gsm_data->call_id = 0;
				SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
			}
			break;

		case FTDM_CHANNEL_STATE_TERMINATING:
			{
				SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
			}
			break;

			/* finished call for good */
		case FTDM_CHANNEL_STATE_DOWN: 
			{
				ftdm_channel_t *closed_chan;
				closed_chan = ftdmchan;
				ftdm_channel_close(&closed_chan);
				ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n");
				SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
			}
			break;

			/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
		case FTDM_CHANNEL_STATE_RINGING: 
			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
			SEND_STATE_SIGNAL(FTDM_SIGEVENT_RINGING);
				
			break;

			/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
		case FTDM_CHANNEL_STATE_RESET:
			{
				ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
				ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
			}
			break;

		default:
			{
				ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
			}
			break;
	}

	
	return FTDM_SUCCESS;
}
예제 #5
0
FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name, 
		int ms, ftdm_sched_callback_t callback, void *data, ftdm_timer_id_t *timerid)
{
	ftdm_status_t status = FTDM_FAIL;
	struct timeval now;
	int rc = 0;
	ftdm_timer_t *newtimer;

	ftdm_assert_return(sched != NULL, FTDM_EINVAL, "sched is null!\n");
	ftdm_assert_return(name != NULL, FTDM_EINVAL, "timer name is null!\n");
	ftdm_assert_return(callback != NULL, FTDM_EINVAL, "sched callback is null!\n");
	ftdm_assert_return(ms > 0, FTDM_EINVAL, "milliseconds must be bigger than 0!\n");

	if (timerid) {
		*timerid = 0;
	}

	rc = gettimeofday(&now, NULL);
	if (rc == -1) {
		ftdm_log(FTDM_LOG_ERROR, "Failed to retrieve time of day\n");
		return FTDM_FAIL;
	}

	ftdm_mutex_lock(sched->mutex);

	newtimer = ftdm_calloc(1, sizeof(*newtimer));
	if (!newtimer) {
		goto done;
	}
	newtimer->id = sched->currid;
	sched->currid++;
	if (!sched->currid) {
		ftdm_log(FTDM_LOG_NOTICE, "Timer id wrap around for sched %s\n", sched->name);
		/* we do not want currid to be zero since is an invalid id 
		 * TODO: check that currid does not exists already in the context, it'd be insane
		 * though, having a timer to live all that time */
		sched->currid++;
	}

	ftdm_set_string(newtimer->name, name);
	newtimer->callback = callback;
	newtimer->usrdata = data;

	newtimer->time.tv_sec = now.tv_sec + (ms / 1000);
	newtimer->time.tv_usec = now.tv_usec + (ms % 1000) * 1000;
	if (newtimer->time.tv_usec >= FTDM_MICROSECONDS_PER_SECOND) {
		newtimer->time.tv_sec += 1;
		newtimer->time.tv_usec -= FTDM_MICROSECONDS_PER_SECOND;
	}

	if (!sched->timers) {
		sched->timers = newtimer;
	}  else {
		newtimer->next = sched->timers;
		sched->timers->prev = newtimer;
		sched->timers = newtimer;
	}

	if (timerid) {
		*timerid = newtimer->id;
	}

	status = FTDM_SUCCESS;
done:

	ftdm_mutex_unlock(sched->mutex);
#ifdef __WINDOWS__
	UNREFERENCED_PARAMETER(sched);
	UNREFERENCED_PARAMETER(name);
	UNREFERENCED_PARAMETER(ms);
	UNREFERENCED_PARAMETER(callback);
	UNREFERENCED_PARAMETER(data);
	UNREFERENCED_PARAMETER(timerid);
#endif
	return status;
}
예제 #6
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;

    }
}