Merge branch 'master' into netborder

Conflicts:
	libs/freetdm/src/ftdm_io.c
	libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
	libs/freetdm/src/include/freetdm.h
This commit is contained in:
Moises Silva committed 2011-01-05 13:11:37 -05:00
commit eb84fc772f
224 files changed
+13786 -6134

No files matched your search

+23
View File
@@ -30,6 +30,12 @@
* 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>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
#include "private/ftdm_core.h"
@@ -144,3 +150,20 @@ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number)
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target)
{
uint8_t val;
ftdm_status_t status = FTDM_SUCCESS;
val = ftdm_str2ftdm_calling_party_category(string);
if (val == FTDM_CPC_INVALID) {
ftdm_log(FTDM_LOG_WARNING, "Invalid category string (%s)\n", string);
val = FTDM_CPC_ORDINARY;
status = FTDM_FAIL;
}
*target = val;
return status;
}
+491 -517
View File
File diff suppressed because it is too large. Load diff
-692
View File
@@ -1,692 +0,0 @@
/*
* ftdm_m3ua.c
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic *
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
#include "freetdm.h"
#include "m3ua_client.h"
#include "ftdm_m3ua.h"
#define MAX_REQ_ID MAX_PENDING_CALLS
typedef uint16_t m3ua_request_id_t;
typedef enum {
BST_FREE,
BST_WAITING,
BST_READY,
BST_FAIL
} m3ua_request_status_t;
typedef struct {
m3ua_request_status_t status;
m3uac_event_t event;
ftdm_span_t *span;
ftdm_channel_t *ftdmchan;
} m3ua_request_t;
struct general_config {
uint32_t region;
};
typedef struct general_config general_config_t;
struct m3ua_channel_profile {
char name[80];
int cust_span;
unsigned char opc[3];
unsigned char dpc[3];
int local_ip[4];
int local_port;
int remote_ip[4];
int remote_port;
int m3ua_mode;
};
typedef struct m3ua_channel_profile m3ua_channel_profile_t;
static struct {
ftdm_hash_t *profile_hash;
general_config_t general_config;
} globals;
struct m3ua_span_data {
uint32_t boardno;
uint32_t flags;
};
typedef struct m3ua_span_data m3ua_span_data_t;
struct m3ua_chan_data {
ftdm_buffer_t *digit_buffer;
ftdm_mutex_t *digit_mutex;
ftdm_size_t dtmf_len;
uint32_t flags;
uint32_t hdlc_bytes;
};
typedef struct m3ua_chan_data m3ua_chan_data_t;
static ftdm_mutex_t *request_mutex = NULL;
static ftdm_mutex_t *signal_mutex = NULL;
static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
static void release_request_id(m3ua_request_id_t r)
{
ftdm_mutex_lock(request_mutex);
req_map[r] = 0;
ftdm_mutex_unlock(request_mutex);
}
/*static m3ua_request_id_t next_request_id(void)
{
m3ua_request_id_t r = 0;
int ok = 0;
while(!ok) {
ftdm_mutex_lock(request_mutex);
for (r = 1; r <= MAX_REQ_ID; r++) {
if (!req_map[r]) {
ok = 1;
req_map[r] = 1;
break;
}
}
ftdm_mutex_unlock(request_mutex);
if (!ok) {
ftdm_sleep(5);
}
}
return r;
}
*/
static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
{
m3ua_data_t *m3ua_data = ftdmchan->span->signal_data;
m3uac_connection_t *mcon = &m3ua_data->mcon;
ftdm_sigmsg_t sig;
ftdm_status_t status;
ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
memset(&sig, 0, sizeof(sig));
sig.chan_id = ftdmchan->chan_id;
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
if (ftdmchan->extra_id) {
release_request_id((m3ua_request_id_t)ftdmchan->extra_id);
ftdmchan->extra_id = 0;
}
ftdm_channel_close(&ftdmchan);
}
break;
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_PROGRESS:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
} else {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_ACK,
0);
}
}
break;
case FTDM_CHANNEL_STATE_RING:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_START;
if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
}
}
break;
case FTDM_CHANNEL_STATE_RESTART:
{
if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP && ftdmchan->last_state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
}
break;
case FTDM_CHANNEL_STATE_UP:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_UP;
if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
} else {
if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_ACK,
0);
}
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_ANSWERED,
0);
}
}
break;
case FTDM_CHANNEL_STATE_DIALING:
{
}
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
{
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
break;
case FTDM_CHANNEL_STATE_HANGUP:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA)) {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_STOPPED,
ftdmchan->caller_data.hangup_cause);
} else {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_NACK,
ftdmchan->caller_data.hangup_cause);
}
}
break;
case FTDM_CHANNEL_STATE_CANCEL:
{
sig.event_id = FTDM_SIGEVENT_STOP;
status = m3ua_data->signal_cb(&sig);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_NACK_ACK,
0);
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
sig.event_id = FTDM_SIGEVENT_STOP;
status = m3ua_data->signal_cb(&sig);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_STOPPED_ACK,
0);
}
break;
default:
break;
}
}
static __inline__ void check_state(ftdm_span_t *span)
{
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
if (ftdm_test_flag((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag_locked((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
state_advance(&span->channels[j]);
ftdm_channel_complete_state(&span->channels[j]);
}
}
}
}
static int parse_ss7_event(ftdm_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event)
{
ftdm_mutex_lock(signal_mutex);
if (!ftdm_running()) {
ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
goto end;
}
if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED) &&
event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
ftdm_log(FTDM_LOG_WARNING,
"INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
m3uac_event_id_name(event->event_id),
event->event_id,
event->span+1,
event->chan+1,
event->release_cause,
event->call_setup_id,
event->fseqno,
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
);
goto end;
}
ftdm_log(FTDM_LOG_DEBUG,
"RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
m3uac_event_id_name(event->event_id),
event->event_id,
event->span+1,
event->chan+1,
event->release_cause,
event->call_setup_id,
event->fseqno,
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
);
switch(event->event_id) {
case SIGBOOST_EVENT_CALL_START:
//handle_call_start(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_STOPPED:
//handle_call_stop(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_START_ACK:
//handle_call_start_ack(mcon, event);
break;
case SIGBOOST_EVENT_CALL_START_NACK:
//handle_call_start_nack(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_ANSWERED:
//handle_call_answer(span, mcon, event);
break;
case SIGBOOST_EVENT_HEARTBEAT:
//handle_heartbeat(mcon, event);
break;
case SIGBOOST_EVENT_CALL_STOPPED_ACK:
case SIGBOOST_EVENT_CALL_START_NACK_ACK:
//handle_call_done(span, mcon, event);
break;
case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
//handle_call_loop_start(event);
break;
case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
//handle_call_stop(event);
break;
case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
//handle_restart_ack(mcon, span, event);
break;
case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
//handle_gap_abate(event);
break;
default:
ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id));
break;
}
end:
ftdm_mutex_unlock(signal_mutex);
return 0;
}
static FIO_CONFIGURE_FUNCTION(m3ua_configure)
{
m3ua_channel_profile_t *profile = NULL;
int ok = 1;
if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
profile = ftdm_malloc(sizeof(*profile));
memset(profile, 0, sizeof(*profile));
ftdm_set_string(profile->name, category);
hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
}
// ftdm_set_string(m3ua_data->mcon. cfg.local_ip, local_ip);
if (!strcasecmp(var, "local_sctp_port")) {
profile->local_port = 30000 ;
profile->remote_port = 30000;
profile->cust_span++;
}
ok = 1;
if (ok) {
ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
} else {
ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
}
return FTDM_SUCCESS;
}
static FIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span)
{
return FTDM_FAIL;
}
static FIO_OPEN_FUNCTION(m3ua_open)
{
return FTDM_FAIL;
}
static FIO_CLOSE_FUNCTION(m3ua_close)
{
return FTDM_FAIL;
}
/*static FIO_SET_INTERVAL_FUNCTION(m3ua_set_interval)
{
return 0;
}*/
static FIO_WAIT_FUNCTION(m3ua_wait)
{
return FTDM_FAIL;
}
static FIO_READ_FUNCTION(m3ua_read)
{
return FTDM_FAIL;
}
static FIO_WRITE_FUNCTION(m3ua_write)
{
return FTDM_FAIL;
}
static FIO_COMMAND_FUNCTION(m3ua_command)
{
return FTDM_FAIL;
}
static FIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event)
{
return FTDM_FAIL;
}
static FIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event)
{
return FTDM_FAIL;
}
static FIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy)
{
m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->io_data;
if (span_data) {
ftdm_safe_free(span_data);
}
return FTDM_SUCCESS;
}
static FIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy)
{
m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) ftdmchan->io_data;
m3ua_span_data_t *span_data = (m3ua_span_data_t *) ftdmchan->span->io_data;
if (!chan_data) {
return FTDM_FAIL;
}
ftdm_mutex_destroy(&chan_data->digit_mutex);
ftdm_buffer_destroy(&chan_data->digit_buffer);
ftdm_safe_free(chan_data);
if (span_data) {
ftdm_safe_free(span_data);
}
return FTDM_SUCCESS;
}
static FIO_GET_ALARMS_FUNCTION(m3ua_get_alarms)
{
return FTDM_FAIL;
}
static ftdm_io_interface_t m3ua_interface;
ftdm_status_t m3ua_init(ftdm_io_interface_t **zint)
{
assert(zint != NULL);
memset(&m3ua_interface, 0, sizeof(m3ua_interface));
m3ua_interface.name = "m3ua";
m3ua_interface.configure = m3ua_configure;
m3ua_interface.configure_span = m3ua_configure_span;
m3ua_interface.open = m3ua_open;
m3ua_interface.close = m3ua_close;
m3ua_interface.wait = m3ua_wait;
m3ua_interface.read = m3ua_read;
m3ua_interface.write = m3ua_write;
m3ua_interface.command = m3ua_command;
m3ua_interface.poll_event = m3ua_poll_event;
m3ua_interface.next_event = m3ua_next_event;
m3ua_interface.channel_destroy = m3ua_channel_destroy;
m3ua_interface.span_destroy = m3ua_span_destroy;
m3ua_interface.get_alarms = m3ua_get_alarms;
*zint = &m3ua_interface;
return FTDM_FAIL;
}
ftdm_status_t m3ua_destroy(void)
{
return FTDM_FAIL;
}
static void *m3ua_run(ftdm_thread_t *me, void *obj)
{
ftdm_span_t *span = (ftdm_span_t *) obj;
m3ua_data_t *m3ua_data = span->signal_data;
m3uac_connection_t *mcon, *pcon;
uint32_t ms = 10, too_long = 60000;
m3ua_data->pcon = m3ua_data->mcon;
if (m3uac_connection_open(&m3ua_data->mcon,
m3ua_data->mcon.cfg.local_ip,
m3ua_data->mcon.cfg.local_port,
m3ua_data->mcon.cfg.remote_ip,
m3ua_data->mcon.cfg.remote_port) < 0) {
ftdm_log(FTDM_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno));
goto end;
}
if (m3uac_connection_open(&m3ua_data->pcon,
m3ua_data->pcon.cfg.local_ip,
++m3ua_data->pcon.cfg.local_port,
m3ua_data->pcon.cfg.remote_ip,
m3ua_data->pcon.cfg.remote_port) < 0) {
ftdm_log(FTDM_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno));
goto end;
}
mcon = &m3ua_data->mcon;
pcon = &m3ua_data->pcon;
top:
//init_outgoing_array();
m3uac_exec_command(mcon,
0,
0,
-1,
SIGBOOST_EVENT_SYSTEM_RESTART,
0);
while (ftdm_test_flag(m3ua_data, FTDM_M3UA_RUNNING)) {
fd_set rfds, efds;
struct timeval tv = { 0, ms * 1000 };
int max, activity, i = 0;
m3uac_event_t *event = NULL;
if (!ftdm_running()) {
m3uac_exec_command(mcon,
0,
0,
-1,
SIGBOOST_EVENT_SYSTEM_RESTART,
0);
break;
}
FD_ZERO(&rfds);
FD_ZERO(&efds);
FD_SET(mcon->socket, &rfds);
FD_SET(mcon->socket, &efds);
FD_SET(pcon->socket, &rfds);
FD_SET(pcon->socket, &efds);
max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
goto error;
}
if (activity) {
if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
goto error;
}
if (FD_ISSET(pcon->socket, &rfds)) {
if ((event = m3uac_connection_readp(pcon, i))) {
parse_ss7_event(span, mcon, event);
} else goto top;
}
if (FD_ISSET(mcon->socket, &rfds)) {
if ((event = m3uac_connection_read(mcon, i))) {
parse_ss7_event(span, mcon, event);
} else goto top;
}
}
check_state(span);
mcon->hb_elapsed += ms;
if (mcon->hb_elapsed >= too_long && (mcon->up || !ftdm_test_flag(span, FTDM_SPAN_SUSPENDED))) {
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
mcon->up = 0;
ftdm_log(FTDM_LOG_CRIT, "Lost Heartbeat!\n");
}
}
goto end;
error:
ftdm_log(FTDM_LOG_CRIT, "Socket Error!\n");
end:
m3uac_connection_close(&m3ua_data->mcon);
m3uac_connection_close(&m3ua_data->pcon);
ftdm_clear_flag(m3ua_data, FTDM_M3UA_RUNNING);
ftdm_log(FTDM_LOG_DEBUG, "M3UA thread ended.\n");
return NULL;
}
ftdm_status_t m3ua_start(ftdm_span_t *span)
{
m3ua_data_t *m3ua_data = span->signal_data;
ftdm_set_flag(m3ua_data, FTDM_M3UA_RUNNING);
return ftdm_thread_create_detached(m3ua_run, span);
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
*/
+486
View File
@@ -0,0 +1,486 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
#include "private/ftdm_core.h"
FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID)
FTDM_ENUM_NAMES(CHANNEL_STATE_STATUS_NAMES, CHANNEL_STATE_STATUS_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t, CHANNEL_STATE_STATUS_NAMES, FTDM_STATE_STATUS_INVALID)
/* This function is only needed for boost and we should get rid of it at the next refactoring */
FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *fchan)
{
ftdm_channel_lock(fchan);
if (fchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, fchan, fchan->init_state, 1);
fchan->init_state = FTDM_CHANNEL_STATE_DOWN;
}
ftdm_channel_unlock(fchan);
return FTDM_SUCCESS;
}
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_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_UP) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);
} else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
}
/* if there is a pending ack for an indication
* MAINTENANCE WARNING: we're assuming an indication performed
* via state change will involve a single state change
*/
if (ftdm_test_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING)) {
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_set_state(const char *file, const char *func, int line,
ftdm_channel_t *fchan, ftdm_channel_state_t state)
{
if (fchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
/* the current state is not completed, setting a new state from a signaling module
when the current state is not completed is equivalent to implicitly acknowledging
the current state */
_ftdm_channel_complete_state(file, func, line, fchan);
}
return ftdm_channel_set_state(file, func, line, fchan, state, 0);
}
static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map)
{
int x = 0, ok = 0;
ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) {
int i = 0, proceed = 0;
if (!state_map->nodes[x].type) {
break;
}
if (state_map->nodes[x].direction != direction) {
continue;
}
if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) {
proceed = 1;
} else {
for(i = 0; i < FTDM_MAP_MAX; i++) {
if (state_map->nodes[x].check_states[i] == ftdmchan->state) {
proceed = 1;
break;
}
}
}
if (!proceed) {
continue;
}
for(i = 0; i < FTDM_MAP_MAX; i++) {
ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
if (state_map->nodes[x].states[i] == FTDM_END) {
break;
}
if (state_map->nodes[x].states[i] == state) {
ok = !ok;
goto end;
}
}
}
end:
return ok;
}
/* this function MUST be called with the channel lock held. If waitrq == 1, the channel will be unlocked/locked (never call it with waitrq == 1 with an lock recursivity > 1) */
#define DEFAULT_WAIT_TIME 1000
FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq)
{
ftdm_status_t status;
int ok = 1;
int waitms = DEFAULT_WAIT_TIME;
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n",
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return FTDM_FAIL;
}
if (ftdmchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR,
"Ignored state change request from %s to %s, the previous state change has not been processed yet (status = %s)\n",
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state),
ftdm_state_status2str(ftdmchan->state_status));
return FTDM_FAIL;
}
if (ftdmchan->state == state) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return FTDM_FAIL;
}
if (!ftdmchan->state_completed_interrupt) {
status = ftdm_interrupt_create(&ftdmchan->state_completed_interrupt, FTDM_INVALID_SOCKET);
if (status != FTDM_SUCCESS) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_CRIT,
"Failed to create state change interrupt when moving from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return status;
}
}
if (ftdmchan->span->state_map) {
ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
goto end;
}
/* basic core state validation (by-passed if the signaling module provides a state_map) */
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_HANGUP:
case FTDM_CHANNEL_STATE_TERMINATING:
{
ok = 0;
switch(state) {
case FTDM_CHANNEL_STATE_DOWN:
case FTDM_CHANNEL_STATE_BUSY:
case FTDM_CHANNEL_STATE_RESTART:
ok = 1;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_UP:
{
ok = 1;
switch(state) {
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_RING:
ok = 0;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_DOWN:
{
ok = 0;
switch(state) {
case FTDM_CHANNEL_STATE_DIALTONE:
case FTDM_CHANNEL_STATE_COLLECT:
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_IDLE:
case FTDM_CHANNEL_STATE_GET_CALLERID:
case FTDM_CHANNEL_STATE_GENRING:
ok = 1;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_BUSY:
{
switch(state) {
case FTDM_CHANNEL_STATE_UP:
ok = 0;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_RING:
{
switch(state) {
case FTDM_CHANNEL_STATE_UP:
ok = 1;
break;
default:
break;
}
}
break;
default:
break;
}
end:
if (!ok) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
goto done;
}
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
ftdmchan->last_state = ftdmchan->state;
ftdmchan->state = state;
ftdmchan->state_status = FTDM_STATE_STATUS_NEW;
ftdmchan->history[ftdmchan->hindex].file = file;
ftdmchan->history[ftdmchan->hindex].func = func;
ftdmchan->history[ftdmchan->hindex].line = line;
ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state;
ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state;
ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms();
ftdmchan->history[ftdmchan->hindex].end_time = 0;
ftdmchan->hindex++;
if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) {
ftdmchan->hindex = 0;
}
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_mutex_lock(ftdmchan->span->mutex);
ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
if (ftdmchan->span->pendingchans) {
ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
}
ftdm_mutex_unlock(ftdmchan->span->mutex);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) {
/* the channel should not block waiting for state processing */
goto done;
}
if (!waitrq) {
/* no waiting was requested */
goto done;
}
/* let's wait for the state change to be completed by the signaling stack */
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
ftdm_mutex_unlock(ftdmchan->mutex);
status = ftdm_interrupt_wait(ftdmchan->state_completed_interrupt, waitms);
ftdm_mutex_lock(ftdmchan->mutex);
if (status != FTDM_SUCCESS) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
ftdm_log_chan_ex(ftdmchan, file, func, line,
FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not completed after aprox %dms\n",
ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
ok = 0;
goto done;
}
done:
return ok ? FTDM_SUCCESS : FTDM_FAIL;
}
FT_DECLARE(int) ftdm_channel_get_state(const ftdm_channel_t *ftdmchan)
{
int state;
ftdm_channel_lock(ftdmchan);
state = ftdmchan->state;
ftdm_channel_unlock(ftdmchan);
return state;
}
FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *ftdmchan)
{
const char *state;
ftdm_channel_lock(ftdmchan);
state = ftdm_channel_state2str(ftdmchan->state);
ftdm_channel_unlock(ftdmchan);
return state;
}
FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan)
{
int last_state;
ftdm_channel_lock(ftdmchan);
last_state = ftdmchan->last_state;
ftdm_channel_unlock(ftdmchan);
return last_state;
}
FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan)
{
const char *state;
ftdm_channel_lock(ftdmchan);
state = ftdm_channel_state2str(ftdmchan->last_state);
ftdm_channel_unlock(ftdmchan);
return state;
}
static void write_history_entry(const ftdm_channel_t *fchan, ftdm_stream_handle_t *stream, int i, ftdm_time_t *prevtime)
{
char func[255];
char line[255];
char states[255];
const char *filename = NULL;
snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state));
snprintf(func, sizeof(func), "[%s]", fchan->history[i].func);
filename = strrchr(fchan->history[i].file, *FTDM_PATH_SEPARATOR);
if (!filename) {
filename = fchan->history[i].file;
} else {
filename++;
}
if (!(*prevtime)) {
*prevtime = fchan->history[i].time;
}
snprintf(line, sizeof(func), "[%s:%d]", filename, fchan->history[i].line);
stream->write_function(stream, "%-30.30s %-30.30s %-30.30s %lums\n", states, func, line, (fchan->history[i].time - *prevtime));
*prevtime = fchan->history[i].time;
}
FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan)
{
uint8_t i = 0;
ftdm_time_t currtime = 0;
ftdm_time_t prevtime = 0;
ftdm_stream_handle_t stream = { 0 };
FTDM_STANDARD_STREAM(stream);
if (!fchan->history[0].file) {
stream.write_function(&stream, "-- No state history --\n");
return stream.data;
}
stream.write_function(&stream, "%-30.30s %-30.30s %-30.30s %s",
"-- States --", "-- Function --", "-- Location --", "-- Time Offset --\n");
for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) {
if (!fchan->history[i].file) {
break;
}
write_history_entry(fchan, &stream, i, &prevtime);
}
for (i = 0; i < fchan->hindex; i++) {
write_history_entry(fchan, &stream, i, &prevtime);
}
currtime = ftdm_current_time_in_ms();
stream.write_function(&stream, "\nTime since last state change: %lums\n", (currtime - prevtime));
return stream.data;
}
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;
}
FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
{
uint32_t j;
for(j = 1; j <= span->chan_count; j++) {
if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
return 0;
}
}
return 1;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
+10 -3
View File
@@ -56,7 +56,11 @@ struct ftdm_interrupt {
/* for generic interruption */
HANDLE event;
#else
/* for generic interruption */
/* In theory we could be using thread conditions for generic interruption,
* however, Linux does not have a primitive like Windows WaitForMultipleObjects
* to wait for both thread condition and file descriptors, therefore we decided
* to use a dummy pipe for generic interruption/condition logic
* */
int readfd;
int writefd;
#endif
@@ -243,6 +247,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex)
FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device)
{
ftdm_status_t status = FTDM_SUCCESS;
ftdm_interrupt_t *interrupt = NULL;
#ifndef WIN32
int fds[2];
@@ -253,7 +258,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt,
interrupt = ftdm_calloc(1, sizeof(*interrupt));
if (!interrupt) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n");
return FTDM_FAIL;
return FTDM_ENOMEM;
}
interrupt->device = device;
@@ -261,11 +266,13 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt,
interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!interrupt->event) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
status = FTDM_ENOMEM;
goto failed;
}
#else
if (pipe(fds)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
status = FTDM_FAIL;
goto failed;
}
interrupt->readfd = fds[0];
@@ -287,7 +294,7 @@ failed:
#endif
ftdm_safe_free(interrupt);
}
return FTDM_FAIL;
return status;
}
#define ONE_BILLION 1000000000
@@ -37,7 +37,9 @@
typedef enum {
FTDM_ANALOG_RUNNING = (1 << 0),
FTDM_ANALOG_CALLERID = (1 << 1)
FTDM_ANALOG_CALLERID = (1 << 1),
FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2),
FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3)
} ftdm_analog_flag_t;
#define FTDM_MAX_HOTLINE_STR 20
@@ -47,11 +49,13 @@ struct ftdm_analog_data {
uint32_t flags;
uint32_t max_dialstr;
uint32_t wait_dialtone_timeout;
uint32_t polarity_delay;
uint32_t digit_timeout;
char hotline[FTDM_MAX_HOTLINE_STR];
};
/* Analog flags to be set in the sflags (signaling flags) channel memeber */
#define AF_POLARITY_REVERSE (1 << 0)
static void *ftdm_analog_run(ftdm_thread_t *me, void *obj);
typedef struct ftdm_analog_data ftdm_analog_data_t;
@@ -96,6 +96,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
*status = FTDM_SIG_STATE_DOWN;
return FTDM_SUCCESS;
}
*status = FTDM_SIG_STATE_UP;
return FTDM_SUCCESS;
}
@@ -109,7 +113,25 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_get_span_sig_status)
{
*status = FTDM_SIG_STATE_UP;
ftdm_iterator_t *citer = NULL;
ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
return FTDM_FAIL;
}
/* if ALL channels are in alarm, report DOWN, UP otherwise. */
*status = FTDM_SIG_STATE_DOWN;
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
ftdm_channel_lock(fchan);
if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) {
*status = FTDM_SIG_STATE_UP;
ftdm_channel_unlock(fchan);
break;
}
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
}
@@ -162,6 +184,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
uint32_t digit_timeout = 10;
uint32_t wait_dialtone_timeout = 30000;
uint32_t max_dialstr = MAX_DTMF;
uint32_t polarity_delay = 600;
const char *var, *val;
int *intval;
uint32_t flags = FTDM_ANALOG_CALLERID;
@@ -214,6 +237,29 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
} else {
flags &= ~FTDM_ANALOG_CALLERID;
}
} else if (!strcasecmp(var, "answer_polarity_reverse")) {
if (!(val = va_arg(ap, char *))) {
break;
}
if (ftdm_true(val)) {
flags |= FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
} else {
flags &= ~FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
}
} else if (!strcasecmp(var, "hangup_polarity_reverse")) {
if (!(val = va_arg(ap, char *))) {
break;
}
if (ftdm_true(val)) {
flags |= FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
} else {
flags &= ~FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
}
} else if (!strcasecmp(var, "polarity_delay")) {
if (!(intval = va_arg(ap, int *))) {
break;
}
polarity_delay = *intval;
} else if (!strcasecmp(var, "callwaiting")) {
if (!(intval = va_arg(ap, int *))) {
break;
@@ -254,6 +300,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
analog_data->flags = flags;
analog_data->digit_timeout = digit_timeout;
analog_data->wait_dialtone_timeout = wait_dialtone_timeout;
analog_data->polarity_delay = polarity_delay;
analog_data->max_dialstr = max_dialstr;
span->signal_cb = sig_cb;
strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
@@ -377,6 +424,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data;
ftdm_channel_t *closed_chan;
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = analog_data->wait_dialtone_timeout;
uint32_t answer_on_polarity_counter = 0;
ftdm_sigmsg_t sig;
ftdm_status_t status;
@@ -448,7 +496,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
/* do not go up if we're waiting for polarity reversal */
if (ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
}
}
}
}
@@ -493,8 +546,10 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) {
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_UP)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
@@ -530,15 +585,37 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (done) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
}
}
case FTDM_CHANNEL_STATE_UP:
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
ftdm_sleep(interval);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA &&
ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Answering on polarity reverse\n");
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
answer_on_polarity_counter = state_counter;
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_UP
&& ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)){
/* if this polarity reverse is close to the answer polarity reverse, ignore it */
if (answer_on_polarity_counter
&& (state_counter - answer_on_polarity_counter) > analog_data->polarity_delay) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Hanging up on polarity reverse\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING,
"Not hanging up on polarity reverse, too close to Answer reverse\n");
}
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
} else {
ftdm_sleep(interval);
}
continue;
}
break;
@@ -551,7 +628,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
break;
}
} else {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
indicate = 0;
@@ -591,6 +667,19 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
sig.event_id = FTDM_SIGEVENT_UP;
}
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
ftdm_polarity_t polarity = FTDM_POLARITY_REVERSE;
if (ftdmchan->polarity == FTDM_POLARITY_FORWARD) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on answer\n");
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
} else {
/* the polarity may be already reversed if this is the second time we
* answer (ie, due to 2 calls being on the same line) */
}
}
ftdm_span_send_signal(ftdmchan->span, &sig);
continue;
}
@@ -615,6 +704,22 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
continue;
}
break;
case FTDM_CHANNEL_STATE_HANGUP:
/* this state is only used when the user hangup, if the device hang up (onhook) we currently
* go straight to DOWN. If we ever change this (as other signaling modules do) by using this
* state for both user and device hangup, we should check here for the type of hangup since
* some actions (polarity reverse) do not make sense if the device hung up */
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
ftdmchan->last_state == FTDM_CHANNEL_STATE_UP &&
ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
ftdm_polarity_t polarity = ftdmchan->polarity == FTDM_POLARITY_REVERSE
? FTDM_POLARITY_FORWARD : FTDM_POLARITY_REVERSE;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on hangup\n");
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
}
break;
case FTDM_CHANNEL_STATE_DOWN:
{
sig.event_id = FTDM_SIGEVENT_STOP;
@@ -717,7 +822,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
dtmf_offset = strlen(dtmf);
last_digit = elapsed;
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
sig.raw_data = dtmf;
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
collecting = 0;
}
@@ -823,6 +928,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
done:
closed_chan = ftdmchan;
ftdm_channel_lock(closed_chan);
if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
@@ -833,7 +941,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
closed_chan = ftdmchan;
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
ftdm_channel_close(&ftdmchan);
ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
@@ -851,8 +960,11 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
ftdm_log_chan(closed_chan, FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
ftdm_channel_unlock(closed_chan);
return NULL;
}
@@ -879,19 +991,32 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
ftdm_mutex_lock(event->channel->mutex);
locked++;
/* MAINTENANCE WARNING:
* 1. Be aware you are working on the locked channel
* 2. We should not be calling ftdm_span_send_signal or ftdm_set_state when there is already a channel thread running
* however, since this is old code I am not changing it now, but new code should adhere to that convention
* otherwise, we have possible races where we compete with the user for state changes, ie, the user requests
* a state change and then we process an event, the state change from the user is pending so our ftdm_set_state
* operation will fail. In cases where we win the race, our state change will be accepted but if a user requests
* a state change before the state change we requested here is processed by the channel thread, we'll end up
* rejecting the user request.
*
* See docs/locking.txt for further information about what guarantees should signaling modules provide when
* locking/unlocking a channel
* */
switch(event->enum_id) {
case FTDM_OOB_RING_START:
{
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
goto end;
}
if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) {
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
} else {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_RING);
}
event->channel->ring_count = 1;
ftdm_mutex_unlock(event->channel->mutex);
@@ -909,24 +1034,33 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
}
if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
if (event->channel->state == FTDM_CHANNEL_STATE_HANGUP &&
ftdm_test_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE)) {
/* we do not need to process HANGUP since the device also hangup already */
ftdm_channel_complete_state(event->channel);
}
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
}
if (event->channel->type == FTDM_CHAN_TYPE_FXS) {
/* we always return to forward when the device goes onhook */
ftdm_polarity_t forward_polarity = FTDM_POLARITY_FORWARD;
ftdm_channel_command(event->channel, FTDM_COMMAND_SET_POLARITY, &forward_polarity);
}
}
break;
case FTDM_OOB_FLASH:
{
if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag(event->channel->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(event->channel);
event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
}
ftdm_channel_rotate_tokens(event->channel);
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
} else {
sig.event_id = FTDM_SIGEVENT_FLASH;
ftdm_span_send_signal(span, &sig);
@@ -940,12 +1074,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
}
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
} else {
if(!analog_data->max_dialstr) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_COLLECT);
} else {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
}
ftdm_mutex_unlock(event->channel->mutex);
locked = 0;
@@ -957,9 +1091,53 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
}
}
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
}
}
break;
case FTDM_OOB_ALARM_TRAP:
{
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(span, &sig);
}
break;
case FTDM_OOB_ALARM_CLEAR:
{
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(span, &sig);
}
break;
case FTDM_OOB_POLARITY_REVERSE:
{
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
"Ignoring polarity reversal, this should not happen in non-FXO channels!\n");
break;
}
if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD) &&
ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
"Forcing onhook in channel not in thread after polarity reversal\n");
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
break;
}
if (!ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)
&& !ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
"Ignoring polarity reversal because this channel is not configured for it\n");
break;
}
if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
"Ignoring polarity reversal because this channel is down\n");
break;
}
/* we have a good channel, set the polarity flag and let the channel thread deal with it */
ftdm_set_sflag(event->channel, AF_POLARITY_REVERSE);
}
break;
default:
{
ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state));
@@ -355,7 +355,6 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
break;
}
} else {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
indicate = 0;
@@ -467,7 +466,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
dtmf_offset = strlen(dtmf);
last_digit = elapsed;
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
sig.raw_data = dtmf;
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
collecting = 0;
}
@@ -497,7 +497,7 @@ static ftdm_state_map_t isdn_state_map = {
* \param ftdmchan Channel to handle
* \note This function MUST be called with the channel locked
*/
static __inline__ void state_advance(ftdm_channel_t *chan)
static ftdm_status_t state_advance(ftdm_channel_t *chan)
{
ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
q931_call *call = (q931_call *)chan->call_data;
@@ -511,27 +511,23 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
sig.chan_id = ftdm_channel_get_id(chan);
sig.span_id = ftdm_channel_get_span_id(chan);
sig.channel = chan;
ftdm_channel_complete_state(chan);
switch (ftdm_channel_get_state(chan)) {
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_channel_t *chtmp = chan;
chan->call_data = NULL;
ftdm_channel_done(chan);
/*
* Close channel completely, BRI PTMP will thank us
*/
if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
ftdm_channel_t *chtmp = chan;
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
} else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
} else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
}
break;
@@ -631,7 +627,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
/* TODO: set hangup cause? */
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
return;
return FTDM_SUCCESS;
}
ton = caller_data->dnis.type;
@@ -714,6 +710,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
default:
break;
}
return FTDM_SUCCESS;
}
/**
@@ -729,13 +726,8 @@ static __inline__ void check_state(ftdm_span_t *span)
for (j = 1; j <= ftdm_span_get_chan_count(span); j++) {
ftdm_channel_t *chan = ftdm_span_get_channel(span, j);
ftdm_channel_lock(chan);
while (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag(chan, FTDM_CHANNEL_STATE_CHANGE);
state_advance(chan);
ftdm_channel_complete_state(chan);
}
ftdm_channel_advance_states(chan);
ftdm_channel_unlock(chan);
}
}
@@ -1403,8 +1395,7 @@ static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev
sig.chan_id = ftdm_channel_get_id(chan);
sig.channel = chan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(span, &sig);
}
}
@@ -1440,7 +1431,7 @@ static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_
sig.chan_id = ftdm_channel_get_id(chan);
sig.channel = chan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(span, &sig);
}
@@ -1917,6 +1908,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
span->outgoing_call = isdn_outgoing_call;
span->state_map = &isdn_state_map;
span->state_processor = state_advance;
span->get_channel_sig_status = isdn_get_channel_sig_status;
span->get_span_sig_status = isdn_get_span_sig_status;
@@ -127,9 +127,8 @@ static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
} else {
ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
}
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
return -1;
/* we cannot return -1, libpri seems to expect values >= 0 */
return 0;
}
spri->errs = 0;
res = (int)len;
@@ -156,8 +155,8 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
return -1;
/* we cannot return -1, libpri seems to expect values >= 0 */
return 0;
}
#ifdef IODEBUG
@@ -265,7 +265,7 @@ static ftdm_state_map_t pritap_state_map = {
}
};
static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_status_t status;
ftdm_sigmsg_t sig;
@@ -278,6 +278,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
@@ -321,24 +323,20 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
break;
}
return;
return FTDM_SUCCESS;
}
static __inline__ void pritap_check_state(ftdm_span_t *span)
{
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
state_advance(span->channels[j]);
ftdm_channel_complete_state(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
}
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
}
static int pri_io_read(struct pri *pri, void *buf, int buflen)
@@ -896,6 +894,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span)
span->get_span_sig_status = pritap_get_span_sig_status;
span->state_map = &pritap_state_map;
span->state_processor = state_advance;
return FTDM_SUCCESS;
}
+325 -237
View File
@@ -33,6 +33,7 @@
* Contributors:
*
* Arnaldo Pereira <arnaldo@sangoma.com>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
@@ -49,10 +50,6 @@
#include "freetdm.h"
#include "private/ftdm_core.h"
/* debug thread count for r2 legs */
static ftdm_mutex_t* g_thread_count_mutex;
static int32_t g_thread_count = 0;
typedef int openr2_call_status_t;
/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
@@ -76,7 +73,6 @@ typedef struct ftdm_r2_call_t {
int disconnect_rcvd:1;
int ftdm_call_started:1;
int protocol_error:1;
ftdm_channel_state_t chanstate;
ftdm_size_t dnis_index;
ftdm_size_t ani_index;
char logname[255];
@@ -171,8 +167,7 @@ static ftdm_hash_t *g_mod_data_hash;
/* IO interface for the command API */
static ftdm_io_interface_t g_ftdm_r2_interface;
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan);
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
/* whether R2 call accept process is pending */
#define IS_ACCEPTING_PENDING(ftdmchan) \
@@ -352,7 +347,6 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call)
call->disconnect_rcvd = 0;
call->ftdm_call_started = 0;
call->protocol_error = 0;
call->chanstate = FTDM_CHANNEL_STATE_DOWN;
call->dnis_index = 0;
call->ani_index = 0;
call->name[0] = 0;
@@ -380,11 +374,72 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
R2CALL(ftdmchan)->answer_pending = 0;
}
static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc)
{
switch (cpc) {
case OR2_CALLING_PARTY_CATEGORY_UNKNOWN:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER:
return FTDM_CPC_ORDINARY;
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER:
return FTDM_CPC_PRIORITY;
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT:
return FTDM_CPC_TEST;
case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE:
return FTDM_CPC_PAYPHONE;
case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL:
return FTDM_CPC_OPERATOR;
}
return FTDM_CPC_INVALID;
}
static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc)
{
switch (cpc) {
case FTDM_CPC_UNKNOWN:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
case FTDM_CPC_OPERATOR:
return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL;
case FTDM_CPC_ORDINARY:
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
case FTDM_CPC_PRIORITY:
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER;
case FTDM_CPC_DATA:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
case FTDM_CPC_TEST:
return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT;
case FTDM_CPC_PAYPHONE:
return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE;
case FTDM_CPC_INVALID:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
}
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
}
/* this function must be called with the chan mutex held! */
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
{
openr2_call_status_t callstatus;
ftdm_r2_data_t *r2data;
openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
r2data = ftdmchan->span->signal_data;
@@ -397,6 +452,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
ft_r2_clean_call(ftdmchan->call_data);
if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) {
category = r2data->category;
} else {
category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc);
}
/* start io dump */
if (r2data->mf_dump_size) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
@@ -404,9 +465,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.dnis.digits,
r2data->category);
category,
ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? 0 : 1);
if (callstatus) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
@@ -414,7 +476,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
R2CALL(ftdmchan)->ftdm_call_started = 1;
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
@@ -456,19 +517,40 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status)
{
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
openr2_cas_signal_t rxcas, txcas;
/* get the current rx and tx cas bits */
openr2_chan_get_cas(r2chan, &rxcas, &txcas);
/* if we're already in the state the user asks us to be, we have nothing to do */
if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n");
return FTDM_SUCCESS;
}
if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n");
return FTDM_SUCCESS;
}
/* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable.
* see docs/sigstatus.txt for details */
switch(status) {
case FTDM_SIG_STATE_DOWN:
case FTDM_SIG_STATE_SUSPENDED:
openr2_chan_set_blocked(r2chan);
if (rxcas == OR2_CAS_IDLE) {
ftdm_r2_set_chan_sig_status(ftdmchan, status);
}
break;
case FTDM_SIG_STATE_UP:
openr2_chan_set_idle(r2chan);
if (rxcas == OR2_CAS_IDLE) {
ftdm_r2_set_chan_sig_status(ftdmchan, status);
}
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
return FTDM_FAIL;
}
ftdm_r2_set_chan_sig_status(ftdmchan, status);
return FTDM_SUCCESS;
}
@@ -484,10 +566,13 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
*status = FTDM_SIG_STATE_SUSPENDED;
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
ftdm_channel_lock(fchan);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) {
*status = FTDM_SIG_STATE_UP;
ftdm_channel_unlock(fchan);
break;
}
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
@@ -497,21 +582,6 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
{
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *citer = NULL;
uint32_t span_opr = -1;
/* we either set the channels to BLOCK or IDLE */
switch(status) {
case FTDM_SIG_STATE_DOWN:
case FTDM_SIG_STATE_SUSPENDED:
span_opr = 0;
break;
case FTDM_SIG_STATE_UP:
span_opr = 1;
break;
default:
ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
return FTDM_FAIL;
}
chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
@@ -521,15 +591,13 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
/* iterate over all channels, setting them to the requested state */
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
if (span_opr == 0) {
openr2_chan_set_blocked(r2chan);
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n");
} else {
openr2_chan_set_idle(r2chan);
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n");
/* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes
* care of notifying the user when appropriate */
ftdm_channel_lock(fchan);
if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) {
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status));
}
ftdm_r2_set_chan_sig_status(fchan, status);
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
@@ -552,7 +620,7 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
}
}
@@ -586,7 +654,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
}
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
@@ -595,12 +662,14 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
static void dump_mf(openr2_chan_t *r2chan);
/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis,
openr2_calling_party_category_t category, int ani_restricted)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category);
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = %d, ANI restricted = %s\n",
ani, dnis, category, ani_restricted ? "Yes" : "No");
/* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
if (r2data->mf_dump_size) {
@@ -615,6 +684,8 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
} else {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
}
ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category);
ftdmchan->caller_data.pres = ani_restricted ? FTDM_PRES_RESTRICTED : FTDM_PRES_ALLOWED;
}
/*
@@ -632,12 +703,10 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
static void clear_accept_pending(ftdm_channel_t *fchan)
{
if (IS_ACCEPTING_PENDING(fchan)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
} else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n",
ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
}
}
@@ -745,7 +814,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
/* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
}
static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
@@ -777,7 +846,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data)
goto done;
}
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
done:
ftdm_channel_unlock(ftdmchan);
}
@@ -1158,6 +1227,18 @@ static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level)
static ftdm_state_map_t r2_state_map = {
{
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
},
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
@@ -1209,6 +1290,20 @@ static ftdm_state_map_t r2_state_map = {
/* Outbound states */
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
@@ -1515,10 +1610,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
span->set_channel_sig_status = ftdm_r2_set_channel_sig_status;
span->state_map = &r2_state_map;
span->state_processor = ftdm_r2_state_advance;
/* use signals queue */
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
/* we can skip states (going straight from RING to UP) */
ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
/* setup the scheduler */
snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
@@ -1541,10 +1640,10 @@ fail:
}
/* the channel must be locked when calling this function */
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_sigmsg_t sigev;
int ret;
ftdm_status_t ret;
ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
openr2_chan_t *r2chan = r2call->r2chan;
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
@@ -1554,172 +1653,173 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
ret = 0;
ret = FTDM_SUCCESS;
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
* to complete (the processing is media-bound)
* */
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
&& (r2call->chanstate != ftdmchan->state)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
r2call->chanstate = ftdmchan->state;
if (IS_ACCEPTING_PENDING(ftdmchan)) {
/*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
}
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
r2call->ftdm_call_started = 1;
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
ft_r2_accept_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
// the answering will be done in the on_call_accepted handler
ft_r2_accept_call(ftdmchan);
r2call->answer_pending = 1;
} else {
ft_r2_answer_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
if (!r2call->disconnect_rcvd) {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
} else if (!r2call->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
/* do not set to down yet, give some time for recovery */
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
}
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
/* if the call has not been started yet we must go to HANGUP right here */
if (!r2call->ftdm_call_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* notify the user of the call terminating and we wait for the user to move us to hangup */
sigev.event_id = FTDM_SIGEVENT_STOP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
ret = 1;
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
if (IS_ACCEPTING_PENDING(ftdmchan)) {
/*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_channel_complete_state(ftdmchan);
}
if (ret) {
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
r2call->ftdm_call_started = 1;
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
ft_r2_accept_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
// the answering will be done in the on_call_accepted handler
ft_r2_accept_call(ftdmchan);
r2call->answer_pending = 1;
} else {
ft_r2_answer_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
if (!r2call->disconnect_rcvd) {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
} else if (!r2call->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
/* do not set to down yet, give some time for recovery */
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
}
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
/* if the call has not been started yet we must go to HANGUP right here */
if (!r2call->ftdm_call_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* notify the user of the call terminating and we wait for the user to move us to hangup */
sigev.event_id = FTDM_SIGEVENT_STOP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
if (ftdmchan->last_state != FTDM_CHANNEL_STATE_RESET) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Reset Complete\n");
}
ret = FTDM_BREAK;
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
}
break;
/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
case FTDM_CHANNEL_STATE_RESET:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
openr2_chan_set_idle(r2chan);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
if (ret == FTDM_BREAK) {
ftdm_channel_t *closed_chan;
closed_chan = ftdmchan;
ftdm_channel_close(&closed_chan);
@@ -1728,20 +1828,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
return ret;
}
/* the channel must be locked when calling this function */
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan)
{
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
* to complete (the processing is media-bound)
* */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
&& (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
ftdm_r2_state_advance(ftdmchan);
}
}
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
{
openr2_chan_t *r2chan = NULL;
@@ -1776,10 +1862,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
}
for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_channel_lock(ftdmchan);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_span_id(r2chan, span->span_id);
openr2_chan_set_idle(r2chan);
openr2_chan_process_cas_signaling(r2chan);
ftdm_channel_unlock(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txqueue_size);
}
@@ -1861,7 +1949,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_mutex_lock(ftdmchan->mutex);
ftdm_channel_lock(ftdmchan);
call = R2CALL(ftdmchan);
@@ -1870,12 +1958,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
r2chan = call->r2chan;
openr2_chan_process_signaling(r2chan);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
if (!call->accepted) {
/* if the call is not accepted we do not want users reading */
@@ -1883,7 +1971,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
}
ftdm_mutex_unlock(ftdmchan->mutex);
ftdm_channel_unlock(ftdmchan);
}
}
@@ -1891,8 +1979,10 @@ done:
citer = ftdm_span_get_chan_iterator(span, chaniter);
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_channel_lock(ftdmchan);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_blocked(r2chan);
ftdm_channel_unlock(ftdmchan);
}
ftdm_iterator_free(chaniter);
@@ -1947,6 +2037,14 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle
ftdm_mutex_unlock(fchan->mutex);
}
#define FT_SYNTAX "USAGE:\n" \
"--------------------------------------------------------------------------------\n" \
"ftdm r2 status <span_id|span_name>\n" \
"ftdm r2 loopstats <span_id|span_name>\n" \
"ftdm r2 block|unblock <span_id|span_name> [<chan_id>]\n" \
"ftdm r2 version\n" \
"ftdm r2 variants\n" \
"--------------------------------------------------------------------------------\n"
static FIO_API_FUNCTION(ftdm_r2_api)
{
ftdm_span_t *span = NULL;
@@ -2130,14 +2228,6 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
if (argc == 1) {
if (!strcasecmp(argv[0], "threads")) {
ftdm_mutex_lock(g_thread_count_mutex);
stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
ftdm_mutex_unlock(g_thread_count_mutex);
stream->write_function(stream, "+OK.\n");
goto done;
}
if (!strcasecmp(argv[0], "version")) {
stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
stream->write_function(stream, "+OK.\n");
@@ -2163,7 +2253,7 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
}
stream->write_function(stream, "-ERR invalid command.\n");
stream->write_function(stream, "%s", FT_SYNTAX);
done:
@@ -2192,7 +2282,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
if (!g_mod_data_hash) {
return FTDM_FAIL;
}
ftdm_mutex_create(&g_thread_count_mutex);
return FTDM_SUCCESS;
}
@@ -2212,7 +2301,6 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
}
}
hashtable_destroy(g_mod_data_hash);
ftdm_mutex_destroy(&g_thread_count_mutex);
return FTDM_SUCCESS;
}
@@ -951,7 +951,6 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon,
}
}
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
static __inline__ void stop_loop(ftdm_channel_t *ftdmchan);
/**
@@ -1002,7 +1001,7 @@ tryagain:
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) {
retry = 0;
stop_loop(ftdmchan);
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
goto tryagain;
} else {
ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n",
@@ -1267,7 +1266,7 @@ static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_e
}
ftdm_mutex_lock(ftdmchan->mutex);
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
return ftdmchan;
}
@@ -1354,11 +1353,11 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
}
if(ftdmchan != NULL) {
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
return 0;
return 0;
}
@@ -1366,7 +1365,7 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
* \brief Handler for channel state change
* \param ftdmchan Channel to handle
*/
static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
@@ -1374,12 +1373,6 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
ftdm_status_t status;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
} else {
return FTDM_SUCCESS;
}
ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n");
ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
@@ -1389,6 +1382,8 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
@@ -1640,24 +1635,15 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
default:
break;
}
ftdm_channel_complete_state(ftdmchan);
return FTDM_SUCCESS;
}
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
{
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
state_advance(ftdmchan);
}
}
/**
* \brief Initialises outgoing requests array
*/
static __inline__ void init_outgoing_array(void)
{
memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
}
/**
@@ -1685,7 +1671,7 @@ static __inline__ void check_state(ftdm_span_t *span)
if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
}
state_advance(span->channels[j]);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
@@ -1695,7 +1681,7 @@ static __inline__ void check_state(ftdm_span_t *span)
* but without taking the chan out of the queue, so check th
* flag before advancing the state */
ftdm_mutex_lock(ftdmchan->mutex);
state_advance(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
}
@@ -2478,7 +2464,7 @@ static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(ftdmchan->span, &sig);
return;
}
@@ -2687,6 +2673,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
span->get_span_sig_status = sangoma_boost_get_span_sig_status;
span->set_span_sig_status = sangoma_boost_set_span_sig_status;
span->state_map = &boost_state_map;
span->state_processor = state_advance;
sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
@@ -31,6 +31,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _GNU_SOURCE
#if HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -40,11 +40,12 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;C:\Program Files\libsng_isdn\include&quot;;&quot;C:\Program Files\libsng_isdn\include\sng_isdn&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
AdditionalIncludeDirectories="&quot;C:\Program Files\sangoma\sng_isdn\include&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -63,7 +64,7 @@
Name="VCLinkerTool"
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\libsng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\sangoma\sng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
@@ -116,10 +117,11 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;C:\Program Files\sangoma\sng_isdn\include&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -136,7 +138,9 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\sangoma\sng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
@@ -85,7 +85,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<ExceptionHandling>
@@ -95,10 +95,11 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
@@ -110,7 +111,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
@@ -119,6 +120,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -135,11 +137,13 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -147,23 +151,27 @@
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -46,10 +46,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
static void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span);
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event);
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
@@ -270,13 +269,6 @@ ftdm_state_map_t sangoma_isdn_state_map = {
}
};
static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan)
{
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_isdn_process_state_change(ftdmchan);
}
}
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
@@ -457,7 +449,7 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
/* double check that this channel has a state change pending */
ftdm_channel_lock(ftdmchan);
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
@@ -470,11 +462,11 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
/* twiddle */
break;
case FTDM_FAIL:
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name);
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
break;
default:
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name);
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
break;
}
@@ -536,7 +528,7 @@ ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisd
break;
}
ftdm_channel_lock(ftdmchan);
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
return ftdmchan;
}
@@ -600,13 +592,14 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev
sngisdn_process_rst_ind(sngisdn_event);
break;
}
if(ftdmchan != NULL) {
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
if (ftdmchan != NULL) {
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
}
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
/* this function is called with the channel already locked by the core */
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
{
ftdm_sigmsg_t sigev;
ftdm_channel_state_t initial_state;
@@ -618,13 +611,12 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
/*first lock the channel*/
ftdm_channel_lock(ftdmchan);
/*clear the state change flag...since we might be setting a new state*/
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
/* Acknowledge the state change */
ftdm_channel_complete_state(ftdmchan);
#ifdef FTDM_DEBUG_CHAN_MEMORY
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect");
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ) == 0, "Failed to mprotect");
}
#endif
@@ -879,11 +871,10 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
}
#ifdef FTDM_DEBUG_CHAN_MEMORY
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect");
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE) == 0, "Failed to mprotect");
}
#endif
ftdm_channel_unlock(ftdmchan);
return;
return FTDM_SUCCESS;
}
static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
@@ -1098,6 +1089,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
span->state_map = &sangoma_isdn_state_map;
span->state_processor = ftdm_sangoma_isdn_process_state_change;
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
@@ -137,8 +137,9 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
sigev.raw.data = raw_data;
sigev.raw.len = data_len;
sigev.raw.autofree = 1;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
@@ -250,8 +251,9 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
sigev.raw.data = raw_data;
sigev.raw.len = data_len;
sigev.raw.autofree = 1;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
}
@@ -46,7 +46,6 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data;
/* PROTOTYPES *****************************************************************/
static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj);
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event);
static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span);
@@ -308,9 +307,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
ftdm_mutex_lock(ftdmchan->mutex);
/* process state changes for this channel until they are all done */
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change (ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* unlock the channel */
ftdm_mutex_unlock (ftdmchan->mutex);
@@ -403,9 +400,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
ftdm_mutex_lock(ftdmchan->mutex);
/* while there's a state change present on this channel process it */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change(ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* figure out the type of event and send it to the right handler */
switch (sngss7_event->event_id) {
@@ -468,9 +463,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
} /* switch (sngss7_event->event_id) */
/* while there's a state change present on this channel process it */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change(ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* unlock the channel */
ftdm_mutex_unlock(ftdmchan->mutex);
@@ -479,7 +472,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
}
/******************************************************************************/
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
{
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
sng_isup_inf_t *isup_intf = NULL;
@@ -495,7 +488,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state));
/* clear the state change flag...since we might be setting a new state */
ftdm_clear_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
/*check what state we are supposed to be in */
switch (ftdmchan->state) {
@@ -1212,7 +1205,7 @@ suspend_goto_restart:
/**************************************************************************/
}/*switch (ftdmchan->state) */
return;
return FTDM_SUCCESS;
}
/******************************************************************************/
@@ -1476,6 +1469,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
span->get_channel_sig_status = ftdm_sangoma_ss7_get_sig_status;
span->set_channel_sig_status = ftdm_sangoma_ss7_set_sig_status;
span->state_map = &sangoma_ss7_state_map;
span->state_processor = ftdm_sangoma_ss7_process_state_change;
span->signal_data = ss7_span_info;
/* set the flag to indicate that this span uses channel state change queues */
@@ -452,7 +452,7 @@ extern int cmbLinkSetId;
/* PROTOTYPES *****************************************************************/
/* in ftmod_sangoma_ss7_main.c */
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
/* in ftmod_sangoma_ss7_logger.c */
void handle_sng_log(uint8_t level, char *fmt,...);
@@ -100,7 +100,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -127,7 +127,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -148,7 +148,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -174,7 +174,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -784,17 +784,27 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
}
break;
case FTDM_COMMAND_SET_POLARITY:
{
ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT;
err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity);
if (!err) {
ftdmchan->polarity = polarity;
}
}
break;
default:
err = FTDM_NOTIMPL;
break;
};
if (err) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
int myerrno = errno;
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno));
errno = myerrno;
return err;
}
return FTDM_SUCCESS;
}
@@ -1224,6 +1234,131 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
return FTDM_SUCCESS;
}
/**
* \brief Process an event in a channel and set it's OOB event id. The channel must be locked.
* \param fchan Channel in which event occured
* \param event_id Pointer where we save the OOB event id
* \param tdm_api Wanpipe tdm struct that contain the event
* \return FTDM_SUCCESS or FTDM_FAIL
*/
static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, wanpipe_tdm_api_t *tdm_api)
{
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_API_EVENT_LINK_STATUS:
{
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
*event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
*event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_API_EVENT_RXHOOK:
{
if (fchan->type == FTDM_CHAN_TYPE_FXS) {
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (*event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(fchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
*event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag(fchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(fchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
*event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag(fchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
ftdm_status_t status;
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(fchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(fchan->last_error, sizeof(fchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
*event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_API_EVENT_RING_DETECT:
{
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_API_EVENT_RING_TRIP_DETECT:
{
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_API_EVENT_RBS:
{
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
fchan->rx_cas_bits = wanpipe_swap_bits(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_API_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
*event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag(fchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
}
}
}
break;
case WP_API_EVENT_ALARM:
{
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api->wp_tdm_cmd.event.wp_api_event_alarm);
*event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case WP_API_EVENT_POLARITY_REVERSE:
{
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Got polarity reverse\n");
*event_id = FTDM_OOB_POLARITY_REVERSE;
}
break;
default:
{
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type);
*event_id = FTDM_OOB_INVALID;
}
break;
}
event:
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a wanpipe channel
* \param channel Channel to retrieve event from
@@ -1237,8 +1372,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
wanpipe_tdm_api_t tdm_api;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT))
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
memset(&tdm_api, 0, sizeof(tdm_api));
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
@@ -1249,115 +1385,11 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_TDMAPI_EVENT_LINK_STATUS:
{
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
return FTDM_FAIL;
}
event:
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
@@ -1419,114 +1451,15 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_TDMAPI_EVENT_LINK_STATUS:
{
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
}
}
continue;
} else {
int err;
ftdm_channel_t *ftdmchan = span->channels[i];
err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
if (err) {
snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
ftdm_channel_lock(ftdmchan);
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process events from channel\n");
ftdm_channel_unlock(ftdmchan);
return FTDM_FAIL;
}
ftdm_channel_unlock(ftdmchan);
event:
@@ -1538,9 +1471,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
return FTDM_SUCCESS;
}
}
return FTDM_FAIL;
}
/**
+191 -116
View File
@@ -52,42 +52,48 @@ static struct {
float txgain;
} zt_globals;
#if defined(__FreeBSD__)
typedef unsigned long ioctlcmd;
#else
typedef int ioctlcmd;
#endif
/**
* \brief General IOCTL codes
*/
struct ioctl_codes {
int GET_BLOCKSIZE;
int SET_BLOCKSIZE;
int FLUSH;
int SYNC;
int GET_PARAMS;
int SET_PARAMS;
int HOOK;
int GETEVENT;
int IOMUX;
int SPANSTAT;
int MAINT;
int GETCONF;
int SETCONF;
int CONFLINK;
int CONFDIAG;
int GETGAINS;
int SETGAINS;
int SPANCONFIG;
int CHANCONFIG;
int SET_BUFINFO;
int GET_BUFINFO;
int AUDIOMODE;
int ECHOCANCEL;
int HDLCRAWMODE;
int HDLCFCSMODE;
int SPECIFY;
int SETLAW;
int SETLINEAR;
int GETCONFMUTE;
int ECHOTRAIN;
int SETTXBITS;
int GETRXBITS;
ioctlcmd GET_BLOCKSIZE;
ioctlcmd SET_BLOCKSIZE;
ioctlcmd FLUSH;
ioctlcmd SYNC;
ioctlcmd GET_PARAMS;
ioctlcmd SET_PARAMS;
ioctlcmd HOOK;
ioctlcmd GETEVENT;
ioctlcmd IOMUX;
ioctlcmd SPANSTAT;
ioctlcmd MAINT;
ioctlcmd GETCONF;
ioctlcmd SETCONF;
ioctlcmd CONFLINK;
ioctlcmd CONFDIAG;
ioctlcmd GETGAINS;
ioctlcmd SETGAINS;
ioctlcmd SPANCONFIG;
ioctlcmd CHANCONFIG;
ioctlcmd SET_BUFINFO;
ioctlcmd GET_BUFINFO;
ioctlcmd AUDIOMODE;
ioctlcmd ECHOCANCEL;
ioctlcmd HDLCRAWMODE;
ioctlcmd HDLCFCSMODE;
ioctlcmd SPECIFY;
ioctlcmd SETLAW;
ioctlcmd SETLINEAR;
ioctlcmd GETCONFMUTE;
ioctlcmd ECHOTRAIN;
ioctlcmd SETTXBITS;
ioctlcmd GETRXBITS;
};
/**
@@ -181,6 +187,7 @@ static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event);
/**
* \brief Initialises codec, and rx/tx gains
@@ -985,6 +992,124 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
return k ? FTDM_SUCCESS : FTDM_FAIL;
}
/**
* \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked.
* \param fchan Channel to retrieve event from
* \param event_id Pointer to OOB event id
* \param zt_event_id Zaptel event id
* \return FTDM_SUCCESS or FTDM_FAIL
*/
static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
{
switch(zt_event_id) {
case ZT_EVENT_RINGEROFF:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGERON:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGBEGIN:
{
*event_id = FTDM_OOB_RING_START;
}
break;
case ZT_EVENT_ONHOOK:
{
*event_id = FTDM_OOB_ONHOOK;
}
break;
case ZT_EVENT_WINKFLASH:
{
if (fchan->state == FTDM_CHANNEL_STATE_DOWN || fchan->state == FTDM_CHANNEL_STATE_DIALING) {
*event_id = FTDM_OOB_WINK;
} else {
*event_id = FTDM_OOB_FLASH;
}
}
break;
case ZT_EVENT_RINGOFFHOOK:
{
if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
*event_id = FTDM_OOB_OFFHOOK;
} else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
*event_id = FTDM_OOB_RING_START;
} else {
*event_id = FTDM_OOB_NOOP;
}
}
break;
case ZT_EVENT_ALARM:
{
*event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case ZT_EVENT_NOALARM:
{
*event_id = FTDM_OOB_ALARM_CLEAR;
}
break;
case ZT_EVENT_BITSCHANGED:
{
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
int bits = 0;
int err = ioctl(fchan->sockfd, codes.GETRXBITS, &bits);
if (err) {
return FTDM_FAIL;
}
fchan->rx_cas_bits = bits;
}
break;
default:
{
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
*event_id = FTDM_OOB_INVALID;
}
break;
}
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a ftdm channel
* \param ftdmchan Channel to retrieve event from
* \param event FreeTDM event to return
* \return Success or failure
*/
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
{
uint32_t event_id = FTDM_OOB_INVALID;
zt_event_t zt_event_id = 0;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n",
strerror(errno));
return FTDM_FAIL;
}
/* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */
if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
return FTDM_FAIL;
}
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = ftdmchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a ftdmtel span
* \param span Span to retrieve event from
@@ -997,91 +1122,29 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
zt_event_t zt_event_id = 0;
for(i = 1; i <= span->chan_count; i++) {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
switch(zt_event_id) {
case ZT_EVENT_RINGEROFF:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGERON:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGBEGIN:
{
event_id = FTDM_OOB_RING_START;
}
break;
case ZT_EVENT_ONHOOK:
{
event_id = FTDM_OOB_ONHOOK;
}
break;
case ZT_EVENT_WINKFLASH:
{
if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) {
event_id = FTDM_OOB_WINK;
} else {
event_id = FTDM_OOB_FLASH;
}
}
break;
case ZT_EVENT_RINGOFFHOOK:
{
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
event_id = FTDM_OOB_OFFHOOK;
} else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
event_id = FTDM_OOB_RING_START;
} else {
event_id = FTDM_OOB_NOOP;
}
}
break;
case ZT_EVENT_ALARM:
{
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case ZT_EVENT_NOALARM:
{
event_id = FTDM_OOB_ALARM_CLEAR;
}
break;
case ZT_EVENT_BITSCHANGED:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
int bits = 0;
int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
if (err) {
return FTDM_FAIL;
}
span->channels[i]->rx_cas_bits = bits;
}
break;
default:
{
ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
event_id = FTDM_OOB_INVALID;
}
break;
}
span->channels[i]->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = span->channels[i];
*event = &span->event_header;
return FTDM_SUCCESS;
ftdm_channel_t *fchan = span->channels[i];
if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT);
}
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
ftdm_channel_lock(fchan);
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
ftdm_channel_unlock(fchan);
return FTDM_FAIL;
}
ftdm_channel_unlock(fchan);
fchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = fchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
return FTDM_FAIL;
@@ -1146,6 +1209,7 @@ static FIO_WRITE_FUNCTION(zt_write)
bytes += 2;
}
tryagain:
w = write(ftdmchan->sockfd, data, bytes);
if (w >= 0) {
@@ -1153,6 +1217,17 @@ static FIO_WRITE_FUNCTION(zt_write)
return FTDM_SUCCESS;
}
if (errno == ELAST) {
zt_event_t zt_event_id = 0;
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
return FTDM_FAIL;
}
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
goto tryagain;
}
return FTDM_FAIL;
}
+114 -26
View File
@@ -144,7 +144,9 @@ typedef enum {
/*! \brief Hunting direction (when hunting for free channels) */
typedef enum {
FTDM_TOP_DOWN,
FTDM_BOTTOM_UP
FTDM_BOTTOM_UP,
FTDM_RR_DOWN,
FTDM_RR_UP,
} ftdm_direction_t;
/*! \brief I/O channel type */
@@ -265,15 +267,32 @@ typedef enum {
#define USER_LAYER1_PROT_STRINGS "V.110", "u-law", "a-law", "Invalid"
FTDM_STR2ENUM_P(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t)
/*! Calling Party Category */
typedef enum {
FTDM_CPC_UNKNOWN,
FTDM_CPC_OPERATOR,
FTDM_CPC_ORDINARY,
FTDM_CPC_PRIORITY,
FTDM_CPC_DATA,
FTDM_CPC_TEST,
FTDM_CPC_PAYPHONE,
FTDM_CPC_INVALID
} ftdm_calling_party_category_t;
#define CALLING_PARTY_CATEGORY_STRINGS "unknown", "operator", "ordinary", "priority", "data-call", "test-call", "payphone", "invalid"
FTDM_STR2ENUM_P(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t)
/*! \brief Digit limit used in DNIS/ANI */
#define FTDM_DIGITS_LIMIT 25
/*! \brief Number abstraction */
typedef struct {
char digits[25];
char digits[FTDM_DIGITS_LIMIT];
uint8_t type;
uint8_t plan;
} ftdm_number_t;
typedef void * ftdm_variable_container_t;
/*! \brief Caller information */
typedef struct ftdm_caller_data {
char cid_date[8]; /*!< Caller ID date */
@@ -282,10 +301,10 @@ typedef struct ftdm_caller_data {
ftdm_number_t ani; /*!< ANI (Automatic Number Identification) */
ftdm_number_t dnis; /*!< DNIS (Dialed Number Identification Service) */
ftdm_number_t rdnis; /*!< RDNIS (Redirected Dialed Number Identification Service) */
char aniII[25]; /*! ANI II */
char aniII[FTDM_DIGITS_LIMIT]; /*! ANI II */
uint8_t screen; /*!< Screening */
uint8_t pres; /*!< Presentation*/
char collected[25]; /*!< Collected digits so far */
char collected[FTDM_DIGITS_LIMIT]; /*!< Collected digits so far */
int hangup_cause; /*!< Hangup cause */
char raw_data[1024]; /*!< Protocol specific raw caller data */
uint32_t raw_data_len; /*!< Raw data length */
@@ -294,12 +313,14 @@ typedef struct ftdm_caller_data {
ftdm_bearer_cap_t bearer_capability;
/* user information layer 1 protocol */
ftdm_user_layer1_prot_t bearer_layer1;
ftdm_variable_container_t variables; /*!<variables attached to this call */
ftdm_calling_party_category_t cpc; /*!< Calling party category */
ftdm_variable_container_t variables; /*!< Variables attached to this call */
/* We need call_id inside caller_data for the user to be able to retrieve
* the call_id when ftdm_channel_call_place is called. This is the only time
* that the user can use caller_data.call_id to obtain the call_id. The user
* should use the call_id from sigmsg otherwise */
uint32_t call_id; /*!< Unique call ID for this call */
ftdm_channel_t *fchan; /*!< FreeTDM channel associated (can be NULL) */
} ftdm_caller_data_t;
/*! \brief Tone type */
@@ -328,12 +349,13 @@ typedef enum {
FTDM_SIGEVENT_FACILITY, /*!< In call facility event */
FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */
FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */
FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */
FTDM_SIGEVENT_INVALID, /*!<Invalid */
} ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", "TRACE", "TRACE_RAW", "INVALID"
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", \
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
@@ -418,19 +440,55 @@ typedef struct {
ftdm_trace_type_t type;
} ftdm_event_trace_t;
typedef struct {
/* Digits collected */
char digits[FTDM_DIGITS_LIMIT];
} ftdm_event_collected_t;
/*! \brief FreeTDM supported indications.
* This is used during incoming calls when you want to request the signaling stack
* to notify about indications occurring locally. See ftdm_channel_call_indicate for more info */
typedef enum {
FTDM_CHANNEL_INDICATE_NONE,
FTDM_CHANNEL_INDICATE_RINGING,
FTDM_CHANNEL_INDICATE_PROCEED,
FTDM_CHANNEL_INDICATE_PROGRESS,
FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
FTDM_CHANNEL_INDICATE_BUSY,
/* Using this indication is equivalent to call ftdm_channel_call_answer API */
FTDM_CHANNEL_INDICATE_ANSWER,
FTDM_CHANNEL_INDICATE_INVALID,
} ftdm_channel_indication_t;
#define INDICATION_STRINGS "NONE", "RINGING", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "BUSY", "ANSWER", "INVALID"
/*! \brief Move from string to ftdm_channel_indication_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t)
typedef struct {
/* The indication that was completed */
ftdm_channel_indication_t indication;
/* Completion status of the indication */
ftdm_status_t status;
} ftdm_event_indication_completed_t;
/*! \brief Generic signaling message */
struct ftdm_sigmsg {
ftdm_signal_event_t event_id; /*!< The type of message */
ftdm_channel_t *channel; /*!< Related channel */
uint32_t chan_id; /*!< easy access to chan id */
uint32_t span_id; /*!< easy access to span_id */
void *raw_data; /*!< Message specific data if any */
uint32_t raw_data_len; /*!< Data len in case is needed */
uint32_t call_id; /*!< unique call id for this call */
union {
ftdm_event_sigstatus_t sigstatus; /*!< valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED */
ftdm_event_trace_t trace; /*!< valid if event_id is FTDM_SIGEVENT_TRACE or FTDM_SIGEVENT_TRACE_RAW */
}ev_data;
ftdm_event_collected_t collected; /*!< valid if event_id is FTDM_SIGEVENT_COLLECTED_DIGIT */
ftdm_event_indication_completed_t indication_completed; /*!< valid if the event_id is FTDM_SIGEVENT_INDICATION_COMPLETED */
} ev_data;
struct {
uint8_t autofree; /*!< Whether the freetdm core will free it after message delivery */
uint32_t len; /*!< Data len */
void *data; /*!< Signaling module specific data */
} raw;
};
/*! \brief Crash policy
@@ -535,11 +593,17 @@ typedef enum {
FTDM_COMMAND_GET_LINK_STATUS,
FTDM_COMMAND_ENABLE_LOOP,
FTDM_COMMAND_DISABLE_LOOP,
FTDM_COMMAND_COUNT,
FTDM_COMMAND_SET_RX_QUEUE_SIZE,
FTDM_COMMAND_SET_TX_QUEUE_SIZE,
FTDM_COMMAND_SET_POLARITY,
FTDM_COMMAND_COUNT,
} ftdm_command_t;
typedef enum {
FTDM_POLARITY_FORWARD = 0,
FTDM_POLARITY_REVERSE = 1
} ftdm_polarity_t;
/*! \brief Custom memory handler hooks. Not recommended to use unless you need memory allocation customizations */
typedef void *(*ftdm_malloc_func_t)(void *pool, ftdm_size_t len);
typedef void *(*ftdm_calloc_func_t)(void *pool, ftdm_size_t elements, ftdm_size_t len);
@@ -598,7 +662,20 @@ typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS;
typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ;
typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ;
typedef ftdm_status_t (*fio_channel_next_event_t) FIO_CHANNEL_NEXT_EVENT_ARGS ;
/*! \brief Callback for signal delivery (FTDM_SIGEVENT_START and friends)
* \note This callback is provided by the user during ftdm_configure_span_signaling
*
* \note You must NOT do any blocking during this callback since this function is
* most likely called in an internal signaling thread that can potentially be
* shared for all the channels in a span and blocking will delay processing
* (sometimes even audio processing) for other channels
*
* \note Although some simple FreeTDM APIs can work (ie: ftdm_span_get_id etc), the
* use of any FreeTDM call API (ie ftdm_channel_call_answer) is discouraged
*/
typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ;
typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ;
typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ;
typedef ftdm_status_t (*fio_configure_t) FIO_CONFIGURE_ARGS ;
@@ -682,17 +759,6 @@ typedef enum {
FTDM_CODEC_NONE = (1 << 30)
} ftdm_codec_t;
/*! \brief FreeTDM supported indications.
* This is used during incoming calls when you want to request the signaling stack
* to notify about indications occurring locally */
typedef enum {
FTDM_CHANNEL_INDICATE_RINGING,
FTDM_CHANNEL_INDICATE_PROCEED,
FTDM_CHANNEL_INDICATE_PROGRESS,
FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
FTDM_CHANNEL_INDICATE_BUSY,
} ftdm_channel_indication_t;
/*! \brief FreeTDM supported hardware alarms. */
typedef enum {
FTDM_ALARM_NONE = 0,
@@ -715,7 +781,12 @@ FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *ha
*/
FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan);
/*! \brief Answer call */
/*! \brief Answer call. This can also be accomplished by ftdm_channel_call_indicate with FTDM_CHANNEL_INDICATE_ANSWER, in both
* cases you will get a FTDM_SIGEVENT_INDICATION_COMPLETED when the indication is sent (or an error occurs)
* \note Although this API will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered,
* there is no guarantee of whether the event will arrive after or before your execution thread returns
* from ftdm_channel_call_answer
*/
#define ftdm_channel_call_answer(ftdmchan) _ftdm_channel_call_answer(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
/*! \brief Answer call recording the source code point where the it was called (see ftdm_channel_call_answer for an easy to use macro) */
@@ -727,7 +798,19 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
/*! \brief Place an outgoing call recording the source code point where it was called (see ftdm_channel_call_place for an easy to use macro) */
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Indicate a new condition in an incoming call */
/*! \brief Indicate a new condition in an incoming call
*
* \note Every indication request will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered with
* the proper status that will inform you if the request was successful or not. The exception is if this
* function returns something different to FTDM_SUCCESS, in which case the request failed right away and no
* further FTDM_SIGEVENT_INDICATION_COMPLETED will be delivered
* Be aware there is no guarantee of whether the completion event will arrive after or before your execution
* thread returns from ftdm_channel_call_indicate. This means you could get FTDM_SIGEVENT_INDICATION_COMPLETED
* even before your execution thread returns from the ftdm_channel_call_indicate() API
*
* \note You cannot send more than one indication at the time. You must wait for the completed event before
* calling this function again (unless the return code was different than FTDM_SUCCESS)
*/
#define ftdm_channel_call_indicate(ftdmchan, indication) _ftdm_channel_call_indicate(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (indication))
/*! \brief Indicate a new condition in an incoming call recording the source code point where it was called (see ftdm_channel_call_indicate for an easy to use macro) */
@@ -1468,9 +1551,14 @@ FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *c
*/
FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *channel);
/*! \brief Initialize channel state for an outgoing call */
/*! \brief Initialize channel state for an outgoing call
* \note This API will eventually be deprecated, is only needed if you use boost signaling
*/
FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan);
/*! \brief Enable/disable blocking mode in the channels for this span */
FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, ftdm_bool_t enabled);
/*! \brief Initialize the library */
FT_DECLARE(ftdm_status_t) ftdm_global_init(void);
@@ -30,6 +30,12 @@
* 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>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
#ifndef __FTDM_CALL_UTILS_H__
@@ -114,5 +120,16 @@ FT_DECLARE(ftdm_status_t) ftdm_set_presentation_ind(const char *string, uint8_t
*/
FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number);
/*!
* \brief Set the Calling Party Category from an enum
*
* \param cpc_string string value
* \param target the target to set value to
*
* \retval FTDM_SUCCESS success
* \retval FTDM_FAIL failure
*/
FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target);
#endif /* __FTDM_CALL_UTILS_H__ */
+10 -1
View File
@@ -183,7 +183,16 @@ typedef enum {
FTDM_TIMEOUT, /*!< Operation timed out (ie: polling on a device)*/
FTDM_NOTIMPL, /*!< Operation not implemented */
FTDM_BREAK, /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */
FTDM_EINVAL /*!< Invalid argument */
/*!< Any new return codes should try to mimc unix style error codes, no need to reinvent */
/* Remapping some of the codes that were before */
FTDM_ENOMEM = FTDM_MEMERR, /*!< Memory error */
FTDM_ETIMEDOUT = FTDM_TIMEOUT, /*!< Operation timedout */
FTDM_ENOSYS = FTDM_NOTIMPL, /*!< The function is not implemented */
FTDM_EINVAL, /*!< Invalid argument */
FTDM_ECANCELED, /*!< Operation cancelled */
FTDM_EBUSY, /*!< Device busy */
} ftdm_status_t;
/*! \brief FreeTDM bool type. */
+5
View File
@@ -51,6 +51,9 @@ extern "C" {
#include <unistd.h>
#endif
/*! \brief time data type */
typedef uint64_t ftdm_time_t;
/*! \brief sleep x amount of milliseconds */
#ifdef __WINDOWS__
#define ftdm_sleep(x) Sleep(x)
@@ -114,6 +117,8 @@ FT_DECLARE(char *) ftdm_strdup(const char *str);
/*! \brief Duplicate string with limit */
FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen);
/*! \brief Get the current time in milliseconds */
FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
#ifdef __cplusplus
} /* extern C */
+14 -76
View File
@@ -143,7 +143,9 @@ extern "C" {
\return true value if the object has the flags defined
*/
#define ftdm_test_flag(obj, flag) ((obj)->flags & flag)
/*!< Physical (IO) module specific flags */
#define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag)
/*!< signaling module specific flags */
#define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag)
#define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag)
@@ -190,17 +192,6 @@ extern "C" {
#define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
#define ftdm_set_state(obj, s) ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
#define ftdm_set_state_locked(obj, s) \
do { \
ftdm_channel_lock(obj); \
ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
ftdm_channel_unlock(obj); \
} while(0);
#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0);
#ifdef _MSC_VER
/* The while(0) below throws a conditional expression is constant warning */
#pragma warning(disable:4127)
@@ -361,15 +352,6 @@ typedef struct {
ftdm_mutex_t *mutex;
} ftdm_dtmf_debug_t;
typedef struct {
const char *file;
const char *func;
int line;
ftdm_channel_state_t state;
ftdm_channel_state_t last_state;
ftdm_time_t time;
} ftdm_channel_history_entry_t;
typedef enum {
FTDM_IOSTATS_ERROR_CRC = (1 << 0),
FTDM_IOSTATS_ERROR_FRAME = (1 << 1),
@@ -411,7 +393,7 @@ struct ftdm_channel {
uint32_t extra_id;
ftdm_chan_type_t type;
ftdm_socket_t sockfd;
uint32_t flags;
uint64_t flags;
uint32_t pflags;
uint32_t sflags;
ftdm_alarm_flag_t alarm_flags;
@@ -422,9 +404,11 @@ struct ftdm_channel {
uint32_t native_interval;
uint32_t packet_len;
ftdm_channel_state_t state;
ftdm_state_status_t state_status;
ftdm_channel_state_t last_state;
ftdm_channel_state_t init_state;
ftdm_channel_history_entry_t history[10];
ftdm_channel_indication_t indication;
ftdm_state_history_entry_t history[10];
uint8_t hindex;
ftdm_mutex_t *mutex;
teletone_dtmf_detect_state_t dtmf_detect;
@@ -456,6 +440,7 @@ struct ftdm_channel {
ftdm_fsk_data_state_t fsk;
uint8_t fsk_buf[80];
uint32_t ring_count;
ftdm_polarity_t polarity;
/* Private I/O data. Do not touch unless you are an I/O module */
void *io_data;
/* Private signaling data. Do not touch unless you are a signaling module */
@@ -477,6 +462,7 @@ struct ftdm_channel {
ftdm_dtmf_debug_t dtmfdbg;
ftdm_io_dump_t rxdump;
ftdm_io_dump_t txdump;
ftdm_interrupt_t *state_completed_interrupt; /*!< Notify when a state change is completed */
int32_t txdrops;
int32_t rxdrops;
};
@@ -493,6 +479,7 @@ struct ftdm_span {
ftdm_trunk_type_t trunk_type;
ftdm_analog_start_type_t start_type;
ftdm_signal_type_t signal_type;
uint32_t last_used_index;
/* Private signaling data. Do not touch unless you are a signaling module */
void *signal_data;
fio_signal_cb_t signal_cb;
@@ -513,15 +500,15 @@ struct ftdm_span {
ftdm_span_stop_t stop;
ftdm_channel_sig_read_t sig_read;
ftdm_channel_sig_write_t sig_write;
/* Private I/O data per span. Do not touch unless you are an I/O module */
void *io_data;
ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */
void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */
char *type;
char *dtmf_hangup;
size_t dtmf_hangup_len;
ftdm_state_map_t *state_map;
ftdm_caller_data_t default_caller_data;
ftdm_queue_t *pendingchans;
ftdm_queue_t *pendingsignals;
ftdm_queue_t *pendingchans; /*!< Channels pending of state processing */
ftdm_queue_t *pendingsignals; /*!< Signals pending from being delivered to the user */
struct ftdm_span *next;
};
@@ -568,11 +555,7 @@ FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *stat
FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number);
FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level);
FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line,
ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait);
FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname);
FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan);
@@ -585,8 +568,6 @@ FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftd
FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2);
FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky);
FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan);
FT_DECLARE(int) ftdm_load_modules(void);
FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void);
@@ -602,6 +583,7 @@ FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void);
FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan);
FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_status_t status);
/*!
* \brief Retrieves an event from the span
@@ -702,50 +684,6 @@ static __inline__ void ftdm_abort(void)
#endif
}
static __inline__ void ftdm_set_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
{
uint32_t j;
ftdm_mutex_lock(span->mutex);
for(j = 1; j <= span->chan_count; j++) {
if (!FTDM_IS_DCHAN(span->channels[j])) {
ftdm_set_state_locked((span->channels[j]), state);
}
}
ftdm_mutex_unlock(span->mutex);
}
static __inline__ int ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
{
uint32_t j;
for(j = 1; j <= span->chan_count; j++) {
if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
return 0;
}
}
return 1;
}
static __inline__ void ftdm_set_flag_all(ftdm_span_t *span, uint32_t flag)
{
uint32_t j;
ftdm_mutex_lock(span->mutex);
for(j = 1; j <= span->chan_count; j++) {
ftdm_set_flag_locked((span->channels[j]), flag);
}
ftdm_mutex_unlock(span->mutex);
}
static __inline__ void ftdm_clear_flag_all(ftdm_span_t *span, uint32_t flag)
{
uint32_t j;
ftdm_mutex_lock(span->mutex);
for(j = 1; j <= span->chan_count; j++) {
ftdm_clear_flag_locked((span->channels[j]), flag);
}
ftdm_mutex_unlock(span->mutex);
}
static __inline__ int16_t ftdm_saturated_add(int16_t sample1, int16_t sample2)
{
int addres;
@@ -1,134 +0,0 @@
/*
* ftdm_m3ua.h
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
//#include "m3ua_client.h"
#include "freetdm.h"
#ifdef __cplusplus
extern "C" {
#endif
enum e_sigboost_event_id_values
{
SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
/* Following IDs are ss7boost to sangoma_mgd only. */
SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
};
enum e_sigboost_release_cause_values
{
SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
SIGBOOST_RELEASE_CAUSE_BUSY = 17,
/* probable elimination */
//SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
//SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
};
enum e_sigboost_call_setup_ack_nack_cause_values
{
SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */
SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */
SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28,
/* probable elimination */
//SIGBOOST_CALL_SETUP_RESERVED = 0x00,
//SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10,
//SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11,
//SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17,
};
typedef enum {
M3UA_SPAN_SIGNALING_M3UA,
M3UA_SPAN_SIGNALING_SS7BOX,
} M3UA_TSpanSignaling;
#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX"
FTDM_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling)
typedef enum {
FTDM_M3UA_RUNNING = (1 << 0)
} ftdm_m3uat_flag_t;
/*typedef struct m3ua_data {
m3uac_connection_t mcon;
m3uac_connection_t pcon;
fio_signal_cb_t signal_cb;
uint32_t flags;
} m3ua_data_t;
*/
/*typedef struct mu3a_link {
ss7bc_connection_t mcon;
ss7bc_connection_t pcon;
fio_signal_cb_t signal_cb;
uint32_t flags;
} ftdm_m3ua_data_t;
*/
ftdm_status_t m3ua_init(ftdm_io_interface_t **zint);
ftdm_status_t m3ua_destroy(void);
ftdm_status_t m3ua_start(ftdm_span_t *span);
#ifdef __cplusplus
}
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
@@ -0,0 +1,237 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
#ifndef __FTDM_STATE_H__
#define __FTDM_STATE_H__
/*! \file
* \brief State handling definitions
* \note Most, if not all of the state handling functions assume you have a lock acquired. Touching the channel
* state is a sensitive matter that requires checks and careful thought and is typically a process that
* is not encapsulated within a single function, therefore the lock must be explicitly acquired by the
* caller (most of the time, signaling modules), process states, set a new state and process it, and
* finally unlock the channel. See docs/locking.txt fore more info
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
FTDM_CHANNEL_STATE_DOWN,
FTDM_CHANNEL_STATE_HOLD,
FTDM_CHANNEL_STATE_SUSPENDED,
FTDM_CHANNEL_STATE_DIALTONE,
FTDM_CHANNEL_STATE_COLLECT,
FTDM_CHANNEL_STATE_RING,
FTDM_CHANNEL_STATE_RINGING,
FTDM_CHANNEL_STATE_BUSY,
FTDM_CHANNEL_STATE_ATTN,
FTDM_CHANNEL_STATE_GENRING,
FTDM_CHANNEL_STATE_DIALING,
FTDM_CHANNEL_STATE_GET_CALLERID,
FTDM_CHANNEL_STATE_CALLWAITING,
FTDM_CHANNEL_STATE_RESTART,
FTDM_CHANNEL_STATE_PROCEED,
FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_IDLE,
FTDM_CHANNEL_STATE_TERMINATING,
FTDM_CHANNEL_STATE_CANCEL,
FTDM_CHANNEL_STATE_HANGUP,
FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
FTDM_CHANNEL_STATE_IN_LOOP,
FTDM_CHANNEL_STATE_RESET,
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
typedef struct {
const char *file;
const char *func;
int line;
ftdm_channel_state_t state; /*!< Current state (processed or not) */
ftdm_channel_state_t last_state; /*!< Previous state */
ftdm_time_t time; /*!< Time the state was set */
ftdm_time_t end_time; /*!< Time the state processing was completed */
} ftdm_state_history_entry_t;
typedef ftdm_status_t (*ftdm_channel_state_processor_t)(ftdm_channel_t *fchan);
/*!
* \brief Process channel states by invoking the channel state processing routine
* it will keep calling the processing routine while the state status
* is FTDM_STATE_STATUS_NEW, it will not do anything otherwise
*/
FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan);
FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *function, int line, ftdm_channel_t *fchan);
#define ftdm_channel_complete_state(obj) _ftdm_channel_complete_state(__FILE__, __FUNCTION__, __LINE__, obj)
FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state);
/*!
* \brief Status of the current channel state
* \note A given state goes thru several status (yes, states for the state!)
* The order is always FTDM_STATE_STATUS_NEW -> FTDM_STATE_STATUS_PROCESSED -> FTDM_STATUS_COMPLETED
* However, is possible to go from NEW -> COMPLETED directly when the signaling module explicitly changes
* the state of the channel in the middle of processing the current state by calling the ftdm_set_state() API
*
* FTDM_STATE_STATUS_NEW -
* Someone just set the state of the channel, either the signaling module or the user (implicitly through a call API).
* This is accomplished by calling ftdm_channel_set_state() which changes the 'state' and 'last_state' memebers of
* the ftdm_channel_t structure.
*
* FTDM_STATE_STATUS_PROCESSED -
* The signaling module did something based on the new state.
*
* This is accomplished via ftdm_channel_advance_states()
*
* When ftdm_channel_advance_states(), at the very least, if the channel has its state in FTDM_STATE_STATUS_NEW, it
* will move to FTDM_STATE_STATUS_PROCESSED, depending on what the signaling module does during the processing
* the state may move to FTDM_STATE_STATUS_COMPLETED right after or wait for a signaling specific event to complete it.
* It is also possible that more state transitions occur during the execution of ftdm_channel_advance_states() if one
* state processing/completion leads to another state change, the function will not return until the chain of events
* lead to a state that is not in FTDM_STATE_STATUS_NEW
*
* FTDM_STATE_STATUS_COMPLETED -
* The signaling module completed the processing of the state and there is nothing further to be done for this state.
*
* This is accomplished either explicitly by the signaling module by calling ftdm_channel_complete_state() or by
* the signaling module implicitly by trying to set the state of the channel to a new state via ftdm_set_state()
*
* When working with blocking channels (FTDM_CHANNEL_NONBLOCK flag not set), the user thread is signaled and unblocked
* so it can continue.
*
* When a state moves to this status is also possible for a signal FTDM_SIGEVENT_INDICATION_COMPLETED to be delivered
* by the core if the state change was associated to an indication requested by the user,
*/
typedef enum {
FTDM_STATE_STATUS_NEW,
FTDM_STATE_STATUS_PROCESSED,
FTDM_STATE_STATUS_COMPLETED,
FTDM_STATE_STATUS_INVALID
} ftdm_state_status_t;
#define CHANNEL_STATE_STATUS_STRINGS "NEW", "PROCESSED", "COMPLETED", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t)
typedef enum {
ZSM_NONE,
ZSM_UNACCEPTABLE,
ZSM_ACCEPTABLE
} ftdm_state_map_type_t;
typedef enum {
ZSD_INBOUND,
ZSD_OUTBOUND,
} ftdm_state_direction_t;
#define FTDM_MAP_NODE_SIZE 512
#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
struct ftdm_state_map_node {
ftdm_state_direction_t direction;
ftdm_state_map_type_t type;
ftdm_channel_state_t check_states[FTDM_MAP_MAX];
ftdm_channel_state_t states[FTDM_MAP_MAX];
};
typedef struct ftdm_state_map_node ftdm_state_map_node_t;
struct ftdm_state_map {
ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
};
typedef struct ftdm_state_map ftdm_state_map_t;
/*!\brief Set the state for a channel (the channel must be locked when calling this function)
* \note Signaling modules should use ftdm_set_state macro instead
* \note If this function is called with the wait parameter set to a non-zero value, the recursivity
* of the channel lock must be == 1 because the channel will be unlocked/locked when waiting */
FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line,
ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait);
/*!\brief Set the state of a channel immediately and implicitly complete the previous state if needed
* \note FTDM_SIGEVENT_INDICATION_COMPLETED will be sent if the state change
* is associated to some indication (ie FTDM_CHANNEL_INDICATE_PROCEED)
* \note The channel must be locked when calling this function
* */
FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line,
ftdm_channel_t *fchan, ftdm_channel_state_t state);
#define ftdm_set_state(obj, s) _ftdm_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s); \
/*!\brief This macro is deprecated, signaling modules should always lock the channel themselves anyways since they must
* process first the user pending state changes then set a new state before releasing the lock
* this macro is here for backwards compatibility, DO NOT USE IT in new code since it is *always* wrong to set
* a state in a signaling module without checking and processing the current state first (and for that you must lock the channel)
*/
#define ftdm_set_state_locked(obj, s) \
do { \
ftdm_channel_lock(obj); \
ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
ftdm_channel_unlock(obj); \
} while(0);
#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0);
#define ftdm_set_state_all(span, state) \
do { \
uint32_t _j; \
ftdm_mutex_lock((span)->mutex); \
for(_j = 1; _j <= (span)->chan_count; _j++) { \
if (!FTDM_IS_DCHAN(span->channels[_j])) { \
ftdm_set_state_locked((span->channels[_j]), state); \
} \
} \
ftdm_mutex_unlock((span)->mutex); \
} while (0);
#ifdef __cplusplus
}
#endif
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
+51 -109
View File
@@ -69,8 +69,6 @@ extern "C" {
#define FTDM_END -1
#define FTDM_ANY_STATE -1
typedef uint64_t ftdm_time_t;
typedef enum {
FTDM_ENDIAN_BIG = 1,
FTDM_ENDIAN_LITTLE = -1
@@ -123,6 +121,7 @@ typedef enum {
FTDM_STR2ENUM_P(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t)
typedef enum {
FTDM_OOB_NOOP,
FTDM_OOB_ONHOOK,
FTDM_OOB_OFFHOOK,
FTDM_OOB_WINK,
@@ -131,11 +130,11 @@ typedef enum {
FTDM_OOB_RING_STOP,
FTDM_OOB_ALARM_TRAP,
FTDM_OOB_ALARM_CLEAR,
FTDM_OOB_NOOP,
FTDM_OOB_CAS_BITS_CHANGE,
FTDM_OOB_POLARITY_REVERSE,
FTDM_OOB_INVALID
} ftdm_oob_event_t;
#define OOB_STRINGS "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
#define OOB_STRINGS "NOOP", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "CAS_BITS_CHANGE", "POLARITY_REVERSE", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t)
/*! \brief Event types */
@@ -169,7 +168,7 @@ typedef enum {
typedef enum {
FTDM_SPAN_CONFIGURED = (1 << 0),
FTDM_SPAN_READY = (1 << 1),
FTDM_SPAN_STARTED = (1 << 1),
FTDM_SPAN_STATE_CHANGE = (1 << 2),
FTDM_SPAN_SUSPENDED = (1 << 3),
FTDM_SPAN_IN_THREAD = (1 << 4),
@@ -203,113 +202,56 @@ typedef enum {
FTDM_CHANNEL_FEATURE_IO_STATS = (1<<9), /*!< Channel supports IO statistics (HDLC channels only) */
} ftdm_channel_feature_t;
typedef enum {
FTDM_CHANNEL_STATE_DOWN,
FTDM_CHANNEL_STATE_HOLD,
FTDM_CHANNEL_STATE_SUSPENDED,
FTDM_CHANNEL_STATE_DIALTONE,
FTDM_CHANNEL_STATE_COLLECT,
FTDM_CHANNEL_STATE_RING,
FTDM_CHANNEL_STATE_RINGING,
FTDM_CHANNEL_STATE_BUSY,
FTDM_CHANNEL_STATE_ATTN,
FTDM_CHANNEL_STATE_GENRING,
FTDM_CHANNEL_STATE_DIALING,
FTDM_CHANNEL_STATE_GET_CALLERID,
FTDM_CHANNEL_STATE_CALLWAITING,
FTDM_CHANNEL_STATE_RESTART,
FTDM_CHANNEL_STATE_PROCEED,
FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_IDLE,
FTDM_CHANNEL_STATE_TERMINATING,
FTDM_CHANNEL_STATE_CANCEL,
FTDM_CHANNEL_STATE_HANGUP,
FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
FTDM_CHANNEL_STATE_IN_LOOP,
FTDM_CHANNEL_STATE_RESET,
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
/*!< Channel flags. This used to be an enum but we reached the 32bit limit for enums, is safer this way */
#define FTDM_CHANNEL_CONFIGURED (1ULL << 0)
#define FTDM_CHANNEL_READY (1ULL << 1)
#define FTDM_CHANNEL_OPEN (1ULL << 2)
#define FTDM_CHANNEL_DTMF_DETECT (1ULL << 3)
#define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4)
#define FTDM_CHANNEL_TRANSCODE (1ULL << 5)
#define FTDM_CHANNEL_BUFFER (1ULL << 6)
#define FTDM_CHANNEL_EVENT (1ULL << 7)
#define FTDM_CHANNEL_INTHREAD (1ULL << 8)
#define FTDM_CHANNEL_WINK (1ULL << 9)
#define FTDM_CHANNEL_FLASH (1ULL << 10)
#define FTDM_CHANNEL_STATE_CHANGE (1ULL << 11)
#define FTDM_CHANNEL_HOLD (1ULL << 12)
#define FTDM_CHANNEL_INUSE (1ULL << 13)
#define FTDM_CHANNEL_OFFHOOK (1ULL << 14)
#define FTDM_CHANNEL_RINGING (1ULL << 15)
#define FTDM_CHANNEL_PROGRESS_DETECT (1ULL << 16)
#define FTDM_CHANNEL_CALLERID_DETECT (1ULL << 17)
#define FTDM_CHANNEL_OUTBOUND (1ULL << 18)
#define FTDM_CHANNEL_SUSPENDED (1ULL << 19)
#define FTDM_CHANNEL_3WAY (1ULL << 20)
typedef enum {
FTDM_CHANNEL_CONFIGURED = (1 << 0),
FTDM_CHANNEL_READY = (1 << 1),
FTDM_CHANNEL_OPEN = (1 << 2),
FTDM_CHANNEL_DTMF_DETECT = (1 << 3),
FTDM_CHANNEL_SUPRESS_DTMF = (1 << 4),
FTDM_CHANNEL_TRANSCODE = (1 << 5),
FTDM_CHANNEL_BUFFER = (1 << 6),
FTDM_CHANNEL_EVENT = (1 << 7),
FTDM_CHANNEL_INTHREAD = (1 << 8),
FTDM_CHANNEL_WINK = (1 << 9),
FTDM_CHANNEL_FLASH = (1 << 10),
FTDM_CHANNEL_STATE_CHANGE = (1 << 11),
FTDM_CHANNEL_HOLD = (1 << 12),
FTDM_CHANNEL_INUSE = (1 << 13),
FTDM_CHANNEL_OFFHOOK = (1 << 14),
FTDM_CHANNEL_RINGING = (1 << 15),
FTDM_CHANNEL_PROGRESS_DETECT = (1 << 16),
FTDM_CHANNEL_CALLERID_DETECT = (1 << 17),
FTDM_CHANNEL_OUTBOUND = (1 << 18),
FTDM_CHANNEL_SUSPENDED = (1 << 19),
FTDM_CHANNEL_3WAY = (1 << 20),
FTDM_CHANNEL_PROGRESS = (1 << 21),
FTDM_CHANNEL_MEDIA = (1 << 22),
FTDM_CHANNEL_ANSWERED = (1 << 23),
FTDM_CHANNEL_MUTE = (1 << 24),
FTDM_CHANNEL_USE_RX_GAIN = (1 << 25),
FTDM_CHANNEL_USE_TX_GAIN = (1 << 26),
FTDM_CHANNEL_IN_ALARM = (1 << 27),
FTDM_CHANNEL_SIG_UP = (1 << 28),
FTDM_CHANNEL_USER_HANGUP = (1 << 29),
FTDM_CHANNEL_RX_DISABLED = (1 << 30),
FTDM_CHANNEL_TX_DISABLED = (1 << 31),
/* ok, when we reach 32, we need to move to uint64_t all the flag stuff */
} ftdm_channel_flag_t;
#if defined(__cplusplus) && defined(WIN32)
// fix C2676
__inline__ ftdm_channel_flag_t operator|=(ftdm_channel_flag_t a, int32_t b) {
a = (ftdm_channel_flag_t)(a | b);
return a;
}
__inline__ ftdm_channel_flag_t operator&=(ftdm_channel_flag_t a, int32_t b) {
a = (ftdm_channel_flag_t)(a & b);
return a;
}
#endif
/* this 3 flags are really nonsense used by boost module only, as soon
* as we deprecate/delete boost module we can get rid of them
* ==================
* */
#define FTDM_CHANNEL_PROGRESS (1ULL << 21)
#define FTDM_CHANNEL_MEDIA (1ULL << 22)
#define FTDM_CHANNEL_ANSWERED (1ULL << 23)
/* ================== */
typedef enum {
ZSM_NONE,
ZSM_UNACCEPTABLE,
ZSM_ACCEPTABLE
} ftdm_state_map_type_t;
#define FTDM_CHANNEL_MUTE (1ULL << 24)
#define FTDM_CHANNEL_USE_RX_GAIN (1ULL << 25)
#define FTDM_CHANNEL_USE_TX_GAIN (1ULL << 26)
#define FTDM_CHANNEL_IN_ALARM (1ULL << 27)
#define FTDM_CHANNEL_SIG_UP (1ULL << 28)
#define FTDM_CHANNEL_USER_HANGUP (1ULL << 29)
#define FTDM_CHANNEL_RX_DISABLED (1ULL << 30)
#define FTDM_CHANNEL_TX_DISABLED (1ULL << 31)
/*!< The user knows about a call in this channel */
#define FTDM_CHANNEL_CALL_STARTED (1ULL << 32)
/*!< The user wants non-blocking operations in the channel */
#define FTDM_CHANNEL_NONBLOCK (1ULL << 33)
/*!< There is a pending acknowledge for an indication */
#define FTDM_CHANNEL_IND_ACK_PENDING (1ULL << 34)
/*!< There is someone blocking in the channel waiting for state completion */
#define FTDM_CHANNEL_BLOCKING (1ULL << 35)
typedef enum {
ZSD_INBOUND,
ZSD_OUTBOUND,
} ftdm_state_direction_t;
#define FTDM_MAP_NODE_SIZE 512
#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
struct ftdm_state_map_node {
ftdm_state_direction_t direction;
ftdm_state_map_type_t type;
ftdm_channel_state_t check_states[FTDM_MAP_MAX];
ftdm_channel_state_t states[FTDM_MAP_MAX];
};
typedef struct ftdm_state_map_node ftdm_state_map_node_t;
struct ftdm_state_map {
ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
};
typedef struct ftdm_state_map ftdm_state_map_t;
#include "ftdm_state.h"
typedef enum ftdm_channel_hw_link_status {
FTDM_HW_LINK_DISCONNECTED = 0,
-62
View File
@@ -1,62 +0,0 @@
/* WARNING WORK IN PROGRESS
* mstm3ua.c
* mstss7d port
*
* Created by Shane Burrell on 2/2/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
#include "mstm3ua.h"
int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg)
{
*bytemsg++ = M_VERSION_REL1; // 1 Verison
//bytemsg[1] = 0x00; // 2 RESERVED
//bytemsg[2] = M_CLASS_XFER; // 3 Msg Class
//SS7 BOX Kludge
*bytemsg++ = 0x01; // 2 RESERVED
*bytemsg++ = 0x00; // 2 RESERVED
*bytemsg++ = M_TYPE_DATA ; // 4 Msg Type
*bytemsg++ = len; // 5 Msg LENGTH 81 32bit field
*bytemsg++ = 0x00; // 6
*bytemsg++ = 0x00; // 7
*bytemsg++ = 0x00; // 8
return(0);
};
-96
View File
@@ -1,96 +0,0 @@
/*
* mstm3ua.h
* mstss7d
*
* Created by Shane Burrell on 3/2/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
typedef unsigned long m3ua_ulong;
typedef unsigned short m3ua_ushort;
typedef unsigned char m3ua_uchar;
typedef unsigned char u8;
typedef unsigned short u16; /* Note: multi-byte values are little-endian */
typedef unsigned long u32;
#define M_TAG_NETWORK_APPEARANCE 1
#define M_TAG_PROTOCOL_DATA 3
#define M_TAG_INFO_STRING 4
#define M_TAG_AFFECTED_DPC 5
#define M_TAG_ROUTING_CONTEXT 6
#define M_TAG_DIAGNOSTIC_INFORMATION 7
#define M_TAG_HEARTBEAT_DATA 8
#define M_TAG_UNAVAILABILITY_CAUSE 9
#define M_TAG_REASON 10
#define M_TAG_TRAFFIC_MODE_TYPE 11
#define M_TAG_ERROR_CODE 12
#define M_TAG_STATUS_TYPE 13
#define M_TAG_CONGESTED_INDICATIONS 14
#define M_VERSION_REL1 1
#define M_CLASS_MGMT 0x00
#define M_CLASS_XFER 0x01
#define M_CLASS_SSNM 0x02
#define M_CLASS_ASPSM 0x03
#define M_CLASS_ASPTM 0x04
#define M_CLASS_RKM 0x09
#define M_TYPE_ERR (0|M_CLASS_MGMT
#define M_TYPE_NTFY (1|M_CLASS_XFER)
#define M_TYPE_DATA (1|M_CLASS_XFER)
#define M_TYPE_DUNA (1|M_CLASS_SSNM)
#define M_TYPE_DAVA (2|M_CLASS_SSNM)
#define M_TYPE_DUAD (3|M_CLASS_SSNM)
#define M_TYPE_SCON (4|M_CLASS_SSNM)
#define M_TYPE_DUPU (5|M_CLASS_SSNM)
#define M_TYPE_UP (1|M_CLASS_ASPSM)
#define M_TYPE_DOWN (2|M_CLASS_ASPSM)
#define M_TYPE_BEAT (3|M_CLASS_ASPSM)
#define M_TYPE_UP_ACK (4|M_CLASS_ASPSM)
#define M_TYPE_DOWN_ACK (5|M_CLASS_ASPSM)
#define M_TYPE_BEAT_ACK (6|M_CLASS_ASPSM)
#define M_TYPE_ACTIVE (1|M_CLASS_ASPTM)
#define M_TYPE_INACTIVE (2|M_CLASS_ASPTM)
#define M_TYPE_ACTIVE_ACK (3|M_CLASS_ASPTM)
#define M_TYPE_INACTIVE_ACK (4|M_CLASS_ASPTM)
#define M_CLASS_MASK 0xff00
#define M_TYPE_MASK 0x00ff
-333
View File
@@ -1,333 +0,0 @@
/*
* m3ua_client.c
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#include "freetdm.h"
#include <m3ua_client.h>
#ifndef HAVE_GETHOSTBYNAME_R
extern int gethostbyname_r (const char *__name,
struct hostent *__result_buf,
char *__buf, size_t __buflen,
struct hostent **__result,
int *__h_errnop);
#endif
struct m3uac_map {
uint32_t event_id;
const char *name;
};
static struct m3uac_map m3uac_table[] = {
{M3UA_EVENT_CALL_START, "CALL_START"},
{M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"},
{M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"},
{M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
{M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
{M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"},
{M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
{M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
{M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
{M3UA_EVENT_HEARTBEAT, "HEARTBEAT"},
{M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
{M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"}
};
static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
{
int rc;
struct hostent *result, *local_result;
char buf[512], local_buf[512];
int err = 0;
memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
ftdm_log(FTDM_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
local_ip,local_port,ip,port);
if (mcon->socket >= 0) {
int flag;
flag = 1;
gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err);
if (result && local_result) {
mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
mcon->remote_addr.sin_port = htons(port);
mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
mcon->local_addr.sin_port = htons(local_port);
setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int));
rc=listen(mcon->socket,100);
if (rc) {
close(mcon->socket);
mcon->socket = -1;
}
}
}
ftdm_mutex_create(&mcon->mutex);
return mcon->socket;
}
int m3uac_connection_close(m3uac_connection_t *mcon)
{
if (mcon->socket > -1) {
close(mcon->socket);
}
ftdm_mutex_lock(mcon->mutex);
ftdm_mutex_unlock(mcon->mutex);
ftdm_mutex_destroy(&mcon->mutex);
memset(mcon, 0, sizeof(*mcon));
mcon->socket = -1;
return 0;
}
int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
{
create_conn_socket(mcon, local_ip, local_port, ip, port);
return mcon->socket;
}
int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
{
m3uac_event_t oevent;
int retry = 5;
m3uac_event_init(&oevent, cmd, chan, span);
oevent.release_cause = cause;
if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) {
mcon->rxseq_reset = 1;
mcon->txseq = 0;
mcon->rxseq = 0;
mcon->txwindow = 0;
}
if (id >= 0) {
oevent.call_setup_id = id;
}
while (m3uac_connection_write(mcon, &oevent) <= 0) {
if (--retry <= 0) {
ftdm_log(FTDM_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno));
return -1;
} else {
ftdm_log(FTDM_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry);
ftdm_sleep(1);
}
}
return 0;
}
m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration)
{
unsigned int fromlen = sizeof(struct sockaddr_in);
int bytes = 0;
bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
(struct sockaddr *) &mcon->local_addr, &fromlen);
if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
if (mcon->rxseq_reset) {
if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n");
mcon->rxseq = mcon->event.fseqno;
return &mcon->event;
}
errno=EAGAIN;
ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n");
return NULL;
}
mcon->txwindow = mcon->txseq - mcon->event.bseqno;
mcon->rxseq++;
if (mcon->rxseq != mcon->event.fseqno) {
ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
return NULL;
}
return &mcon->event;
} else {
if (iteration == 0) {
ftdm_log(FTDM_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
return NULL;
}
}
return NULL;
}
m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration)
{
unsigned int fromlen = sizeof(struct sockaddr_in);
int bytes = 0;
bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
return &mcon->event;
} else {
if (iteration == 0) {
ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
return NULL;
}
}
return NULL;
}
int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event)
{
int err;
if (!event || mcon->socket < 0 || !mcon->mutex) {
ftdm_log(FTDM_LOG_DEBUG, "Critical Error: No Event Device\n");
return -EINVAL;
}
if (event->span > 16 || event->chan > 31) {
ftdm_log(FTDM_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan);
return -1;
}
gettimeofday(&event->tv,NULL);
ftdm_mutex_lock(mcon->mutex);
event->fseqno = mcon->txseq++;
event->bseqno = mcon->rxseq;
err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
ftdm_mutex_unlock(mcon->mutex);
if (err != sizeof(m3uac_event_t)) {
err = -1;
}
ftdm_log(FTDM_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
m3uac_event_id_name(event->event_id),
event->event_id,
event->span+1,
event->chan+1,
event->release_cause,
event->call_setup_id,
event->fseqno,
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
);
return err;
}
void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id)
{
memset(event, 0, sizeof(m3uac_event_t));
event->event_id = M3UA_EVENT_CALL_START;
if (calling) {
strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
event->calling_number_digits_count = strlen(calling);
}
if (called) {
strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
event->called_number_digits_count = strlen(called);
}
event->call_setup_id = setup_id;
}
void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span)
{
memset(event, 0, sizeof(ss7bc_event_t));
event->event_id = event_id;
event->chan = chan;
event->span = span;
}
const char *m3uac_event_id_name(uint32_t event_id)
{
unsigned int x;
const char *ret = NULL;
for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) {
if (m3uac_table[x].event_id == event_id) {
ret = m3uac_table[x].name;
break;
}
}
return ret;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
-164
View File
@@ -1,164 +0,0 @@
/*
* m3ua_client.h
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* 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.
*/
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
// Fix this for portability
#include <sctp.h>
//#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include <netdb.h>
//#include <sigboost.h>
#include <sys/time.h>
#define MAX_DIALED_DIGITS 31
#define MAX_CALLING_NAME 31
/* Next two defines are used to create the range of values for call_setup_id
* in the t_sigboost structure.
* 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
#define CORE_MAX_SPANS 200
#define CORE_MAX_CHAN_PER_SPAN 30
#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
#define SIZE_RDNIS 80
//#undef MSGWINDOW
#define MSGWINDOW
typedef struct
{
uint32_t event_id;
uint32_t fseqno;
#ifdef MSGWINDOW
uint32_t bseqno;
#endif
uint16_t call_setup_id;
uint32_t trunk_group;
uint32_t span;
uint32_t chan;
uint8_t called_number_digits_count;
char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
uint8_t calling_number_digits_count; /* it's an array */
char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
uint8_t release_cause;
struct timeval tv;
/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
uint8_t calling_number_screening_ind;
uint8_t calling_number_presentation;
char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
} t_m3ua;
typedef t_m3ua m3uac_event_t;
typedef uint32_t m3uac_event_id_t;
typedef struct m3uac_ip_cfg
{
char local_ip[25];
int local_port;
char remote_ip[25];
int remote_port;
}m3uac_ip_cfg_t;
struct m3uac_connection {
ftdm_socket_t socket;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
m3uac_event_t event;
struct hostent remote_hp;
struct hostent local_hp;
unsigned int flags;
ftdm_mutex_t *mutex;
FILE *log;
unsigned int txseq;
unsigned int rxseq;
unsigned int txwindow;
unsigned int rxseq_reset;
m3uac_ip_cfg_t cfg;
uint32_t hb_elapsed;
int up;
};
typedef enum {
MSU_FLAG_EVENT = (1 << 0)
} m3uac_flag_t;
typedef struct m3uac_connection m3uac_connection_t;
static inline void sctp_no_nagle(int socket)
{
//int flag = 1;
//setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
}
int m3uac_connection_close(m3uac_connection_t *mcon);
int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration);
m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration);
int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event);
void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span);
void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id);
const char *m3uac_event_id_name(uint32_t event_id);
int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
-60
View File
@@ -1,60 +0,0 @@
/*
* testm3ua.c
* freetdm
*
* Created by Shane Burrell on 4/8/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#include "testm3ua.h"
#include "freetdm.h"
#include "ftdm_m3ua.h"
static FIO_SIGNAL_CB_FUNCTION(on_signal)
{
return FTDM_FAIL;
}
int main(int argc, char *argv[])
{
ftdm_span_t *span;
//m3ua_data_t *data;
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
if (argc < 5) {
printf("more args needed\n");
exit(-1);
}
if (ftdm_global_init() != FTDM_SUCCESS) {
fprintf(stderr, "Error loading FreeTDM\n");
exit(-1);
}
printf("FreeTDM loaded\n");
if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
fprintf(stderr, "Error finding FreeTDM span\n");
goto done;
}
if (ftdm_m3ua_configure_span(span) == FTDM_SUCCESS) {
//data = span->signal_data;
ftdm_m3ua_start(span);
} else {
fprintf(stderr, "Error starting M3UA\n");
goto done;
}
//while(ftdm_test_flag(data, FTDM_M3UA_RUNNING)) {
// ftdm_sleep(1 * 1000);
//}
done:
ftdm_global_destroy();
}
+112 -32
View File
@@ -2,78 +2,158 @@
#include <signal.h>
#include <stdlib.h>
static int R = 0;
static ftdm_mutex_t *mutex = NULL;
static volatile int running = 0;
static ftdm_mutex_t *the_mutex = NULL;
static ftdm_channel_t *fchan = NULL;
static ftdm_channel_indication_t indication = FTDM_CHANNEL_INDICATE_NONE;
static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
{
int chanid = ftdm_channel_get_ph_id(sigmsg->channel);
ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
return FTDM_SUCCESS;
ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
switch (sigmsg->event_id) {
case FTDM_SIGEVENT_START:
{
ftdm_mutex_lock(the_mutex);
if (!fchan) {
fchan = sigmsg->channel;
indication = FTDM_CHANNEL_INDICATE_PROCEED;
}
ftdm_mutex_unlock(the_mutex);
}
break;
case FTDM_SIGEVENT_INDICATION_COMPLETED:
{
ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROCEED) {
ftdm_log(FTDM_LOG_DEBUG, "Proceed indication result = %d\n", sigmsg->ev_data.indication_completed.status);
ind = FTDM_CHANNEL_INDICATE_PROGRESS;
} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS) {
ftdm_log(FTDM_LOG_DEBUG, "Progress indication result = %d\n", sigmsg->ev_data.indication_completed.status);
ind = FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA;
} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA) {
ftdm_log(FTDM_LOG_DEBUG, "Progress media indication result = %d\n", sigmsg->ev_data.indication_completed.status);
ind = FTDM_CHANNEL_INDICATE_ANSWER;
} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_ANSWER) {
ftdm_log(FTDM_LOG_DEBUG, "Answer indication result = %d\n", sigmsg->ev_data.indication_completed.status);
} else {
ftdm_log(FTDM_LOG_DEBUG, "Unexpected indication, result = %d\n", sigmsg->ev_data.indication_completed.status);
exit(1);
}
ftdm_mutex_lock(the_mutex);
if (fchan) {
indication = ind;
}
ftdm_mutex_unlock(the_mutex);
}
break;
case FTDM_SIGEVENT_STOP:
{
ftdm_channel_call_hangup(sigmsg->channel);
}
break;
case FTDM_SIGEVENT_RELEASED:
{
ftdm_mutex_lock(the_mutex);
if (fchan && fchan == sigmsg->channel) {
fchan = NULL;
}
ftdm_mutex_unlock(the_mutex);
}
break;
default:
break;
}
return FTDM_SUCCESS;
}
static void handle_SIGINT(int sig)
static void stop_test(int sig)
{
ftdm_mutex_lock(mutex);
R = 0;
ftdm_mutex_unlock(mutex);
return;
running = 0;
}
int main(int argc, char *argv[])
{
ftdm_span_t *span;
ftdm_mutex_create(&mutex);
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
ftdm_conf_parameter_t parameters[20];
ftdm_mutex_create(&the_mutex);
if (argc < 2) {
printf("umm no\n");
exit(-1);
exit(1);
}
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
if (ftdm_global_init() != FTDM_SUCCESS) {
fprintf(stderr, "Error loading FreeTDM\n");
exit(-1);
exit(1);
}
ftdm_global_configuration();
printf("FreeTDM loaded\n");
if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
fprintf(stderr, "Error finding FreeTDM span\n");
if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
goto done;
}
/* testing non-blocking operation */
//ftdm_span_set_blocking_mode(span, FTDM_FALSE);
parameters[0].var = "variant";
parameters[0].val = "br";
if (ftdm_configure_span(span, "r2", on_r2_signal,
"variant", "mx",
"max_ani", 10,
"max_dnis", 4,
"logging", "all",
FTDM_TAG_END) == FTDM_SUCCESS) {
parameters[1].var = "max_ani";
parameters[1].val = "4";
parameters[2].var = "max_dnis";
parameters[2].val = "4";
parameters[3].var = "logging";
parameters[3].val = "all";
parameters[4].var = NULL;
parameters[4].val = NULL;
if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, parameters) == FTDM_SUCCESS) {
ftdm_span_start(span);
} else {
fprintf(stderr, "Error starting R2 span\n");
goto done;
}
signal(SIGINT, handle_SIGINT);
ftdm_mutex_lock(mutex);
R = 1;
ftdm_mutex_unlock(mutex);
while(R) {
ftdm_sleep(1 * 1000);
running = 1;
signal(SIGINT, stop_test);
while(running) {
ftdm_sleep(20);
if (fchan && indication != FTDM_CHANNEL_INDICATE_NONE) {
ftdm_channel_t *lchan = NULL;
ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
ftdm_time_t start, stop, diff;
ftdm_mutex_lock(the_mutex);
ind = indication;
indication = FTDM_CHANNEL_INDICATE_NONE;
lchan = fchan;
ftdm_mutex_unlock(the_mutex);
start = ftdm_current_time_in_ms();
ftdm_channel_call_indicate(lchan, ind);
stop = ftdm_current_time_in_ms();
diff = stop - start;
ftdm_log(FTDM_LOG_DEBUG, "Setting indication %s took %llums\n",
ftdm_channel_indication2str(ind), diff);
}
}
done:
done:
ftdm_global_destroy();
return 1;
return 0;
}
/* For Emacs: