typedef enum {
BST_FREE,
BST_WAITING,
- BST_ACK,
BST_READY,
BST_FAIL
} sangoma_boost_request_status_t;
int flags;
} sangoma_boost_request_t;
+typedef struct {
+ int call_setup_id;
+ int last_event_id;
+} sangoma_boost_call_t;
+
+#define CALL_DATA(ftdmchan) ((sangoma_boost_call_t*)((ftdmchan)->call_data))
+
//#define MAX_REQ_ID FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * FTDM_MAX_CHANNELS_PHYSICAL_SPAN
#define MAX_REQ_ID 6000
ftdm_mutex_lock(request_mutex);
if ((id = SETUP_GRID[span][chan])) {
- assert(id <= MAX_REQ_ID);
+ ftdm_assert(id <= MAX_REQ_ID, "Invalid id");
req_map[id] = 0;
SETUP_GRID[span][chan] = 0;
}
*/
static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line)
{
- assert(r <= MAX_REQ_ID);
+ ftdm_assert(r <= MAX_REQ_ID, "Invalid id");
ftdm_mutex_lock(request_mutex);
req_map[r] = 0;
ftdm_mutex_unlock(request_mutex);
r = ++last_req;
if (r >= MAX_REQ_ID) {
- r = i = last_req = 1;
+ r = last_req = 1;
}
if (req_map[r]) {
}
#define next_request_id() __next_request_id(__FUNCTION__, __LINE__)
+
+static void print_request_ids(void)
+{
+ sangoma_boost_request_id_t i = 0;
+
+ ftdm_mutex_lock(request_mutex);
+
+ for (i=1; i<= MAX_REQ_ID; i++){
+ if (req_map[i]) {
+ ftdm_log(FTDM_LOG_CRIT, "Used Request ID=%i\n",i);
+ }
+ }
+
+ ftdm_mutex_unlock(request_mutex);
+
+ return;
+}
+
+
/**
* \brief Finds the channel that triggered an event
* \param span Span where to search the channel
{
uint32_t i;
ftdm_channel_t *ftdmchan = NULL;
- ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data;
uint32_t targetspan = event->span+1;
uint32_t targetchan = event->chan+1;
+
+ /* NC: Sanity check in case the call setup id does not relate
+ to span. This can happen if RESTART is received on a
+ full load. Where stray ACK messages can arrive after
+ a RESTART has taken place.
+ */
+ if (!span) {
+ ftdm_log(FTDM_LOG_CRIT, "No Span for Event=%s s%dc%d cid=%d\n",
+ BOOST_DECODE_EVENT_ID(event->event_id),
+ event->span,
+ event->chan,
+ event->call_setup_id);
+ return NULL;
+ }
+
+ sangoma_boost_data = span->signal_data;
+
if (sangoma_boost_data->sigmod) {
/* span is not strictly needed here since we're supposed to get only events for our span */
targetspan = event->span;
* and PRI stack will retransmit a second SETUP after the first timeout, so
* we should allow for at least 8 seconds.
*/
+
int boost_request_timeout = 10000;
sangoma_boost_request_status_t st;
char dnis[128] = "";
char *gr = NULL;
uint32_t count = 0;
int tg=0;
+
+ /* NC: On large number of calls 10 seconds is not enough.
+ Resetting to 30 seconds. Especially on ss7 when
+ links are reset during large call volume */
+ if (!sangoma_boost_data->sigmod) {
+ boost_request_timeout = 30000;
+ }
if (sangoma_boost_data->sigmod) {
ftdm_log(FTDM_LOG_CRIT, "This function should not be called when sigmod was configured in boost\n");
}
if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED)) {
- ftdm_log(FTDM_LOG_CRIT, "SPAN is not online.\n");
+ ftdm_log(FTDM_LOG_CRIT, "SPAN is Suspended.\n");
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ if (check_congestion(tg)) {
+ ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (CONGESTION)\n",tg+1);
+ *ftdmchan = NULL;
+ return FTDM_FAIL;
+ }
+
+ if (count >= span->chan_count) {
+ ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
*ftdmchan = NULL;
return FTDM_FAIL;
}
-
- ftdm_set_string(dnis, caller_data->dnis.digits);
r = next_request_id();
if (r == 0) {
*ftdmchan = NULL;
return FTDM_FAIL;
}
- sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r);
+
+ /* After this point we must release request id before we leave the function
+ in case of an error. */
+
+ ftdm_set_string(dnis, caller_data->dnis.digits);
if ((gr = strchr(dnis, '@'))) {
*gr++ = '\0';
tg--;
}
}
+
+ sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r);
+
event.trunk_group = tg;
- if (check_congestion(tg)) {
- ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1);
- *ftdmchan = NULL;
- return FTDM_FAIL;
- }
ftdm_span_channel_use_count(span, &count);
- if (count >= span->chan_count) {
- ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
- *ftdmchan = NULL;
- return FTDM_FAIL;
- }
-
if (gr && *(gr+1)) {
switch(*gr) {
case 'g':
if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
- status = FTDM_FAIL;
+ status = OUTBOUND_REQUESTS[r].status = FTDM_FAIL;
if (!sangoma_boost_data->sigmod) {
*ftdmchan = NULL;
}
if (!sangoma_boost_data->sigmod) {
*ftdmchan = NULL;
}
- ftdm_log(FTDM_LOG_CRIT, "s%dc%d: Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", (*ftdmchan)->physical_span_id, (*ftdmchan)->physical_chan_id, r);
+ ftdm_log(FTDM_LOG_CRIT, "Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", r);
goto done;
}
}
ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s over boost channel with request id %d\n", event.called_number_digits, r);
if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+ release_request_id(r);
ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
return FTDM_FAIL;
}
uint32_t event_span = event->span+1;
uint32_t event_chan = event->chan+1;
+
if (nack_map[event->call_setup_id]) {
+ /* In this scenario outgoing call was alrady stopped
+ via NACK and now we are expecting an NACK_ACK.
+ If we receive an ACK its a race condition thus
+ ignor it */
return;
}
OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
return;
}
- }
+ } else {
+
+ ftdm_assert(!mcon->sigmod, "CALL STOP ACK: Invalid Sigmod Path");
+
+ if ((ftdmchan = find_ftdmchan(OUTBOUND_REQUESTS[event->call_setup_id].span, (sangomabc_short_event_t*)event, 1))) {
+ int r;
+ /* NC: If we get CALL START ACK and channel is in active state
+ then we are completely out of sync with the other end.
+ Treat CALL START ACK as CALL STOP and hangup the current call.
+ */
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_UP ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) {
+ ftdm_log(FTDM_LOG_CRIT, "FTDM_CHAN STATE UP/PROG/PROG_MEDIA -> Changed to HANGUP %d:%d\n", event->span+1,event->chan+1);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP, 0, r);
+
+ } else if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
+ /* Do nothing because outgoing STOP will generaate a stop ack */
+
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "FTDM_CHAN STATE INVALID %s on IN CALL ACK %d:%d\n", ftdm_channel_state2str(ftdmchan->state),event->span+1,event->chan+1);
+
+ }
+ ftdmchan=NULL;
+ }
+ }
+
if (!ftdmchan) {
ftdm_log(FTDM_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
} else {
/* only reason to be here is failed to open channel when we we're in sigmod */
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
}
- ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+
sangomabc_exec_command(mcon,
event->span,
event->chan,
{
ftdm_channel_t *ftdmchan;
int r = 0;
-
+
if ((ftdmchan = find_ftdmchan(span, event, 1))) {
ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
ftdm_mutex_lock(ftdmchan->mutex);
}
}
+
/**
* \brief Handler for call start nack event
* \param span Span where event was fired
if (event->call_setup_id) {
if (sangoma_boost_data->sigmod) {
ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
- ftdmchan->call_data = (void*)(intptr_t)event->event_id;
+ CALL_DATA(ftdmchan)->last_event_id = event->event_id;
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
} else {
sangomabc_exec_command(mcon,
/* if there is no call setup id this should not be an outbound channel for sure */
ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), "Yay, outbound flag should not be set here!\n");
- ftdmchan->call_data = (void*)(intptr_t)event->event_id;
+ CALL_DATA(ftdmchan)->last_event_id = event->event_id;
ftdm_mutex_lock(ftdmchan->mutex);
ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
if (r == FTDM_STATE_CHANGE_SUCCESS) {
ftdm_mutex_lock(ftdmchan->mutex);
- if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
+ if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP) ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+
+ /* NC: Checking for state DOWN because ss7box can
+ send CALL_STOP twice in a row. If we do not check for
+ STATE_DOWN we will set the state back to termnating
+ and block the channel forever
+ */
+
/* racing condition where both sides initiated a hangup
* Do not change current state as channel is already clearing
* itself through local initiated hangup */
if ((ftdmchan = find_ftdmchan(span, event, 1))) {
ftdm_mutex_lock(ftdmchan->mutex);
- if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+
+ if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP) ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+
+ /* NC: Do nothing here because we are in process
+ of stopping the call. So ignore the ANSWER. */
+ ftdm_log(FTDM_LOG_CRIT, "ANSWER BUT CALL IS HANGUP %d:%d\n", event->span+1,event->chan+1);
+
+ } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
ftdmchan->init_state = FTDM_CHANNEL_STATE_UP;
+
} else {
int r = 0;
ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, 0, r);
if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
int r;
+
+ /* NC: If we get CALL START and channel is in active state
+ then we are completely out of sync with the other end.
+ Treat CALL START as CALL STOP and hangup the current call.
+ */
+
if (ftdmchan->state == FTDM_CHANNEL_STATE_UP) {
ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1);
ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
handle_call_done(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_START_NACK_ACK:
- handle_call_done(span, mcon, event);
- nack_map[event->call_setup_id] = 0;
+ /* On NACK ack span chan are always invalid
+ All there is to do is to clear the id */
+ if (event->call_setup_id) {
+ nack_map[event->call_setup_id] = 0;
+ release_request_id(event->call_setup_id);
+ }
break;
case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
handle_call_loop_start(span, mcon, event);
if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG)) {
ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
- if (ftdmchan->call_data && ((uint32_t)(intptr_t)ftdmchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) {
+ if (ftdmchan->call_data && CALL_DATA(ftdmchan)->last_event_id == SIGBOOST_EVENT_CALL_START_NACK) {
sangomabc_exec_command(mcon,
BOOST_SPAN(ftdmchan),
BOOST_CHAN(ftdmchan),
}
}
ftdmchan->sflags = 0;
- ftdmchan->call_data = NULL;
+ memset(ftdmchan->call_data,0,sizeof(sangoma_boost_call_t));
+
if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
/* we dont want to call ftdm_channel_done just yet until call released is received */
ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n",
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
if (susp) {
- for (j = 0; j <= span->chan_count; j++) {
- ftdm_mutex_lock(span->channels[j]->mutex);
- ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
- ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
- state_advance(span->channels[j]);
- ftdm_channel_complete_state(span->channels[j]);
- ftdm_mutex_unlock(span->channels[j]->mutex);
+ for(j = 1; j <= span->chan_count; j++) {
+ if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE) || susp) {
+ ftdm_mutex_lock(span->channels[j]->mutex);
+ ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+ if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
+ }
+ state_advance(span->channels[j]);
+ ftdm_channel_complete_state(span->channels[j]);
+ ftdm_mutex_unlock(span->channels[j]->mutex);
+ }
}
} else {
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
sangoma_boost_data->iteration = 0;
}
#endif
- res = ftdm_interrupt_multiple_wait(ints, numints, -1);
- if (FTDM_SUCCESS != res) {
+ res = ftdm_interrupt_multiple_wait(ints, numints, 100);
+ if (FTDM_SUCCESS != res && FTDM_TIMEOUT != res) {
ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res);
return -1;
}
if (ftdm_boost_wait_event(span) < 0) {
ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n");
- goto error;
}
while ((event = ftdm_boost_read_event(span))) {
goto end;
-error:
ftdm_log(FTDM_LOG_CRIT, "Boost event processing Error!\n");
end:
return NULL;
}
+#if 0
+static int sigmod_ss7box_isup_exec_cmd(ftdm_stream_handle_t *stream, char *cmd)
+{
+ FILE *fp;
+ int status=0;
+ char path[1024];
+
+ fp = popen(cmd, "r");
+ if (fp == NULL) {
+ stream->write_function(stream, "%s: -ERR failed to execute cmd: %s\n",
+ __FILE__,cmd);
+ return -1;
+ }
+
+ while (fgets(path, sizeof(path)-1, fp) != NULL) {
+ path[sizeof(path)-1]='\0';
+ stream->write_function(stream,"%s", path);
+ }
+
+
+ status = pclose(fp);
+ if (status == -1) {
+ /* Error reported by pclose() */
+ } else {
+ /* Use macros described under wait() to inspect `status' in order
+ to determine success/failure of command executed by popen() */
+ }
+
+ return status;
+}
+#endif
#define FTDM_BOOST_SYNTAX "list sigmods | <sigmod_name> <command>"
/**
if (!strcasecmp(argv[0], "list")) {
if (!strcasecmp(argv[1], "sigmods")) {
if (ftdm_sangoma_boost_list_sigmods(stream) != FTDM_SUCCESS) {
- stream->write_function(stream, "%s: -ERR failed to execute cmd\n", __FILE__);
+ stream->write_function(stream, "-ERR failed to list sigmods\n");
goto done;
}
goto done;
}
+
+ if (!strcasecmp(argv[1], "ids")) {
+ print_request_ids();
+ goto done;
+ }
+
+#ifndef __WINDOWS__
+#if 0
+/* NC: This code crashes the kernel due to fork on heavy fs load */
+ } else if (!strcasecmp(argv[0], "ss7box_isupd_ckt")) {
+
+ if (!strcasecmp(argv[1], "used")) {
+ stream->write_function(stream, "ss7box_isupd: in use\n", FTDM_BOOST_SYNTAX);
+ sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh inuse");
+ } else if (!strcasecmp(argv[1], "reset")) {
+ stream->write_function(stream, "ss7box_isupd: in reset\n", FTDM_BOOST_SYNTAX);
+ sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh reset");
+ } else if (!strcasecmp(argv[1], "ready")) {
+ stream->write_function(stream, "ss7box_isupd: ready \n", FTDM_BOOST_SYNTAX);
+ sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh free");
+ } else {
+ stream->write_function(stream, "ss7box_isupd: list\n", FTDM_BOOST_SYNTAX);
+ sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh");
+ }
+
+ goto done;
+#endif
+#endif
+ } else if (!strcasecmp(argv[0], "restart")) {
+ sangomabc_connection_t *pcon;
+ ftdm_sangoma_boost_data_t *sangoma_boost_data;
+ ftdm_span_t *span;
+ int err = ftdm_span_find_by_name(argv[1], &span);
+ if (FTDM_SUCCESS != err) {
+ stream->write_function(stream, "-ERR failed to find span by name %s\n",argv[1]);
+ goto done;
+ }
+
+ sangoma_boost_data = span->signal_data;
+ pcon = &sangoma_boost_data->pcon;
+
+ /* No need to set any span flags because
+ our RESTART will generate a RESTART from the sig daemon */
+ sangomabc_exec_commandp(pcon,
+ 0,
+ 0,
+ -1,
+ SIGBOOST_EVENT_SYSTEM_RESTART,
+ 0);
+
+ goto done;
+
} else {
boost_sigmod_interface_t *sigmod_iface = NULL;
sigmod_iface = hashtable_search(g_boost_modules_hash, argv[0]);
*/
static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_boost_io_init)
{
- assert(fio != NULL);
+ ftdm_assert(fio != NULL, "fio is NULL");
memset(&ftdm_sangoma_boost_interface, 0, sizeof(ftdm_sangoma_boost_interface));
ftdm_sangoma_boost_interface.name = "boost";
ftdm_dso_lib_t lib = NULL;
char path[255] = "";
char *err = NULL;
+ int j = 0;
unsigned paramindex = 0;
ftdm_status_t rc = FTDM_SUCCESS;
ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
sangoma_boost_data->mcon.cfg.remote_port = remote_port;
}
+
+ for (j = 1; j <= span->chan_count; j++) {
+ span->channels[j]->call_data = ftdm_calloc(1,sizeof(sangoma_boost_call_t));
+ if (!span->channels[j]->call_data) {
+ FAIL_CONFIG_RETURN(FTDM_FAIL);
+ }
+ }
+
span->signal_cb = sig_cb;
span->start = ftdm_sangoma_boost_start;
span->stop = ftdm_sangoma_boost_stop;
*/
#include "openzap.h"
-#include "sangoma_boost_client.h"
+#include "sangoma_boost_client.h"
#include "zap_sangoma_boost.h"
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
+#ifndef __WINDOWS__
+#include <poll.h>
+#endif
#define MAX_TRUNK_GROUPS 64
static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
return;
}
- }
+ } else {
+ if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, (sangomabc_short_event_t*)event, 1))) {
+ int r;
+
+ /* NC: If we get CALL START ACK and channel is in active state
+ then we are completely out of sync with the other end.
+ Treat CALL START ACK as CALL STOP and hangup the current call.
+ */
+
+ if (zchan->state == ZAP_CHANNEL_STATE_UP ||
+ zchan->state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA ||
+ zchan->state == ZAP_CHANNEL_STATE_PROGRESS) {
+ zap_log(ZAP_LOG_CRIT, "ZCHAN STATE UP/PROG/PROG_MEDIA -> Changed to HANGUP %d:%d\n", event->span+1,event->chan+1);
+ zap_set_state_r(zchan, ZAP_CHANNEL_STATE_HANGUP, 0, r);
+
+ } else if (zap_test_sflag(zchan, SFLAG_HANGUP)) {
+ /* Do nothing because outgoing STOP will generaate a stop ack */
+
+ } else {
+ zap_log(ZAP_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL ACK %d:%d\n", zap_channel_state2str(zchan->state),event->span+1,event->chan+1);
+
+ }
+ zchan=NULL;
+ }
+ }
//printf("WTF BAD ACK CSid=%d span=%d chan=%d\n", event->call_setup_id, event->span+1,event->chan+1);
if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 1))) {
zap_mutex_lock(zchan->mutex);
- if (zap_test_sflag(zchan, SFLAG_HANGUP)) {
+ if (zap_test_sflag(zchan, SFLAG_HANGUP) || zchan->state == ZAP_CHANNEL_STATE_DOWN) {
+
+ /* NC: Checking for state DOWN because ss7box can
+ send CALL_STOP twice in a row. If we do not check for
+ STATE_DOWN we will set the state back to termnating
+ and block the channel forever
+ */
+
/* racing condition where both sides initiated a hangup
* Do not change current state as channel is already clearing
* itself through local initiated hangup */
if ((zchan = find_zchan(span, event, 1))) {
zap_mutex_lock(zchan->mutex);
- if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+ if (zap_test_sflag(zchan, SFLAG_HANGUP) ||
+ zchan->state == ZAP_CHANNEL_STATE_DOWN ||
+ zchan->state == ZAP_CHANNEL_STATE_TERMINATING) {
+ /* NC: Do nothing here because we are in process
+ of stopping the call. So ignore the ANSWER. */
+ zap_log(ZAP_LOG_CRIT, "ANSWER BUT CALL IS HANGUP %d:%d\n", event->span+1,event->chan+1);
+
+ } else if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
zchan->init_state = ZAP_CHANNEL_STATE_UP;
} else {
int r = 0;
if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) {
if ((zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
int r;
+
+ /* NC: If we get CALL START and channel is in active state
+ then we are completely out of sync with the other end.
+ Treat CALL START as CALL STOP and hangup the current call.
+ */
+
if (zchan->state == ZAP_CHANNEL_STATE_UP) {
zap_log(ZAP_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1);
zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
return NULL;
}
+
+#ifndef __WINDOWS__
+static int waitfor_2sockets(int fda, int fdb, char *a, char *b, int timeout)
+{
+ struct pollfd pfds[2];
+ int res = 0;
+ int errflags = (POLLERR | POLLHUP | POLLNVAL);
+
+ if (fda < 0 || fdb < 0) {
+ return -1;
+ }
+
+
+waitfor_2sockets_tryagain:
+
+ *a=0;
+ *b=0;
+
+
+ memset(pfds, 0, sizeof(pfds));
+
+ pfds[0].fd = fda;
+ pfds[1].fd = fdb;
+ pfds[0].events = POLLIN | errflags;
+ pfds[1].events = POLLIN | errflags;
+
+ res = poll(pfds, 2, timeout);
+
+ if (res > 0) {
+ res = 1;
+ if ((pfds[0].revents & errflags) || (pfds[1].revents & errflags)) {
+ res = -1;
+ } else {
+ if ((pfds[0].revents & POLLIN)) {
+ *a=1;
+ res++;
+ }
+ if ((pfds[1].revents & POLLIN)) {
+ *b=1;
+ res++;
+ }
+ }
+
+ if (res == 1) {
+ /* No event found what to do */
+ res=-1;
+ }
+ } else if (res < 0) {
+
+ if (errno == EINTR || errno == EAGAIN) {
+ goto waitfor_2sockets_tryagain;
+ }
+
+ }
+
+ return res;
+}
+#endif
+
/**
* \brief Main thread function for sangoma boost span (monitor)
* \param me Current thread
zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
sangomabc_connection_t *mcon, *pcon;
uint32_t ms = 10; //, too_long = 20000;
-
+ int max, activity, i;
+ sangomabc_event_t *event;
+ struct timeval tv;
+ fd_set rfds, efds;
+#ifndef __WINDOWS__
+ char a=0,b=0;
+#endif
sangoma_boost_data->pcon = sangoma_boost_data->mcon;
zap_set_flag(mcon, MSU_FLAG_DOWN);
while (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING)) {
- fd_set rfds, efds;
- struct timeval tv = { 0, ms * 1000 };
- int max, activity, i = 0;
- sangomabc_event_t *event = NULL;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = ms* 1000;
+ max=0;
+ activity=0;
+ i=0;
+ event = NULL;
if (!zap_running()) {
sangomabc_exec_commandp(pcon,
FD_SET(pcon->socket, &efds);
max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
-
+
+#ifdef __WINDOWS__
if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
goto error;
}
}
}
+#else
+ a=0;
+ b=0;
+ i=0;
+ tv.tv_sec=0;
+ activity = waitfor_2sockets(pcon->socket,mcon->socket,&a,&b,ms);
+ if (activity) {
+ if (a) {
+ while ((event = sangomabc_connection_readp(pcon, i))) {
+ parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
+ i++;
+ }
+ }
+ i=0;
+
+ if (b) {
+ if ((event = sangomabc_connection_read(mcon, i))) {
+ parse_sangoma_event(span, mcon, (sangomabc_short_event_t*)event);
+ i++;
+ }
+ }
+ } else if (activity < 0) {
+ goto error;
+ }
+
+#endif
pcon->hb_elapsed += ms;