FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const char *param, const char *val) { void *newparameters; ftdm_assert_return(param != NULL, FTDM_FAIL, "param is null"); ftdm_assert_return(val != NULL, FTDM_FAIL, "val is null"); if (node->n_parameters == node->t_parameters) { newparameters = ftdm_realloc(node->parameters, (node->t_parameters + PARAMETERS_CHUNK_SIZE) * sizeof(*node->parameters)); if (!newparameters) { return FTDM_MEMERR; } node->parameters = newparameters; node->t_parameters = node->n_parameters + PARAMETERS_CHUNK_SIZE; } node->parameters[node->n_parameters].var = param; node->parameters[node->n_parameters].val = val; node->n_parameters++; return FTDM_SUCCESS; }
FT_DECLARE(ftdm_status_t) ftdm_conf_node_create(const char *name, ftdm_conf_node_t **node, ftdm_conf_node_t *parent) { ftdm_conf_node_t *newnode; ftdm_conf_node_t *sibling = NULL; ftdm_assert_return(name != NULL, FTDM_FAIL, "null node name"); newnode = ftdm_calloc(1, sizeof(**node)); if (!newnode) { return FTDM_MEMERR; } strncpy(newnode->name, name, sizeof(newnode->name)-1); newnode->name[sizeof(newnode->name)-1] = 0; newnode->parameters = ftdm_calloc(PARAMETERS_CHUNK_SIZE, sizeof(*newnode->parameters)); if (!newnode->parameters) { ftdm_safe_free(newnode); return FTDM_MEMERR; } newnode->t_parameters = PARAMETERS_CHUNK_SIZE; if (parent) { /* store who my parent is */ newnode->parent = parent; /* arrange them in FIFO order (newnode should be last) */ if (!parent->child) { /* we're the first node being added */ parent->child = newnode; } else { if (!parent->last) { /* we're the second node being added */ parent->last = newnode; parent->child->next = newnode; newnode->prev = parent->child; } else { /* we're the third or Nth node to be added */ sibling = parent->last; sibling->next = newnode; parent->last = newnode; newnode->prev = sibling; } } } *node = newnode; return FTDM_SUCCESS; }
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; }
FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device) { ftdm_interrupt_t *interrupt = NULL; #ifndef WIN32 int fds[2]; #endif ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "interrupt double pointer is null!\n"); interrupt = ftdm_calloc(1, sizeof(*interrupt)); if (!interrupt) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n"); return FTDM_FAIL; } interrupt->device = device; #ifdef WIN32 interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL); if (!interrupt->event) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n"); goto failed; } #else if (pipe(fds)) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno)); goto failed; } interrupt->readfd = fds[0]; interrupt->writefd = fds[1]; #endif *ininterrupt = interrupt; return FTDM_SUCCESS; failed: if (interrupt) { #ifndef WIN32 if (interrupt->readfd) { close(interrupt->readfd); close(interrupt->writefd); interrupt->readfd = -1; interrupt->writefd = -1; } #endif ftdm_safe_free(interrupt); } return FTDM_FAIL; }
ftdm_status_t sngisdn_add_var(sngisdn_chan_data_t *sngisdn_info, const char* var, const char* val) { char *t_name = 0, *t_val = 0; if (!var || !val) { return FTDM_FAIL; } if (!sngisdn_info->variables) { /* initialize on first use */ sngisdn_info->variables = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys); ftdm_assert_return(sngisdn_info->variables, FTDM_FAIL, "Failed to create hash table\n"); } t_name = ftdm_strdup(var); t_val = ftdm_strdup(val); hashtable_insert(sngisdn_info->variables, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE); return FTDM_SUCCESS; }
FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt) { ftdm_interrupt_t *interrupt = NULL; ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n"); interrupt = *ininterrupt; #ifdef WIN32 CloseHandle(interrupt->event); #else close(interrupt->readfd); close(interrupt->writefd); interrupt->readfd = -1; interrupt->writefd = -1; #endif ftdm_safe_free(interrupt); *ininterrupt = NULL; return FTDM_SUCCESS; }
FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt) { ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n"); #ifdef WIN32 if (!SetEvent(interrupt->event)) { ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n"); return FTDM_FAIL; } #else int err; if ((err = write(interrupt->writefd, "w", 1)) != 1) { ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno)); return FTDM_FAIL; } #endif return FTDM_SUCCESS; }
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; }
FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan) { ftdm_channel_state_t state; ftdm_assert_return(fchan->span->state_processor, FTDM_FAIL, "Cannot process states without a state processor!\n"); while (fchan->state_status == FTDM_STATE_STATUS_NEW) { state = fchan->state; ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Executing state processor for %s\n", ftdm_channel_state2str(fchan->state)); fchan->span->state_processor(fchan); if (state == fchan->state && fchan->state_status == FTDM_STATE_STATUS_NEW) { /* if the state did not change and is still NEW, the state status must go to PROCESSED * otherwise we don't touch it since is a new state and the old state was * already completed implicitly by the state_processor() function via some internal * call to ftdm_set_state() */ fchan->state_status = FTDM_STATE_STATUS_PROCESSED; } } return FTDM_SUCCESS; }
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; }
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; }
static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj) { ftdm_log(FTDM_LOG_INFO,"ftdm_gsm_run\r\n"); ftdm_channel_t *ftdmchan = NULL; ftdm_span_t *span = (ftdm_span_t *) obj; ftdm_gsm_span_data_t *gsm_data = NULL; ftdm_interrupt_t *data_sources[2] = {NULL, NULL}; int waitms = 0; gsm_data = span->signal_data; ftdm_assert_return(gsm_data != NULL, NULL, "No gsm data attached to span\n"); ftdm_log(FTDM_LOG_DEBUG, "GSM monitor thread for span %s started\n", span->name); if (!gsm_data->dchan || ftdm_channel_open_chan(gsm_data->dchan) != FTDM_SUCCESS) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open GSM d-channel of span %s!\n", span->name); gsm_data->dchan = NULL; goto done; } while (ftdm_running()) { wat_span_run(span->span_id); waitms = wat_span_schedule_next(span->span_id); if (waitms > GSM_POLL_INTERVAL_MS) { waitms = GSM_POLL_INTERVAL_MS; } ///////////////////// { ftdm_wait_flag_t flags = FTDM_READ | FTDM_EVENTS; ftdm_status_t status = ftdm_channel_wait(gsm_data->dchan, &flags, waitms); /* double check that this channel has a state change pending */ ftdm_channel_lock(gsm_data->bchan); ftdm_channel_advance_states(gsm_data->bchan); if(FTDM_SUCCESS == status ) { if(flags &FTDM_READ ) { char buffer[1025]; int n = 0, m = 0; memset(buffer, 0, sizeof(buffer)); n = read_channel(gsm_data->dchan, buffer, sizeof(buffer)-1); m = strlen(buffer); wat_span_process_read(span->span_id, buffer, m); #if LOG_SIG_DATA printf("<<======================= incomming data len = %d, %s\r\n", n, buffer); #endif } } ftdm_channel_advance_states(gsm_data->bchan); ftdm_channel_unlock(gsm_data->bchan); } ftdm_span_trigger_signals(span); } done: if (data_sources[0]) { ftdm_interrupt_destroy(&data_sources[0]); } ftdm_log(FTDM_LOG_DEBUG, "GSM thread ending.\n"); return NULL; }
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; }
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; }
FT_DECLARE(ftdm_status_t) ftdm_sched_run(ftdm_sched_t *sched) { ftdm_status_t status = FTDM_FAIL; ftdm_timer_t *runtimer; ftdm_timer_t *timer; ftdm_sched_callback_t callback; int ms = 0; int rc = -1; void *data; struct timeval now; ftdm_assert_return(sched != NULL, FTDM_EINVAL, "sched is null!\n"); tryagain: ftdm_mutex_lock(sched->mutex); rc = gettimeofday(&now, NULL); if (rc == -1) { ftdm_log(FTDM_LOG_ERROR, "Failed to retrieve time of day\n"); goto done; } timer = sched->timers; while (timer) { runtimer = timer; timer = runtimer->next; ms = ((runtimer->time.tv_sec - now.tv_sec) * 1000) + ((runtimer->time.tv_usec - now.tv_usec) / 1000); if (ms <= 0) { if (runtimer == sched->timers) { sched->timers = runtimer->next; if (sched->timers) { sched->timers->prev = NULL; } } callback = runtimer->callback; data = runtimer->usrdata; if (runtimer->next) { runtimer->next->prev = runtimer->prev; } if (runtimer->prev) { runtimer->prev->next = runtimer->next; } runtimer->id = 0; ftdm_safe_free(runtimer); /* avoid deadlocks by releasing the sched lock before triggering callbacks */ ftdm_mutex_unlock(sched->mutex); callback(data); /* after calling a callback we must start the scanning again since the * callback or some other thread may have added or cancelled timers to * the linked list */ goto tryagain; } } status = FTDM_SUCCESS; done: ftdm_mutex_unlock(sched->mutex); #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(sched); #endif return status; }
FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int ms) { int num = 1; #ifdef WIN32 DWORD res = 0; HANDLE ints[2]; #else int res = 0; struct pollfd ints[2]; char pipebuf[255]; #endif ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Condition is null!\n"); /* start implementation */ #ifdef WIN32 ints[0] = interrupt->event; if (interrupt->device != FTDM_INVALID_SOCKET) { num++; ints[1] = interrupt->device; } res = WaitForMultipleObjects(num, ints, FALSE, ms >= 0 ? ms : INFINITE); switch (res) { case WAIT_TIMEOUT: return FTDM_TIMEOUT; case WAIT_FAILED: case WAIT_ABANDONED: /* is it right to fail with abandoned? */ return FTDM_FAIL; default: if (res >= (sizeof(ints)/sizeof(ints[0]))) { ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res); return FTDM_FAIL; } return FTDM_SUCCESS; } #else ints[0].fd = interrupt->readfd; ints[0].events = POLLIN; ints[0].revents = 0; if (interrupt->device != FTDM_INVALID_SOCKET) { num++; ints[1].fd = interrupt->device; ints[1].events = POLLIN; ints[1].revents = 0; } res = poll(ints, num, ms); if (res == -1) { ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno)); return FTDM_FAIL; } if (res == 0) { return FTDM_TIMEOUT; } if (ints[0].revents & POLLIN) { res = read(ints[0].fd, pipebuf, sizeof(pipebuf)); if (res == -1) { ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno)); } } return FTDM_SUCCESS; #endif }