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; } }
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; }
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; }
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; }
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; }
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; } }