Merge root@192.168.1.163:/freeswitch

Conflicts:

	libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
This commit is contained in:
David Yat Sin 2010-04-15 11:54:32 -04:00
commit c4f821f822
26 changed files with 1002 additions and 153 deletions

View File

@ -112,3 +112,9 @@ QTime Call::getCurrentStateTime()
int now = QDateTime::fromTime_t(time).secsTo(QDateTime::currentDateTime());
return QTime::fromString(QString::number(now), "s");
}
/*bool Call::transfer()
{
g_FSHost.sendCmd("uuid_bridge", "")
}*/

View File

@ -38,7 +38,8 @@ typedef enum {
FSCOMM_CALL_STATE_RINGING = 0,
FSCOMM_CALL_STATE_TRYING = 1,
FSCOMM_CALL_STATE_ANSWERED = 2,
FSCOMM_CALL_STATE_FAILED = 3
FSCOMM_CALL_STATE_FAILED = 3,
FSCOMM_CALL_STATE_TRANSFER = 4
} fscomm_call_state_t;
typedef enum {
@ -76,6 +77,8 @@ public:
void setAnsweredEpoch(qulonglong time) { _answeredEpoch = time/1000000; }
QTime getCurrentStateTime();
/*bool transfer();*/
private:
QSharedPointer<Channel> _channel; /* This should be our portaudio channel */
QSharedPointer<Channel> _otherLegChannel;

View File

@ -105,9 +105,23 @@ void ConsoleWindow::cmdSendClicked()
QString res;
g_FSHost.sendCmd(cmd.toAscii().data(), args.toAscii().data(), &res);
QStandardItem *item = new QStandardItem(res);
item->setData(SWITCH_LOG_CONSOLE, ConsoleModel::LogLevelRole);
addNewConsoleItem(item);
if (!res.isEmpty())
{
/* Remove \r\n */
QStringList textList = res.split(QRegExp("(\r+)"), QString::SkipEmptyParts);
QString final_str;
for (int line = 0; line<textList.size(); line++)
{
final_str += textList[line];
}
QStringList lines = final_str.split(QRegExp("(\n+)"), QString::SkipEmptyParts);
for (int line = 0; line < lines.size(); ++line)
{
QStandardItem *item = new QStandardItem(lines[line]);
item->setData(SWITCH_LOG_CONSOLE, ConsoleModel::LogLevelRole);
addNewConsoleItem(item);
}
}
ui->lineCmd->clear();
}

View File

@ -101,6 +101,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup()));
connect(ui->recoredCallBtn, SIGNAL(toggled(bool)), SLOT(recordCall(bool)));
connect(ui->btnHold, SIGNAL(toggled(bool)), this, SLOT(holdCall(bool)));
/*connect(ui->btnTransfer, SIGNAL(clicked()), this, SLOT(transferCall()));*/
connect(ui->tableCalls, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(callTableDoubleClick(QTableWidgetItem*)));
connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered()));
connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close()));
@ -280,9 +281,9 @@ void MainWindow::callTableDoubleClick(QTableWidgetItem *item)
void MainWindow::makeCall()
{
bool ok;
bool ok = true;
QString dialstring = QInputDialog::getText(this, tr("Make new call"),
tr("Number to dial:"), QLineEdit::Normal, NULL,&ok);
tr("Number to dial:"), QLineEdit::Normal, NULL,&ok);
QSharedPointer<Account> acc = g_FSHost.getCurrentDefaultAccount();
if (!acc.isNull()) {

View File

@ -77,6 +77,7 @@ private slots:
void callFailed(QSharedPointer<Call>);
void recordCall(bool);
void holdCall(bool);
/*void transferCall();*/
void setDefaultAccount();
void accountAdd(QSharedPointer<Account>);
void accountDel(QSharedPointer<Account>);

View File

@ -91,6 +91,7 @@ static struct {
char hold_music[256];
switch_mutex_t *mutex;
analog_option_t analog_options;
switch_hash_t *ss7_configs;
} globals;
struct private_object {
@ -1961,6 +1962,15 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
}
static FIO_SIGNAL_CB_FUNCTION(on_ss7_signal)
{
if (on_common_signal(sigmsg) == FTDM_BREAK) {
return FTDM_SUCCESS;
}
ftdm_log(FTDM_LOG_DEBUG, "got ss7 sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, ftdm_signal_event2str(sigmsg->event_id));
return FTDM_SUCCESS;
}
static FIO_SIGNAL_CB_FUNCTION(on_analog_signal)
{
switch_status_t status = SWITCH_STATUS_FALSE;
@ -2022,10 +2032,140 @@ static uint32_t enable_analog_option(const char *str, uint32_t current_options)
}
/* create ftdm_conf_node_t tree based on a fixed pattern XML configuration list
* last 2 args are for limited aka dumb recursivity
* */
static int add_config_list_nodes(switch_xml_t swnode, ftdm_conf_node_t *rootnode,
const char *list_name, const char *list_element_name,
const char *sub_list_name, const char *sub_list_element_name)
{
char *var, *val;
switch_xml_t list;
switch_xml_t element;
switch_xml_t param;
ftdm_conf_node_t *n_list;
ftdm_conf_node_t *n_element;
list = switch_xml_child(swnode, list_name);
if (!list) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no list %s found\n", list_name);
return -1;
}
if ((FTDM_SUCCESS != ftdm_conf_node_create(list_name, &n_list, rootnode))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node\n", list_name);
return -1;
}
for (element = switch_xml_child(list, list_element_name); element; element = element->next) {
char *element_name = (char *) switch_xml_attr(element, "name");
if (!element_name) {
continue;
}
if ((FTDM_SUCCESS != ftdm_conf_node_create(list_element_name, &n_element, n_list))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create %s node for %s\n", list_element_name, element_name);
return -1;
}
ftdm_conf_node_add_param(n_element, "name", element_name);
for (param = switch_xml_child(element, "param"); param; param = param->next) {
var = (char *) switch_xml_attr_soft(param, "name");
val = (char *) switch_xml_attr_soft(param, "value");
ftdm_conf_node_add_param(n_element, var, val);
}
if (sub_list_name && sub_list_element_name) {
if (add_config_list_nodes(element, n_element, sub_list_name, sub_list_element_name, NULL, NULL)) {
return -1;
}
}
}
return 0;
}
static ftdm_conf_node_t *get_ss7_config_node(switch_xml_t cfg, const char *confname)
{
switch_xml_t signode, ss7configs, isup;
ftdm_conf_node_t *rootnode;
/* try to find the conf in the hash first */
rootnode = switch_core_hash_find(globals.ss7_configs, confname);
if (rootnode) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ss7 config %s was found in the hash already\n", confname);
return rootnode;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "not found %s config in hash, searching in xml ...\n", confname);
signode = switch_xml_child(cfg, "signaling_configs");
if (!signode) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found 'signaling_configs' XML config section\n");
return NULL;
}
ss7configs = switch_xml_child(signode, "sngss7_configs");
if (!ss7configs) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found 'sngss7_configs' XML config section\n");
return NULL;
}
/* search the isup config */
for (isup = switch_xml_child(ss7configs, "sng_isup"); isup; isup = isup->next) {
char *name = (char *) switch_xml_attr(isup, "name");
if (!name) {
continue;
}
if (!strcasecmp(name, confname)) {
break;
}
}
if (!isup) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not found '%s' sng_isup XML config section\n", confname);
return NULL;
}
/* found our XML chunk, create the root node */
if ((FTDM_SUCCESS != ftdm_conf_node_create("sng_isup", &rootnode, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create root node for sng_isup config %s\n", confname);
return NULL;
}
/* add mtp linksets */
if (add_config_list_nodes(isup, rootnode, "mtp_linksets", "mtp_linkset", "mtp_links", "mtp_link")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_linksets for sng_isup config %s\n", confname);
ftdm_conf_node_destroy(rootnode);
return NULL;
}
/* add mtp routes */
if (add_config_list_nodes(isup, rootnode, "mtp_routes", "mtp_route", NULL, NULL)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process mtp_routes for sng_isup config %s\n", confname);
ftdm_conf_node_destroy(rootnode);
return NULL;
}
/* add isup interfaces */
if (add_config_list_nodes(isup, rootnode, "isup_interfaces", "isup_interface", NULL, NULL)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to process isup_interfaces for sng_isup config %s\n", confname);
ftdm_conf_node_destroy(rootnode);
return NULL;
}
switch_core_hash_insert(globals.ss7_configs, confname, rootnode);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Added SS7 node configuration %s\n", confname);
return rootnode;
}
static switch_status_t load_config(void)
{
const char *cf = "freetdm.conf";
switch_xml_t cfg, xml, settings, param, spans, myspan;
ftdm_conf_node_t *ss7confnode = NULL;
ftdm_span_t *boost_spans[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN];
ftdm_span_t *boost_span = NULL;
unsigned boosti = 0;
@ -2054,6 +2194,91 @@ static switch_status_t load_config(void)
}
}
switch_core_hash_init(&globals.ss7_configs, module_pool);
if ((spans = switch_xml_child(cfg, "ss7_spans"))) {
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
ftdm_status_t zstatus = FTDM_FAIL;
const char *context = "default";
const char *dialplan = "XML";
ftdm_conf_parameter_t spanparameters[30];
char *id = (char *) switch_xml_attr(myspan, "id");
char *name = (char *) switch_xml_attr(myspan, "name");
char *configname = (char *) switch_xml_attr(myspan, "config");
ftdm_span_t *span = NULL;
uint32_t span_id = 0;
unsigned paramindex = 0;
if (!name && !id) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute 'id' or 'name', skipping ...\n");
continue;
}
if (!configname) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ss7 span missing required attribute, skipping ...\n");
continue;
}
if (name) {
zstatus = ftdm_span_find_by_name(name, &span);
} else {
if (switch_is_number(id)) {
span_id = atoi(id);
zstatus = ftdm_span_find(span_id, &span);
}
if (zstatus != FTDM_SUCCESS) {
zstatus = ftdm_span_find_by_name(id, &span);
}
}
if (zstatus != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
continue;
}
if (!span_id) {
span_id = span->span_id;
}
ss7confnode = get_ss7_config_node(cfg, configname);
if (!ss7confnode) {
ftdm_log(FTDM_LOG_ERROR, "Error finding ss7config '%s' for FreeTDM span id: %s\n", configname, switch_str_nil(id));
continue;
}
memset(spanparameters, 0, sizeof(spanparameters));
for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
if (sizeof(spanparameters)/sizeof(spanparameters[0]) == paramindex) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for ss7 span, ignoring any parameter after %s\n", var);
break;
}
if (!strcasecmp(var, "context")) {
context = val;
} else if (!strcasecmp(var, "dialplan")) {
dialplan = val;
} else {
spanparameters[paramindex].var = var;
spanparameters[paramindex].val = val;
paramindex++;
}
}
if (ftdm_configure_span("ss7", span, on_ss7_signal,
"confnode", ss7confnode,
"parameters", spanparameters,
TAG_END) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error configuring ss7 FreeTDM span %d\n", span_id);
continue;
}
SPAN_CONFIG[span->span_id].span = span;
switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
switch_copy_string(SPAN_CONFIG[span->span_id].type, "Sangoma (SS7)", sizeof(SPAN_CONFIG[span->span_id].type));
ftdm_log(FTDM_LOG_DEBUG, "Configured ss7 FreeTDM span %d with config node %s\n", span_id, configname);
}
}
if ((spans = switch_xml_child(cfg, "analog_spans"))) {
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
char *id = (char *) switch_xml_attr(myspan, "id");
@ -2504,7 +2729,6 @@ static switch_status_t load_config(void)
const char *dialplan = "XML";
uint32_t span_id = 0;
ftdm_span_t *span = NULL;
const char *tonegroup = NULL;
ftdm_conf_parameter_t spanparameters[30];
unsigned paramindex = 0;
@ -2526,9 +2750,8 @@ static switch_status_t load_config(void)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for boost span, ignoring any parameter after %s\n", var);
break;
}
if (!strcasecmp(var, "tonegroup")) {
tonegroup = val;
} else if (!strcasecmp(var, "context")) {
if (!strcasecmp(var, "context")) {
context = val;
} else if (!strcasecmp(var, "dialplan")) {
dialplan = val;
@ -2539,10 +2762,6 @@ static switch_status_t load_config(void)
}
}
if (!tonegroup) {
tonegroup = "us";
}
if (name) {
zstatus = ftdm_span_find_by_name(name, &span);
} else {
@ -3194,6 +3413,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown)
{
switch_hash_index_t *hi;
const void *var;
void *val;
/* destroy ss7 configs */
for (hi = switch_hash_first(NULL, globals.ss7_configs); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, &var, NULL, &val);
ftdm_conf_node_destroy(val);
}
ftdm_global_destroy();
// this breaks pika but they are MIA so *shrug*

View File

@ -29,6 +29,10 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
*
* Moises Silva <moy@sangoma.com>
*/
#include "freetdm.h"
@ -239,6 +243,82 @@ FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits
return 0;
}
#define PARAMETERS_CHUNK_SIZE 20
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;
/* save any siblings */
sibling = parent->child;
/* as a newborn I am first */
parent->child = newnode;
if (sibling) {
/* store a pointer to my next sibling */
newnode->next = sibling;
}
}
*node = newnode;
return FTDM_SUCCESS;
}
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_destroy(ftdm_conf_node_t *node)
{
ftdm_conf_node_t *curr = NULL;
ftdm_conf_node_t *child = node->child;
while (child) {
curr = child;
child = curr->next;
ftdm_conf_node_destroy(curr);
}
ftdm_free(node->parameters);
ftdm_free(node);
return FTDM_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c

View File

@ -1087,16 +1087,20 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_
}
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n",
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return FTDM_FAIL;
}
if (lock) {
ftdm_mutex_lock(ftdmchan->mutex);
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n",
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
if (lock) {
ftdm_mutex_unlock(ftdmchan->mutex);
}
return FTDM_FAIL;
}
if (ftdmchan->span->state_map) {
ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
goto end;
@ -1353,7 +1357,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
ftdm_span_channel_use_count(span, &count);
if (count >= span->chan_count) {
ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
ftdm_log(FTDM_LOG_CRIT, "All circuits are busy: active=%i max=%i.\n",
count, span->chan_count);
*ftdmchan = NULL;
return FTDM_FAIL;
}
@ -1623,8 +1628,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan,
if (ftdmchan->span->get_channel_sig_status) {
return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus);
} else {
ftdm_log(FTDM_LOG_ERROR, "get_channel_sig_status method not implemented!\n");
return FTDM_FAIL;
/* don't log error here, it can be called just to test if its supported */
return FTDM_NOTIMPL;
}
}

View File

@ -414,7 +414,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interru
for (i = 0; i < size; i++) {
ints[i] = interrupts[i]->event;
if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
ints[i+numdevices] = interrupts[i]->device;
ints[size+numdevices] = interrupts[i]->device;
numdevices++;
}
}
@ -446,9 +446,9 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interru
ints[i].revents = 0;
ints[i].fd = interrupts[i]->readfd;
if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
ints[i+numdevices].events = POLLIN;
ints[i+numdevices].revents = 0;
ints[i+numdevices].fd = interrupts[i]->device;
ints[size+numdevices].events = POLLIN;
ints[size+numdevices].revents = 0;
ints[size+numdevices].fd = interrupts[i]->device;
numdevices++;
}
}

View File

@ -92,7 +92,6 @@ typedef uint16_t sangoma_boost_request_id_t;
typedef enum {
BST_FREE,
BST_WAITING,
BST_ACK,
BST_READY,
BST_FAIL
} sangoma_boost_request_status_t;
@ -109,6 +108,13 @@ typedef struct {
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
@ -179,7 +185,7 @@ static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
r = ++last_req;
if (r >= MAX_REQ_ID) {
r = i = last_req = 1;
r = last_req = 1;
}
if (req_map[r]) {
@ -204,6 +210,25 @@ static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
}
#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
@ -215,10 +240,26 @@ static ftdm_channel_t *find_ftdmchan(ftdm_span_t *span, sangomabc_short_event_t
{
uint32_t i;
ftdm_channel_t *ftdmchan = NULL;
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
uint32_t targetspan = BOOST_EVENT_SPAN(sangoma_boost_data->sigmod, event);
uint32_t targetchan = BOOST_EVENT_CHAN(sangoma_boost_data->sigmod, event);
/* 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;
}
for(i = 1; i <= span->chan_count; i++) {
if (span->channels[i]->physical_span_id == targetspan && span->channels[i]->physical_chan_id == targetchan) {
ftdmchan = span->channels[i];
@ -276,12 +317,20 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
* 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");
@ -290,12 +339,22 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
}
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) {
@ -303,7 +362,11 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
*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';
@ -315,22 +378,14 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
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':
@ -373,7 +428,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
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;
}
@ -387,7 +442,7 @@ static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
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;
}
}
@ -494,6 +549,7 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call)
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;
}
@ -550,7 +606,12 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_
uint32_t event_span = BOOST_EVENT_SPAN(mcon->sigmod, event);
uint32_t event_chan = BOOST_EVENT_CHAN(mcon->sigmod, event);
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;
}
@ -607,15 +668,43 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_
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", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
} 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,
@ -636,7 +725,7 @@ static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sa
{
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);
@ -677,6 +766,7 @@ static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sa
}
}
/**
* \brief Handler for call start nack event
* \param span Span where event was fired
@ -718,7 +808,7 @@ static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mc
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,
@ -740,7 +830,7 @@ static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mc
/* 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) {
@ -793,7 +883,16 @@ static void handle_call_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sa
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 */
@ -848,8 +947,18 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon,
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);
@ -881,6 +990,12 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
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", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
@ -1179,8 +1294,12 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
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);
@ -1246,7 +1365,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
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),
@ -1266,7 +1385,8 @@ static __inline__ void state_advance(ftdm_channel_t *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",
@ -1457,13 +1577,17 @@ static __inline__ void check_state(ftdm_span_t *span)
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))) {
@ -1642,8 +1766,8 @@ static int ftdm_boost_wait_event(ftdm_span_t *span)
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;
}
@ -1730,7 +1854,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
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))) {
@ -1743,7 +1866,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
goto end;
error:
ftdm_log(FTDM_LOG_CRIT, "Boost event processing Error!\n");
end:
@ -1758,6 +1880,37 @@ 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>"
/**
@ -1780,11 +1933,63 @@ static FIO_API_FUNCTION(ftdm_sangoma_boost_api)
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]);
@ -1822,7 +2027,7 @@ done:
*/
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";
@ -2205,6 +2410,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
ftdm_dso_lib_t lib = NULL;
char path[255] = "";
char *err = NULL;
int j = 0;
unsigned paramindex = 0;
ftdm_status_t rc = FTDM_SUCCESS;
@ -2299,6 +2505,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
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;

View File

@ -77,7 +77,7 @@ static void sangomabc_print_event_call(sangomabc_connection_t *mcon, sangomabc_e
if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
return;
ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n",
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n",
dir ? "TX":"RX",
priority ? "P":"N",
sangomabc_event_id_name(event->event_id),
@ -96,7 +96,7 @@ static void sangomabc_print_event_short(sangomabc_connection_t *mcon, sangomabc_
{
if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
return;
ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [s%dc%d] Rc=%i CSid=%i Seq=%i \n",
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [s%dc%d] Rc=%i CSid=%i Seq=%i \n",
dir ? "TX":"RX",
priority ? "P":"N",
sangomabc_event_id_name(event->event_id),

View File

@ -51,6 +51,24 @@ enum e_sigboost_event_id_values
SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/
};
#define BOOST_DECODE_EVENT_ID(id) \
(id==SIGBOOST_EVENT_CALL_START)?"SIGBOOST_EVENT_CALL_START": \
(id==SIGBOOST_EVENT_CALL_START_ACK)?"SIGBOOST_EVENT_CALL_START_ACK": \
(id==SIGBOOST_EVENT_CALL_START_NACK)?"SIGBOOST_EVENT_CALL_START_NACK": \
(id==SIGBOOST_EVENT_CALL_ANSWERED)?"SIGBOOST_EVENT_CALL_ANSWERED": \
(id==SIGBOOST_EVENT_CALL_STOPPED)?"SIGBOOST_EVENT_CALL_STOPPED": \
(id==SIGBOOST_EVENT_CALL_STOPPED_ACK)?"SIGBOOST_EVENT_CALL_STOPPED_ACK": \
(id==SIGBOOST_EVENT_SYSTEM_RESTART)?"SIGBOOST_EVENT_SYSTEM_RESTART": \
(id==SIGBOOST_EVENT_SYSTEM_RESTART_ACK)?"SIGBOOST_EVENT_SYSTEM_RESTART_ACK": \
(id==SIGBOOST_EVENT_CALL_RELEASED)?"SIGBOOST_EVENT_CALL_RELEASED": \
(id==SIGBOOST_EVENT_CALL_PROGRESS)?"SIGBOOST_EVENT_CALL_PROGRESS": \
(id==SIGBOOST_EVENT_HEARTBEAT)?"SIGBOOST_EVENT_HEARTBEAT": \
(id==SIGBOOST_EVENT_INSERT_CHECK_LOOP)?"SIGBOOST_EVENT_INSERT_CHECK_LOOP": \
(id==SIGBOOST_EVENT_REMOVE_CHECK_LOOP)?"SIGBOOST_EVENT_REMOVE_CHECK_LOOP": \
(id==SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE)?"SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE": \
(id==SIGBOOST_EVENT_DIGIT_IN)?"SIGBOOST_EVENT_DIGIT_IN": "Unknown"
enum e_sigboost_release_cause_values
{
SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,

View File

@ -827,6 +827,9 @@ FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
FT_DECLARE(void) ftdm_cpu_monitor_disable(void);
FT_DECLARE(ftdm_status_t) ftdm_conf_node_create(const char *name, ftdm_conf_node_t **node, ftdm_conf_node_t *parent);
FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const char *param, const char *val);
FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node);
FIO_CODEC_FUNCTION(fio_slin2ulaw);
FIO_CODEC_FUNCTION(fio_ulaw2slin);

View File

@ -572,6 +572,30 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ;
#include "ftdm_dso.h"
#define FTDM_NODE_NAME_SIZE 50
typedef struct ftdm_conf_node_s {
/* node name */
char name[FTDM_NODE_NAME_SIZE];
/* total slots for parameters */
unsigned int t_parameters;
/* current number of parameters */
unsigned int n_parameters;
/* array of parameters */
ftdm_conf_parameter_t *parameters;
/* first node child */
struct ftdm_conf_node_s *child;
/* next node sibling */
struct ftdm_conf_node_s *next;
/* my parent if any */
struct ftdm_conf_node_s *parent;
} ftdm_conf_node_t;
typedef struct {
char name[256];
fio_io_load_t io_load;
@ -583,9 +607,9 @@ typedef struct {
\brief configure a given span signaling
\see sig_configure
This is just like sig_configure but receives
an array of paramters instead of va_list
an an ftdm_conf_node_t instead
I'd like to deprecate sig_configure and move
all modules to use sigparam_configure
all modules to use configure_span_signaling
*/
fio_configure_span_signaling_t configure_span_signaling;
ftdm_dso_lib_t lib;

View File

@ -32,11 +32,14 @@
*/
#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];
@ -484,7 +487,31 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_
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))) {
@ -640,7 +667,14 @@ static void handle_call_stop(zap_span_t *span, sangomabc_connection_t *mcon, san
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 */
@ -697,7 +731,14 @@ static void handle_call_answer(zap_span_t *span, sangomabc_connection_t *mcon, s
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;
@ -731,6 +772,12 @@ static void handle_call_start(zap_span_t *span, sangomabc_connection_t *mcon, sa
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);
@ -1380,6 +1427,65 @@ static void *zap_sangoma_events_run(zap_thread_t *me, void *obj)
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
@ -1391,7 +1497,13 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj)
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;
@ -1427,10 +1539,13 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj)
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,
@ -1451,7 +1566,8 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj)
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;
}
@ -1477,7 +1593,33 @@ static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj)
}
}
#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;

View File

@ -57,6 +57,24 @@ enum e_sigboost_event_id_values
SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
SIGBOOST_EVENT_DIGIT_IN = 0x8d, /*141*/
};
#define BOOST_DECODE_EVENT_ID(id) \
(id==SIGBOOST_EVENT_CALL_START)?"SIGBOOST_EVENT_CALL_START": \
(id==SIGBOOST_EVENT_CALL_START_ACK)?"SIGBOOST_EVENT_CALL_START_ACK": \
(id==SIGBOOST_EVENT_CALL_START_NACK)?"SIGBOOST_EVENT_CALL_START_NACK": \
(id==SIGBOOST_EVENT_CALL_ANSWERED)?"SIGBOOST_EVENT_CALL_ANSWERED": \
(id==SIGBOOST_EVENT_CALL_STOPPED)?"SIGBOOST_EVENT_CALL_STOPPED": \
(id==SIGBOOST_EVENT_CALL_STOPPED_ACK)?"SIGBOOST_EVENT_CALL_STOPPED_ACK": \
(id==SIGBOOST_EVENT_SYSTEM_RESTART)?"SIGBOOST_EVENT_SYSTEM_RESTART": \
(id==SIGBOOST_EVENT_SYSTEM_RESTART_ACK)?"SIGBOOST_EVENT_SYSTEM_RESTART_ACK": \
(id==SIGBOOST_EVENT_CALL_RELEASED)?"SIGBOOST_EVENT_CALL_RELEASED": \
(id==SIGBOOST_EVENT_CALL_PROGRESS)?"SIGBOOST_EVENT_CALL_PROGRESS": \
(id==SIGBOOST_EVENT_HEARTBEAT)?"SIGBOOST_EVENT_HEARTBEAT": \
(id==SIGBOOST_EVENT_INSERT_CHECK_LOOP)?"SIGBOOST_EVENT_INSERT_CHECK_LOOP": \
(id==SIGBOOST_EVENT_REMOVE_CHECK_LOOP)?"SIGBOOST_EVENT_REMOVE_CHECK_LOOP": \
(id==SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE)?"SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE": \
(id==SIGBOOST_EVENT_DIGIT_IN)?"SIGBOOST_EVENT_DIGIT_IN": "Unknown"
enum e_sigboost_release_cause_values
{
SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,

View File

@ -2622,10 +2622,12 @@ SWITCH_STANDARD_API(session_audio_function)
#define BREAK_SYNTAX "<uuid> [all]"
SWITCH_STANDARD_API(break_function)
{
switch_core_session_t *psession = NULL;
switch_core_session_t *psession = NULL, *qsession = NULL;
char *mycmd = NULL, *flag;
switch_channel_t *channel = NULL;
switch_channel_t *channel = NULL, *qchannel = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
int all = 0;
int both = 0;
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", BREAK_SYNTAX);
@ -2644,22 +2646,58 @@ SWITCH_STANDARD_API(break_function)
goto done;
}
if (flag && !strcasecmp(flag, "all")) {
switch_core_session_flush_private_events(psession);
if (flag) {
if (strstr(flag, "all")) {
all++;
}
if (strstr(flag, "both")) {
both++;
}
}
channel = switch_core_session_get_channel(psession);
if (both) {
const char *quuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
if (quuid) {
qsession = switch_core_session_locate(quuid);
qchannel = switch_core_session_get_channel(qsession);
}
}
if (all) {
switch_core_session_flush_private_events(psession);
if (qsession) {
switch_core_session_flush_private_events(qsession);
}
}
if (switch_channel_test_flag(channel, CF_BROADCAST)) {
switch_channel_stop_broadcast(channel);
} else {
switch_channel_set_flag(channel, CF_BREAK);
}
if (qchannel) {
if (switch_channel_test_flag(qchannel, CF_BROADCAST)) {
switch_channel_stop_broadcast(qchannel);
} else {
switch_channel_set_flag(qchannel, CF_BREAK);
}
}
done:
if (psession) {
switch_core_session_rwunlock(psession);
}
if (qsession) {
switch_core_session_rwunlock(qsession);
}
switch_safe_free(mycmd);
return status;
@ -4164,6 +4202,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "user_data", "find user data", user_data_function, "<user>@<domain> [var|param|attr] <name>");
SWITCH_ADD_API(commands_api_interface, "user_exists", "find a user", user_exists_function, "<key> <user> <domain>");
SWITCH_ADD_API(commands_api_interface, "uuid_audio", "uuid_audio", session_audio_function, AUDIO_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_break", "Break", break_function, BREAK_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_bridge", "uuid_bridge", uuid_bridge_function, "");
SWITCH_ADD_API(commands_api_interface, "uuid_broadcast", "broadcast", uuid_broadcast_function, BROADCAST_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_chat", "Send a chat message", uuid_chat, UUID_CHAT_SYNTAX);
@ -4261,6 +4300,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
switch_console_set_complete("add uuid_audio ::console::list_uuid start write mute");
switch_console_set_complete("add uuid_audio ::console::list_uuid start write level");
switch_console_set_complete("add uuid_audio ::console::list_uuid stop");
switch_console_set_complete("add uuid_break ::console::list_uuid all");
switch_console_set_complete("add uuid_break ::console::list_uuid both");
switch_console_set_complete("add uuid_bridge ::console::list_uuid ::console::list_uuid");
switch_console_set_complete("add uuid_broadcast ::console::list_uuid");
switch_console_set_complete("add uuid_chat ::console::list_uuid");

View File

@ -261,6 +261,7 @@ SWITCH_STANDARD_APP(valet_parking_function)
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "hold");
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
@ -286,6 +287,14 @@ SWITCH_STANDARD_APP(valet_parking_function)
switch_mutex_lock(lot->mutex);
switch_core_hash_delete(lot->hash, ext);
switch_mutex_unlock(lot->mutex);
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VALET_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Lot-Name", lot_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Valet-Extension", ext);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "exit");
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage: %s\n", VALET_APP_SYNTAX);
}

View File

@ -3353,7 +3353,7 @@ SWITCH_STANDARD_API(prefs_api_function)
stream->write_function(stream, "-ERR No such profile\n");
goto done;
}
if (!(profile = get_profile("default"))) {
if (!profile && !(profile = get_profile("default"))) {
stream->write_function(stream, "-ERR profile 'default' doesn't exist\n");
goto done;
}

View File

@ -71,10 +71,10 @@ static switch_mutex_t *g_sessions_lock = NULL;
unsigned long long g_next_session_id = 0;
/* hash of sessions (I think a linked list suits better here, but FS does not have the data type) */
switch_hash_t *g_sessions_hash = NULL;
static switch_hash_t *g_sessions_hash = NULL;
/* global memory pool provided by FS */
switch_memory_pool_t *g_pool = NULL;
static switch_memory_pool_t *g_pool = NULL;
typedef struct vocallo_codec_s {
int codec_id; /* vocallo codec ID */

View File

@ -651,7 +651,7 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN
skinny_line_set_state(listener, line_instance, call_id, SKINNY_ON_HOOK);
send_select_soft_keys(listener, line_instance, call_id, SKINNY_KEY_SET_ON_HOOK, 0xffff);
/* TODO: DefineTimeDate */
send_define_current_time_date(listener);
send_set_speaker_mode(listener, SKINNY_SPEAKER_OFF);
send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, 0, call_id);
}

View File

@ -584,8 +584,12 @@ int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char
&& (line_instance == helper->line_instance)) {/* the calling line */
/* nothing */
} else {
/* TODO: capture and check what should happen here*/
skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY);
send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON);
skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY);
send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, 10, 0xffff);
send_display_prompt_status(listener, 0, "\200\037",
line_instance, helper->tech_pvt->call_id);
skinny_send_call_info(helper->tech_pvt->session, listener, line_instance);
}
}
return 0;
@ -604,21 +608,24 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list
tech_pvt = switch_core_session_get_private(session);
if (!dest) {
if (backspace) { /* backspace */
*tech_pvt->caller_profile->destination_number++ = '\0';
if (strlen(tech_pvt->caller_profile->destination_number) == 0) {/* no digit yet */
send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id);
}
if (append_dest != '\0' && !backspace) {/* append digit */
if (backspace) { /* backspace */
tech_pvt->caller_profile->destination_number[strlen(tech_pvt->caller_profile->destination_number)-1] = '\0';
if (strlen(tech_pvt->caller_profile->destination_number) == 0) {
send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff);
}
send_back_space_request(listener, line_instance, tech_pvt->call_id);
}
if (append_dest != '\0') {/* append digit */
tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool,
"%s%c", tech_pvt->caller_profile->destination_number, append_dest);
}
if (strlen(tech_pvt->caller_profile->destination_number) == 0) {/* no digit yet */
send_start_tone(listener, SKINNY_TONE_DIALTONE, 0, line_instance, tech_pvt->call_id);
if(backspace) {
send_select_soft_keys(listener, line_instance, tech_pvt->call_id, SKINNY_KEY_SET_OFF_HOOK, 0xffff);
/* TODO: How to clear the screen? */
}
} else if (strlen(tech_pvt->caller_profile->destination_number) == 1) {/* first digit */
send_stop_tone(listener, line_instance, tech_pvt->call_id);
if (strlen(tech_pvt->caller_profile->destination_number) == 1) {/* first digit */
if(!backspace) {
send_stop_tone(listener, line_instance, tech_pvt->call_id);
}
send_select_soft_keys(listener, line_instance, tech_pvt->call_id,
SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT, 0xffff);
}
@ -1476,6 +1483,20 @@ switch_status_t send_activate_call_plane(listener_t *listener,
return skinny_send_reply(listener, message);
}
switch_status_t send_back_space_request(listener_t *listener,
uint32_t line_instance,
uint32_t call_id)
{
skinny_message_t *message;
message = switch_core_alloc(listener->pool, 12+sizeof(message->data.back_space_req));
message->type = BACK_SPACE_REQ_MESSAGE;
message->length = 4 + sizeof(message->data.back_space_req);
message->data.back_space_req.line_instance = line_instance;
message->data.back_space_req.call_id = call_id;
return skinny_send_reply(listener, message);
}
switch_status_t send_dialed_number(listener_t *listener,
char called_party[24],
uint32_t line_instance,
@ -2202,6 +2223,7 @@ switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_mess
switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
struct speed_dial_stat_res_message *button = NULL;
uint32_t line_instance = 0;
uint32_t call_id = 0;
@ -2218,10 +2240,6 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess
skinny_create_ingoing_session(listener, &line_instance, &session);
skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0);
break;
case SKINNY_BUTTON_VOICEMAIL:
skinny_create_ingoing_session(listener, &line_instance, &session);
skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0);
break;
case SKINNY_BUTTON_SPEED_DIAL:
skinny_speed_dial_get(listener, request->data.stimulus.instance, &button);
if(strlen(button->line) > 0) {
@ -2229,6 +2247,17 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess
skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0);
}
break;
case SKINNY_BUTTON_HOLD:
session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id);
if(session) {
status = skinny_session_hold_line(session, listener, line_instance);
}
break;
case SKINNY_BUTTON_VOICEMAIL:
skinny_create_ingoing_session(listener, &line_instance, &session);
skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0);
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type);
}
@ -2237,7 +2266,7 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess
switch_core_session_rwunlock(session);
}
return SWITCH_STATUS_SUCCESS;
return status;
}
switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request)
@ -2442,55 +2471,52 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
return SWITCH_STATUS_FALSE;
}
switch(request->type) {
case ALARM_MESSAGE:
return skinny_handle_alarm(listener, request);
/* registering phase */
case KEEP_ALIVE_MESSAGE:
return skinny_handle_keep_alive_message(listener, request);
case REGISTER_MESSAGE:
return skinny_handle_register(listener, request);
case HEADSET_STATUS_MESSAGE:
return skinny_headset_status_message(listener, request);
case CONFIG_STAT_REQ_MESSAGE:
return skinny_handle_config_stat_request(listener, request);
case CAPABILITIES_RES_MESSAGE:
return skinny_handle_capabilities_response(listener, request);
case PORT_MESSAGE:
return skinny_handle_port_message(listener, request);
case BUTTON_TEMPLATE_REQ_MESSAGE:
return skinny_handle_button_template_request(listener, request);
case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
return skinny_handle_soft_key_template_request(listener, request);
case SOFT_KEY_SET_REQ_MESSAGE:
return skinny_handle_soft_key_set_request(listener, request);
case LINE_STAT_REQ_MESSAGE:
return skinny_handle_line_stat_request(listener, request);
case KEYPAD_BUTTON_MESSAGE:
return skinny_handle_keypad_button_message(listener, request);
case STIMULUS_MESSAGE:
return skinny_handle_stimulus_message(listener, request);
case OFF_HOOK_MESSAGE:
return skinny_handle_off_hook_message(listener, request);
case ON_HOOK_MESSAGE:
return skinny_handle_on_hook_message(listener, request);
case SPEED_DIAL_STAT_REQ_MESSAGE:
return skinny_handle_speed_dial_stat_request(listener, request);
case LINE_STAT_REQ_MESSAGE:
return skinny_handle_line_stat_request(listener, request);
case CONFIG_STAT_REQ_MESSAGE:
return skinny_handle_config_stat_request(listener, request);
case TIME_DATE_REQ_MESSAGE:
return skinny_handle_time_date_request(listener, request);
case BUTTON_TEMPLATE_REQ_MESSAGE:
return skinny_handle_button_template_request(listener, request);
case CAPABILITIES_RES_MESSAGE:
return skinny_handle_capabilities_response(listener, request);
case ALARM_MESSAGE:
return skinny_handle_alarm(listener, request);
case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
return skinny_handle_open_receive_channel_ack_message(listener, request);
case SOFT_KEY_SET_REQ_MESSAGE:
return skinny_handle_soft_key_set_request(listener, request);
case SOFT_KEY_EVENT_MESSAGE:
return skinny_handle_soft_key_event_message(listener, request);
case UNREGISTER_MESSAGE:
return skinny_handle_unregister(listener, request);
case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
return skinny_handle_soft_key_template_request(listener, request);
case SERVICE_URL_STAT_REQ_MESSAGE:
return skinny_handle_service_url_stat_request(listener, request);
case FEATURE_STAT_REQ_MESSAGE:
return skinny_handle_feature_stat_request(listener, request);
case HEADSET_STATUS_MESSAGE:
return skinny_headset_status_message(listener, request);
case REGISTER_AVAILABLE_LINES_MESSAGE:
return skinny_handle_register_available_lines_message(listener, request);
case TIME_DATE_REQ_MESSAGE:
return skinny_handle_time_date_request(listener, request);
/* live phase */
case KEEP_ALIVE_MESSAGE:
return skinny_handle_keep_alive_message(listener, request);
case SOFT_KEY_EVENT_MESSAGE:
return skinny_handle_soft_key_event_message(listener, request);
case OFF_HOOK_MESSAGE:
return skinny_handle_off_hook_message(listener, request);
case STIMULUS_MESSAGE:
return skinny_handle_stimulus_message(listener, request);
case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
return skinny_handle_open_receive_channel_ack_message(listener, request);
case KEYPAD_BUTTON_MESSAGE:
return skinny_handle_keypad_button_message(listener, request);
case ON_HOOK_MESSAGE:
return skinny_handle_on_hook_message(listener, request);
/* end phase */
case UNREGISTER_MESSAGE:
return skinny_handle_unregister(listener, request);
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Unhandled request %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length);

View File

@ -457,6 +457,13 @@ struct unregister_ack_message {
uint32_t unregister_status;
};
/* BackSpaceReqMessage */
#define BACK_SPACE_REQ_MESSAGE 0x0119
struct back_space_req_message {
uint32_t line_instance;
uint32_t call_id;
};
/* DialedNumberMessage */
#define DIALED_NUMBER_MESSAGE 0x011D
struct dialed_number_message {
@ -540,6 +547,7 @@ union skinny_data {
struct clear_prompt_status_message clear_prompt_status;
struct activate_call_plane_message activate_call_plane;
struct unregister_ack_message unregister_ack;
struct back_space_req_message back_space_req;
struct dialed_number_message dialed_number;
struct feature_stat_res_message feature_res;
struct display_pri_notify_message display_pri_notify;
@ -748,6 +756,9 @@ switch_status_t send_clear_prompt_status(listener_t *listener,
uint32_t call_id);
switch_status_t send_activate_call_plane(listener_t *listener,
uint32_t line_instance);
switch_status_t send_back_space_request(listener_t *listener,
uint32_t line_instance,
uint32_t call_id);
switch_status_t send_dialed_number(listener_t *listener,
char called_party[24],
uint32_t line_instance,

View File

@ -86,6 +86,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
{"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE},
{"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE},
{"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE},
{"BackSpaceReqMessage", BACK_SPACE_REQ_MESSAGE},
{"DialedNumberMessage", DIALED_NUMBER_MESSAGE},
{"FeatureResMessage", FEATURE_STAT_RES_MESSAGE},
{"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE},
@ -117,6 +118,7 @@ struct skinny_table SKINNY_BUTTONS[] = {
{"Unknown", SKINNY_BUTTON_UNKNOWN},
{"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL},
{"SpeedDial", SKINNY_BUTTON_SPEED_DIAL},
{"Hold", SKINNY_BUTTON_HOLD},
{"Line", SKINNY_BUTTON_LINE},
{"Voicemail", SKINNY_BUTTON_VOICEMAIL},
{"Privacy", SKINNY_BUTTON_PRIVACY},

View File

@ -84,7 +84,7 @@ uint32_t func(const char *str)\
}
struct skinny_table SKINNY_MESSAGE_TYPES[56];
struct skinny_table SKINNY_MESSAGE_TYPES[57];
const char *skinny_message_type2str(uint32_t id);
uint32_t skinny_str2message_type(const char *str);
#define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)
@ -151,13 +151,14 @@ enum skinny_button_definition {
SKINNY_BUTTON_UNKNOWN = 0x00,
SKINNY_BUTTON_LAST_NUMBER_REDIAL = 0x01,
SKINNY_BUTTON_SPEED_DIAL = 0x02,
SKINNY_BUTTON_HOLD = 0x03,
SKINNY_BUTTON_LINE = 0x09,
SKINNY_BUTTON_VOICEMAIL = 0x0F,
SKINNY_BUTTON_PRIVACY = 0x13,
SKINNY_BUTTON_SERVICE_URL = 0x14,
SKINNY_BUTTON_UNDEFINED = 0xFF,
};
struct skinny_table SKINNY_BUTTONS[9];
struct skinny_table SKINNY_BUTTONS[10];
const char *skinny_button2str(uint32_t id);
uint32_t skinny_str2button(const char *str);
#define SKINNY_PUSH_STIMULI SKINNY_DECLARE_PUSH_MATCH(SKINNY_BUTTONS)

View File

@ -614,12 +614,12 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
#endif
if (uuid) {
sql = switch_mprintf("update sip_dialogs set call_info_state='%q' where hostname='%q' and uuid='%q'",
call_info_state, mod_sofia_globals.hostname, uuid);
sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' where hostname='%q' and uuid='%q'",
call_info, call_info_state, mod_sofia_globals.hostname, uuid);
} else {
sql = switch_mprintf("update sip_dialogs set call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' "
sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' "
"and sip_dialogs.sip_from_host='%q' and call_info='%q'",
call_info_state, mod_sofia_globals.hostname, euser, host, call_info);
call_info, call_info_state, mod_sofia_globals.hostname, euser, host, call_info);
}