diff --git a/libs/freetdm/freetdm.2008.sln b/libs/freetdm/freetdm.2008.sln
index 61f631f5c0..4d1f019987 100644
--- a/libs/freetdm/freetdm.2008.sln
+++ b/libs/freetdm/freetdm.2008.sln
@@ -63,6 +63,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\f
{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.vcproj", "{94F04D58-5EB8-4B48-8FE5-75EBF468073B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2008.vcproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -158,6 +162,18 @@ Global
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32
+ {94F04D58-5EB8-4B48-8FE5-75EBF468073B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {94F04D58-5EB8-4B48-8FE5-75EBF468073B}.Debug|Win32.Build.0 = Debug|Win32
+ {94F04D58-5EB8-4B48-8FE5-75EBF468073B}.Debug|x64.ActiveCfg = Debug|Win32
+ {94F04D58-5EB8-4B48-8FE5-75EBF468073B}.Release|Win32.ActiveCfg = Release|Win32
+ {94F04D58-5EB8-4B48-8FE5-75EBF468073B}.Release|Win32.Build.0 = Release|Win32
+ {94F04D58-5EB8-4B48-8FE5-75EBF468073B}.Release|x64.ActiveCfg = Release|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 3ad4393ab5..b7b8e040d6 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -2007,6 +2007,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
break;
case FTDM_SIGEVENT_PROGRESS:
+ case FTDM_SIGEVENT_PROGRESS_MEDIA:
{
if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
channel = switch_core_session_get_channel(session);
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 99c0c86ed5..f02c9c48db 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -928,12 +928,12 @@ FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span)
}
-FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms)
+FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms, short *poll_events)
{
assert(span->fio != NULL);
if (span->fio->poll_event) {
- return span->fio->poll_event(span, ms);
+ return span->fio->poll_event(span, ms, poll_events);
} else {
ftdm_log(FTDM_LOG_ERROR, "poll_event method not implemented in module %s!", span->fio->name);
}
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index 4dce1904ac..dacda7e448 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -966,7 +966,7 @@ static void *ftdm_analog_run(ftdm_thread_t *me, void *obj)
int waitms = 1000;
ftdm_status_t status;
- if ((status = ftdm_span_poll_event(span, waitms)) != FTDM_FAIL) {
+ if ((status = ftdm_span_poll_event(span, waitms, NULL)) != FTDM_FAIL) {
errs = 0;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
index 081665b3fc..199bba43a3 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
@@ -657,7 +657,7 @@ static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj)
int waitms = 10;
ftdm_status_t status;
- status = ftdm_span_poll_event(span, waitms);
+ status = ftdm_span_poll_event(span, waitms, NULL);
switch(status) {
case FTDM_SUCCESS:
diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c
index 3715e9844c..65c9dfc11f 100644
--- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c
@@ -1558,7 +1558,7 @@ static __inline__ void check_events(ftdm_span_t *span)
{
ftdm_status_t status;
- status = ftdm_span_poll_event(span, 5);
+ status = ftdm_span_poll_event(span, 5, NULL);
switch(status) {
case FTDM_SUCCESS:
diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
index 444b907911..a7135aab0d 100644
--- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
+++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
@@ -907,7 +907,7 @@ static __inline__ void check_events(ftdm_span_t *span)
{
ftdm_status_t status;
- status = ftdm_span_poll_event(span, 5);
+ status = ftdm_span_poll_event(span, 5, NULL);
switch(status) {
case FTDM_SUCCESS:
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj
new file mode 100644
index 0000000000..9ea351ba6a
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
index 564a812496..df9e7736d5 100644
--- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
@@ -32,23 +32,36 @@
*/
#include
+#ifdef __linux__
+#include
+#include
+#endif
#include
+#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 users kills a span we clear this flag to kill the signaling thread */
/* FIXME: what about the calls that are already up-and-running? */
typedef enum {
FTDM_R2_RUNNING = (1 << 0),
} ftdm_r2_flag_t;
+typedef enum {
+ FTDM_R2_PROCESSING = (1 << 0),
+ FTDM_R2_WAITING_ACK = (1 << 1),
+} ftdm_r2_call_flag_t;
+
/* private call information stored in ftdmchan->call_data void* ptr */
#define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data))
typedef struct ftdm_r2_call_t {
- openr2_chan_t *r2chan;
+ openr2_chan_t *r2chan;
+ ftdm_r2_call_flag_t flags;
int accepted:1;
int answer_pending:1;
int state_ack_pending:1;
@@ -58,6 +71,7 @@ typedef struct ftdm_r2_call_t {
ftdm_size_t dnis_index;
ftdm_size_t ani_index;
char name[10];
+ unsigned long txdrops;
} ftdm_r2_call_t;
/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
@@ -82,6 +96,7 @@ typedef struct ft_r2_conf_s {
int skip_category;
int get_ani_first;
int call_files;
+ int mf_files;
int double_answer;
int charge_calls;
int forced_release;
@@ -104,6 +119,12 @@ typedef struct ftdm_r2_data_s {
int forced_release:1;
/* whether accept the call when offered, or wait until the user decides to accept */
int accept_on_offer:1;
+ /* max time spent in ms doing real work in a single loop */
+ int jobmax;
+ /* total working loops */
+ unsigned long loops;
+ /* LWP */
+ unsigned long monitor_thread_id;
} ftdm_r2_data_t;
/* one element per span will be stored in g_mod_data_hash global var to keep track of them
@@ -116,9 +137,6 @@ typedef struct ftdm_r2_span_pvt_s {
/* span monitor thread */
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj);
-/* channel monitor thread */
-static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj);
-
/* hash of all the private span allocations
we need to keep track of them to destroy them when unloading the module
since freetdm does not notify signaling modules when destroying a span
@@ -128,6 +146,150 @@ 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);
+
+
+/* functions not available on windows */
+#ifdef WIN32
+#include
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+ SYSTEMTIME st;
+ time_t tt;
+ struct tm tmtm;
+ /* mktime converts local to UTC */
+ GetLocalTime (&st);
+ tmtm.tm_sec = st.wSecond;
+ tmtm.tm_min = st.wMinute;
+ tmtm.tm_hour = st.wHour;
+ tmtm.tm_mday = st.wDay;
+ tmtm.tm_mon = st.wMonth - 1;
+ tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1;
+ tt = mktime (&tmtm);
+ tp->tv_sec = tt;
+ tp->tv_usec = st.wMilliseconds * 1000;
+#else
+ /**
+ ** The earlier time calculations using GetLocalTime
+ ** had a time resolution of 10ms.The timeGetTime, part
+ ** of multimedia apis offer a better time resolution
+ ** of 1ms.Need to link against winmm.lib for this
+ **/
+ unsigned long Ticks = 0;
+ unsigned long Sec =0;
+ unsigned long Usec = 0;
+ Ticks = timeGetTime();
+
+ Sec = Ticks/1000;
+ Usec = (Ticks - (Sec*1000))*1000;
+ tp->tv_sec = Sec;
+ tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+ (void)nothing;
+ return 0;
+}
+
+static char *strsep(char **stringp, const char *delim)
+{
+ char *start = *stringp;
+ char *ptr;
+
+ if (!start)
+ return NULL;
+
+ if (!*delim)
+ ptr = start + strlen(start);
+ else {
+ ptr = strpbrk(start, delim);
+ if (!ptr) {
+ *stringp = NULL;
+ return start;
+ }
+ }
+
+ *ptr = '\0';
+ *stringp = ptr + 1;
+
+ return start;
+}
+#endif /* WIN32 */
+
+static ftdm_call_cause_t ftdm_r2_cause_to_ftdm_cause(ftdm_channel_t *fchan, openr2_call_disconnect_cause_t cause)
+{
+ switch (cause) {
+
+ case OR2_CAUSE_NORMAL_CLEARING:
+ return FTDM_CAUSE_NORMAL_CLEARING;
+
+ case OR2_CAUSE_BUSY_NUMBER:
+ return FTDM_CAUSE_USER_BUSY;
+
+ case OR2_CAUSE_NETWORK_CONGESTION:
+ return FTDM_CAUSE_SWITCH_CONGESTION;
+
+ case OR2_CAUSE_UNALLOCATED_NUMBER:
+ return FTDM_CAUSE_NO_ROUTE_DESTINATION;
+
+ case OR2_CAUSE_NUMBER_CHANGED:
+ return FTDM_CAUSE_NUMBER_CHANGED;
+
+ case OR2_CAUSE_OUT_OF_ORDER:
+ return FTDM_CAUSE_NETWORK_OUT_OF_ORDER;
+
+ case OR2_CAUSE_NO_ANSWER:
+ return FTDM_CAUSE_NO_ANSWER;
+
+ case OR2_CAUSE_UNSPECIFIED:
+ return FTDM_CAUSE_NORMAL_UNSPECIFIED;
+
+ case OR2_CAUSE_COLLECT_CALL_REJECTED:
+ return FTDM_CAUSE_CALL_REJECTED;
+
+ case OR2_CAUSE_FORCED_RELEASE:
+ return FTDM_CAUSE_NORMAL_CLEARING;
+ }
+ ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Mapping openr2 cause %d to unspecified\n", cause);
+ return FTDM_CAUSE_NORMAL_UNSPECIFIED;
+}
+
+static openr2_call_disconnect_cause_t ftdm_r2_ftdm_cause_to_openr2_cause(ftdm_channel_t *fchan)
+{
+ switch (fchan->caller_data.hangup_cause) {
+
+ case FTDM_CAUSE_NORMAL_CLEARING:
+ return OR2_CAUSE_NORMAL_CLEARING;
+
+ case FTDM_CAUSE_USER_BUSY:
+ return OR2_CAUSE_BUSY_NUMBER;
+
+ case FTDM_CAUSE_SWITCH_CONGESTION:
+ return OR2_CAUSE_NETWORK_CONGESTION;
+
+ case FTDM_CAUSE_NO_ROUTE_DESTINATION:
+ return OR2_CAUSE_UNALLOCATED_NUMBER;
+
+ case FTDM_CAUSE_NUMBER_CHANGED:
+ return OR2_CAUSE_NUMBER_CHANGED;
+
+ case FTDM_CAUSE_NETWORK_OUT_OF_ORDER:
+ case FTDM_CAUSE_SERVICE_UNAVAILABLE:
+ return OR2_CAUSE_OUT_OF_ORDER;
+
+ case FTDM_CAUSE_NO_ANSWER:
+ case FTDM_CAUSE_NO_USER_RESPONSE:
+ return OR2_CAUSE_NO_ANSWER;
+
+ case FTDM_CAUSE_NORMAL_UNSPECIFIED:
+ return OR2_CAUSE_UNSPECIFIED;
+
+ }
+ ftdm_log_chan(fchan, FTDM_LOG_WARNING, "freetdm hangup cause %d mapped to openr2 cause %s\n",
+ fchan->caller_data.hangup_cause, openr2_proto_get_disconnect_string(OR2_CAUSE_UNSPECIFIED));
+ return OR2_CAUSE_UNSPECIFIED;
+}
+
static void ft_r2_clean_call(ftdm_r2_call_t *call)
{
openr2_chan_t *r2chan = call->r2chan;
@@ -143,7 +305,6 @@ static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
// hanging up the call with protocol error as the reason, this openr2 API will fail only when there something
// wrong at the I/O layer or the library itself
openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
- R2CALL(ftdmchan)->accepted = 1;
}
static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
@@ -157,37 +318,46 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
R2CALL(ftdmchan)->answer_pending = 0;
}
+/* this function must be called with the chan mutex held! */
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
{
- ftdm_status_t status;
- ftdm_mutex_lock(ftdmchan->mutex);
+ openr2_call_status_t callstatus;
+ ftdm_r2_data_t *r2data;
- /* the channel may be down but the thread not quite done */
- ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200);
+ r2data = ftdmchan->span->signal_data;
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
- ftdm_log(FTDM_LOG_ERROR, "%d:%d Yay! R2 outgoing call in channel that is already in thread.\n",
- ftdmchan->span_id, ftdmchan->chan_id);
- ftdm_mutex_unlock(ftdmchan->mutex);
+ if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ /* collision, an incoming seized the channel between our take and use timing */
+ ftdm_log_chan(ftdmchan,
+ FTDM_LOG_CRIT, "R2 cannot dial out in channel in state %s, try another channel!.\n", ftdm_channel_state2str(ftdmchan->state));
return FTDM_FAIL;
}
ft_r2_clean_call(ftdmchan->call_data);
- R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
R2CALL(ftdmchan)->ftdm_started = 1;
- ftdm_mutex_unlock(ftdmchan->mutex);
+ R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
- status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
- if (status == FTDM_FAIL) {
- ftdm_log(FTDM_LOG_ERROR, "%d:%d Cannot handle request to start call in channel, failed to create thread!\n",
- ftdmchan->span_id, ftdmchan->chan_id);
- ftdm_channel_done(ftdmchan);
- return FTDM_FAIL;
+ callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan,
+ ftdmchan->caller_data.cid_num.digits,
+ ftdmchan->caller_data.dnis.digits,
+ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER);
+
+ if (callstatus) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
+ return FTDM_FAIL;
+ }
+
+ if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Collision after call attempt, try another channel, new state = %s\n",
+ ftdm_channel_state2str(ftdmchan->state));
+ ftdm_clear_flag(R2CALL(ftdmchan), FTDM_R2_WAITING_ACK);
+ return FTDM_BREAK;
}
- return FTDM_SUCCESS;
+ /* non-threaded implementation, we're done here */
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 call placed in non-threaded mode\n");
+ return FTDM_SUCCESS;
}
static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
@@ -197,91 +367,114 @@ static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
return ftdm_thread_create_detached(ftdm_r2_run, span);
}
+static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
+{
+ ftdm_r2_data_t *r2_data = span->signal_data;
+ while (ftdm_test_flag(r2_data, FTDM_R2_RUNNING)) {
+ ftdm_log(FTDM_LOG_DEBUG, "Waiting for R2 span %s\n", span->name);
+ ftdm_sleep(100);
+ }
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_r2_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size)
+{
+ openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+ if (!openr2_chan_get_read_enabled(r2chan)) {
+ ftdm_mutex_lock(ftdmchan->mutex);
+ //openr2_chan_process_input(r2chan, data, size);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+ return FTDM_SUCCESS;
+}
+
/* always called from the monitor thread */
static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
{
+ //ftdm_status_t status;
+ ftdm_r2_call_t *r2call;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_status_t status;
- ftdm_log(FTDM_LOG_NOTICE, "Received request to start call on chan %d\n", openr2_chan_get_number(r2chan));
+ //ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
+
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n");
ftdm_mutex_lock(ftdmchan->mutex);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state));
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+
if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
- ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, invalid state (%d)\n",
- openr2_chan_get_number(r2chan), ftdmchan->state);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot handle request to start call in state %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
- /* the channel may be down but the thread not quite done */
- ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200);
-
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
- ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, already in thread!\n",
- openr2_chan_get_number(r2chan));
+ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open channel during incoming call! [%s]\n", ftdmchan->last_error);
ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
+
+ /* mark the channel in use (so no outgoing calls can be placed here) */
+ ftdm_channel_use(ftdmchan);
+
+ memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected));
+ memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected));
+
+ /* clean the call data structure but keep the R2 processing flag on! */
ft_r2_clean_call(ftdmchan->call_data);
- R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+ r2call = R2CALL(ftdmchan);
+ ftdm_set_flag(r2call, FTDM_R2_PROCESSING);
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
+ R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+ } else {
+ R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DIALING;
+ }
+
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
ftdm_mutex_unlock(ftdmchan->mutex);
- status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
- if (status == FTDM_FAIL) {
- ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, failed to create thread!\n",
- openr2_chan_get_number(r2chan));
- }
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Span is not threaded, not launching thread for this call\n");
+ return;
}
/* 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)
{
- ftdm_sigmsg_t sigev;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log(FTDM_LOG_NOTICE, "Call offered on chan %d, ANI = %s, DNIS = %s, Category = %s\n", openr2_chan_get_number(r2chan),
- ani, dnis, openr2_proto_get_category_string(category));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Priority = (%d)\n", ani, dnis, category);
+ //ftdmchan->caller_data.priority = category;
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
- /* notify the user about the new call */
- memset(&sigev, 0, sizeof(sigev));
- sigev.chan_id = ftdmchan->chan_id;
- sigev.span_id = ftdmchan->span_id;
- sigev.channel = ftdmchan;
- sigev.event_id = FTDM_SIGEVENT_START;
-
- if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_NOTICE, "Failed to handle call offered on chan %d\n", openr2_chan_get_number(r2chan));
- openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
- return;
- }
- ftdm_channel_use(ftdmchan);
- R2CALL(ftdmchan)->ftdm_started = 1;
}
static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log(FTDM_LOG_NOTICE, "Call accepted on chan %d\n", openr2_chan_get_number(r2chan));
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n");
/* at this point the MF signaling has ended and there is no point on keep reading */
openr2_chan_disable_read(r2chan);
+ R2CALL(ftdmchan)->accepted = 1;
if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
R2CALL(ftdmchan)->state_ack_pending = 1;
if (R2CALL(ftdmchan)->answer_pending) {
- ftdm_log(FTDM_LOG_DEBUG, "Answer was pending on chan %d, answering now.\n", openr2_chan_get_number(r2chan));
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n");
ft_r2_answer_call(ftdmchan);
return;
}
} else {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
}
}
static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log(FTDM_LOG_NOTICE, "Call answered on chan %d\n", openr2_chan_get_number(r2chan));
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call answered\n");
/* notify the upper layer of progress in the outbound call */
if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
@@ -294,14 +487,19 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon
ftdm_sigmsg_t sigev;
ftdm_r2_data_t *r2data;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log(FTDM_LOG_NOTICE, "Call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
- ftdm_log(FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call on channel %d\n", ftdmchan->physical_chan_id);
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call disconnected\n");
+
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call\n");
R2CALL(ftdmchan)->disconnect_rcvd = 1;
- /* acknowledge the hangup, cause will be ignored. From here to -> HANGUP once the freetdm side hangs up as well */
- openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call had been disconnected already by the user\n");
+ /* just ack the hangup to go down */
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+ return;
+ }
/* if the call has not been started yet we must go to HANGUP right here */
if (!R2CALL(ftdmchan)->ftdm_started) {
@@ -309,8 +507,7 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon
return;
}
- /* FIXME: use the cause received from openr2 and map it to ftdm cause */
- ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
+ ftdmchan->caller_data.hangup_cause = ftdm_r2_cause_to_ftdm_cause(ftdmchan, cause);
/* notify the user of the call terminating */
memset(&sigev, 0, sizeof(sigev));
@@ -326,27 +523,32 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon
static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log(FTDM_LOG_NOTICE, "Call finished on chan %d\n", openr2_chan_get_number(r2chan));
- /* this means the freetdm side disconnected the call, therefore we must move to DOWN here */
- if (!R2CALL(ftdmchan)->disconnect_rcvd) {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
- return;
- }
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call finished\n");
+
+ /* the call is done as far as the stack is concerned, lets move to down here */
+ ftdm_set_state_locked(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(ftdmchan);
}
static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
{
+#if 0
ftdm_log(FTDM_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan));
+#endif
}
static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
{
- ftdm_log(FTDM_LOG_NOTICE, "Alarm on chan %d (%d)\n", openr2_chan_get_number(r2chan), alarm);
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Alarm notification: %d\n", alarm);
}
static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
{
- ftdm_log(FTDM_LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "OS error: %s\n", strerror(errorcode));
}
static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
@@ -355,18 +557,26 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
ftdm_r2_data_t *r2data;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log(FTDM_LOG_ERROR, "Protocol error on chan %d\n", openr2_chan_get_number(r2chan));
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Got protocol error when we're already down!\n");
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
+
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n");
R2CALL(ftdmchan)->disconnect_rcvd = 1;
if (!R2CALL(ftdmchan)->ftdm_started) {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_PROTOCOL_ERROR;
- /* notify the user of the call terminating */
+ /* FIXME: go to terminating and notify the user from the terminating handler instead of notifying here */
memset(&sigev, 0, sizeof(sigev));
sigev.chan_id = ftdmchan->chan_id;
sigev.span_id = ftdmchan->span_id;
@@ -375,63 +585,76 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
r2data = ftdmchan->span->signal_data;
ftdm_span_send_signal(ftdmchan->span, &sigev);
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
}
static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
{
- ftdm_log(FTDM_LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end blocked in state %s\n", ftdm_channel_state2str(ftdmchan->state));
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED);
}
static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan)
{
- ftdm_log(FTDM_LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end unblocked in state %s\n", ftdm_channel_state2str(ftdmchan->state));
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+
+ /* XXX when should we set/unset this flag? XXX */
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SIG_UP);
}
-static void ftdm_r2_write_log(openr2_log_level_t level, const char *message)
+static void ftdm_r2_write_log(openr2_log_level_t level, const char *file, const char *function, int line, const char *message)
{
switch (level) {
case OR2_LOG_NOTICE:
- ftdm_log(FTDM_LOG_NOTICE, "%s", message);
+ ftdm_log(file, function, line, FTDM_LOG_LEVEL_NOTICE, "%s", message);
break;
case OR2_LOG_WARNING:
- ftdm_log(FTDM_LOG_WARNING, "%s", message);
+ ftdm_log(file, function, line, FTDM_LOG_LEVEL_WARNING, "%s", message);
break;
case OR2_LOG_ERROR:
- ftdm_log(FTDM_LOG_ERROR, "%s", message);
+ ftdm_log(file, function, line, FTDM_LOG_LEVEL_ERROR, "%s", message);
break;
case OR2_LOG_STACK_TRACE:
case OR2_LOG_MF_TRACE:
case OR2_LOG_CAS_TRACE:
case OR2_LOG_DEBUG:
case OR2_LOG_EX_DEBUG:
- ftdm_log(FTDM_LOG_DEBUG, "%s", message);
+ ftdm_log(file, function, line, FTDM_LOG_LEVEL_DEBUG, "%s", message);
break;
default:
ftdm_log(FTDM_LOG_WARNING, "We should handle logging level %d here.\n", level);
- ftdm_log(FTDM_LOG_DEBUG, "%s", message);
+ ftdm_log(file, function, line, FTDM_LOG_LEVEL_DEBUG, "%s", message);
break;
}
}
-static void ftdm_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+static void ftdm_r2_on_context_log(openr2_context_t *r2context, const char *file, const char *function, unsigned int line,
+ openr2_log_level_t level, const char *fmt, va_list ap)
{
#define CONTEXT_TAG "Context -"
char logmsg[256];
char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
- ftdm_r2_write_log(level, completemsg);
+ ftdm_r2_write_log(level, file, function, line, completemsg);
#undef CONTEXT_TAG
}
-static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, const char *file, const char *function, unsigned int line,
+ openr2_log_level_t level, const char *fmt, va_list ap)
{
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
#define CHAN_TAG "Chan "
- char logmsg[256];
+ char logmsg[512];
char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
- snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d: %s", openr2_chan_get_number(r2chan), logmsg);
- ftdm_r2_write_log(level, completemsg);
+ snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d:%d [%s] %s",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), logmsg);
+ ftdm_r2_write_log(level, file, function, line, completemsg);
#undef CHAN_TAG
}
@@ -442,7 +665,7 @@ static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_size_t collected_len = R2CALL(ftdmchan)->dnis_index;
- ftdm_log(FTDM_LOG_DEBUG, "DNIS digit %d received chan %d\n", digit, openr2_chan_get_number(r2chan));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "DNIS digit %c received\n", digit);
/* save the digit we just received */
ftdmchan->caller_data.dnis.digits[collected_len] = digit;
@@ -458,13 +681,13 @@ static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
sigev.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
r2data = ftdmchan->span->signal_data;
if (ftdm_span_send_signal(ftdmchan->span, &sigev) == FTDM_BREAK) {
- ftdm_log(FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits);
return OR2_STOP_DNIS_REQUEST;
}
/* the only other reason to stop requesting DNIS is that there is no more room to save it */
if (collected_len == (sizeof(ftdmchan->caller_data.dnis.digits) - 1)) {
- ftdm_log(FTDM_LOG_NOTICE, "No more room for DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "No more room for DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits);
return OR2_STOP_DNIS_REQUEST;
}
@@ -478,35 +701,39 @@ static void ftdm_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
/* check if we should drop ANI */
if (collected_len == (sizeof(ftdmchan->caller_data.ani.digits) - 1)) {
- ftdm_log(FTDM_LOG_NOTICE, "No more room for ANI %c on chan %d, digit dropped.\n", digit, openr2_chan_get_number(r2chan));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "No more room for ANI, digit dropped: %c\n", digit);
return;
}
- ftdm_log(FTDM_LOG_DEBUG, "ANI digit %c received chan %d\n", digit, openr2_chan_get_number(r2chan));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ANI digit %c received\n", digit);
/* save the digit we just received */
- ftdmchan->caller_data.ani.digits[collected_len++] = digit;
+ ftdmchan->caller_data.ani.digits[collected_len] = digit;
+ collected_len++;
ftdmchan->caller_data.ani.digits[collected_len] = '\0';
+ R2CALL(ftdmchan)->ani_index = collected_len;
}
static openr2_event_interface_t ftdm_r2_event_iface = {
- .on_call_init = ftdm_r2_on_call_init,
- .on_call_offered = ftdm_r2_on_call_offered,
- .on_call_accepted = ftdm_r2_on_call_accepted,
- .on_call_answered = ftdm_r2_on_call_answered,
- .on_call_disconnect = ftdm_r2_on_call_disconnect,
- .on_call_end = ftdm_r2_on_call_end,
- .on_call_read = ftdm_r2_on_call_read,
- .on_hardware_alarm = ftdm_r2_on_hardware_alarm,
- .on_os_error = ftdm_r2_on_os_error,
- .on_protocol_error = ftdm_r2_on_protocol_error,
- .on_line_blocked = ftdm_r2_on_line_blocked,
- .on_line_idle = ftdm_r2_on_line_idle,
+ /* .on_call_init */ ftdm_r2_on_call_init,
+ /* .on_call_offered */ ftdm_r2_on_call_offered,
+ /* .on_call_accepted */ ftdm_r2_on_call_accepted,
+ /* .on_call_answered */ ftdm_r2_on_call_answered,
+ /* .on_call_disconnect */ ftdm_r2_on_call_disconnect,
+ /* .on_call_end */ ftdm_r2_on_call_end,
+ /* .on_call_read */ ftdm_r2_on_call_read,
+ /* .on_hardware_alarm */ ftdm_r2_on_hardware_alarm,
+ /* .on_os_error */ ftdm_r2_on_os_error,
+ /* .on_protocol_error */ ftdm_r2_on_protocol_error,
+ /* .on_line_blocked */ ftdm_r2_on_line_blocked,
+ /* .on_line_idle */ ftdm_r2_on_line_idle,
+
/* cast seems to be needed to get rid of the annoying warning regarding format attribute */
- .on_context_log = (openr2_handle_context_logging_func)ftdm_r2_on_context_log,
- .on_dnis_digit_received = ftdm_r2_on_dnis_digit_received,
- .on_ani_digit_received = ftdm_r2_on_ani_digit_received,
+ /* .on_context_log */ (openr2_handle_context_logging_func)ftdm_r2_on_context_log,
+ /* .on_dnis_digit_received */ ftdm_r2_on_dnis_digit_received,
+ /* .on_ani_digit_received */ ftdm_r2_on_ani_digit_received,
+
/* so far we do nothing with billing pulses */
- .on_billing_pulse_received = NULL
+ /* .on_billing_pulse_received */ NULL,
};
static int ftdm_r2_io_set_cas(openr2_chan_t *r2chan, int cas)
@@ -564,10 +791,11 @@ static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size)
static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
{
ftdm_status_t status;
+ int32_t timeout;
ftdm_wait_flag_t ftdmflags = 0;
ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
- int32_t timeout = block ? -1 : 0;
+ timeout = block ? -1 : 0;
if (*flags & OR2_IO_READ) {
ftdmflags |= FTDM_READ;
@@ -578,10 +806,10 @@ static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
if (*flags & OR2_IO_OOB_EVENT) {
ftdmflags |= FTDM_EVENTS;
}
-
+
status = ftdm_channel_wait(ftdm_chan, &ftdmflags, timeout);
- if (FTDM_SUCCESS != status) {
+ if (FTDM_SUCCESS != status && FTDM_TIMEOUT != status) {
return -1;
}
@@ -610,18 +838,19 @@ static openr2_io_fd_t ftdm_r2_io_open(openr2_context_t *r2context, int channo)
/* since freetdm takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */
static int ftdm_r2_io_close(openr2_chan_t *r2chan)
{
- ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n");
+ ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n");
return 0;
}
/* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
{
- ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
+ ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan);
+ ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
return 0;
}
-/* since the signaling thread calls openr2_chan_process_cas_signaling directly, openr2 should never call this hook */
static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
{
*event = 0;
@@ -630,16 +859,16 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e
}
static openr2_io_interface_t ftdm_r2_io_iface = {
- .open = ftdm_r2_io_open, /* never called */
- .close = ftdm_r2_io_close, /* never called */
- .set_cas = ftdm_r2_io_set_cas,
- .get_cas = ftdm_r2_io_get_cas,
- .flush_write_buffers = ftdm_r2_io_flush_write_buffers,
- .write = ftdm_r2_io_write,
- .read = ftdm_r2_io_read,
- .setup = ftdm_r2_io_setup, /* never called */
- .wait = ftdm_r2_io_wait,
- .get_oob_event = ftdm_r2_io_get_oob_event /* never called */
+ /* .open */ ftdm_r2_io_open, /* never called */
+ /* .close */ ftdm_r2_io_close, /* never called */
+ /* .set_cas */ ftdm_r2_io_set_cas,
+ /* .get_cas */ ftdm_r2_io_get_cas,
+ /* .flush_write_buffers */ ftdm_r2_io_flush_write_buffers,
+ /* .write */ ftdm_r2_io_write,
+ /* .read */ ftdm_r2_io_read,
+ /* .setup */ ftdm_r2_io_setup, /* never called */
+ /* .wait */ ftdm_r2_io_wait,
+ /* .get_oob_event */ ftdm_r2_io_get_oob_event /* never called */
};
static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
@@ -653,29 +882,32 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
ftdm_r2_span_pvt_t *spanpvt = NULL;
ftdm_r2_call_t *r2call = NULL;
openr2_chan_t *r2chan = NULL;
-
- assert(sig_cb != NULL);
+ openr2_log_level_t tmplevel;
+ char *clevel;
+ char *logval = NULL;
ft_r2_conf_t r2conf =
{
- .variant = OR2_VAR_ITU,
- .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
- .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
- .max_ani = 10,
- .max_dnis = 4,
- .mfback_timeout = -1,
- .metering_pulse_timeout = -1,
- .allow_collect_calls = -1,
- .immediate_accept = -1,
- .skip_category = -1,
- .forced_release = -1,
- .charge_calls = -1,
- .get_ani_first = -1,
- .call_files = -1,
- .logdir = NULL,
- .advanced_protocol_file = NULL
+ /* .variant */ OR2_VAR_ITU,
+ /* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
+ /* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING,
+ /* .max_ani */ 10,
+ /* .max_dnis */ 4,
+ /* .mfback_timeout */ -1,
+ /* .metering_pulse_timeout */ -1,
+ /* .allow_collect_calls */ -1,
+ /* .immediate_accept */ -1,
+ /* .skip_category */ -1,
+ /* .forced_release */ -1,
+ /* .charge_calls */ -1,
+ /* .get_ani_first */ -1,
+ /* .call_files */ 0,
+ /* .mf_files */ 0,
+ /* .logdir */ NULL,
+ /* .advanced_protocol_file */ NULL
};
+ assert(sig_cb != NULL);
if (span->signal_type) {
snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
@@ -732,9 +964,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
continue;
}
- openr2_log_level_t tmplevel;
- char *clevel;
- char *logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */
+ logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */
if (!logval) {
ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val);
continue;
@@ -784,6 +1014,9 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
} else if (!strcasecmp(var, "call_files")) {
r2conf.call_files = va_arg(ap, int);
ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
+ } else if (!strcasecmp(var, "mf_files")) {
+ r2conf.mf_files = va_arg(ap, int);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with mf files = %d\n", span->span_id, r2conf.mf_files);
} else if (!strcasecmp(var, "mfback_timeout")) {
r2conf.mfback_timeout = va_arg(ap, int);
ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
@@ -834,7 +1067,9 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout);
openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
- if (r2conf.logdir) {
+
+ if (r2conf.logdir && r2conf.logdir[0]) {
+ ftdm_log(FTDM_LOG_DEBUG, "Setting openr2 for span %s logdir to %s\n", span->name, r2conf.logdir);
openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
}
if (r2conf.advanced_protocol_file) {
@@ -853,9 +1088,14 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span.");
goto fail;
}
+ openr2_chan_set_log_level(r2chan, r2conf.loglevel);
if (r2conf.call_files) {
openr2_chan_enable_call_files(r2chan);
- openr2_chan_set_log_level(r2chan, r2conf.loglevel);
+#if 0
+ if (r2conf.mf_files) {
+ openr2_chan_enable_mf_files(r2chan);
+ }
+#endif
}
r2call = ftdm_malloc(sizeof(*r2call));
@@ -874,13 +1114,16 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
}
+ r2data->flags = 0;
spanpvt->r2context = r2data->r2context;
/* just the value must be freed by the hash */
hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE);
span->start = ftdm_r2_start;
- r2data->flags = 0;
+ span->stop = ftdm_r2_stop;
+ span->sig_read = ftdm_r2_sig_read;
+
span->signal_cb = sig_cb;
span->signal_type = FTDM_SIGTYPE_R2;
span->signal_data = r2data;
@@ -902,301 +1145,401 @@ fail:
}
-static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj)
+/* the channel must be locked when calling this function */
+static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
{
- ftdm_channel_t *closed_chan;
- uint32_t interval = 0;
ftdm_sigmsg_t sigev;
- ftdm_channel_t *ftdmchan = (ftdm_channel_t *)obj;
+ int ret;
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
-
- ftdm_mutex_lock(g_thread_count_mutex);
- g_thread_count++;
- ftdm_mutex_unlock(g_thread_count_mutex);
-
- ftdm_log(FTDM_LOG_DEBUG, "R2 CHANNEL thread starting on %d in state %s.\n",
- ftdmchan->physical_chan_id,
- ftdm_channel_state2str(ftdmchan->state));
-
- if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
- goto endthread;
- }
-
- ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
-
- assert(interval != 0);
- ftdm_log(FTDM_LOG_DEBUG, "Got %d interval for chan %d\n", interval, ftdmchan->physical_chan_id);
-
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- /* FIXME: is this needed? */
- memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected));
- memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected));
- }
-
memset(&sigev, 0, sizeof(sigev));
sigev.chan_id = ftdmchan->chan_id;
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
- while (ftdm_running()) {
- int32_t read_enabled = openr2_chan_get_read_enabled(r2chan);
- ftdm_wait_flag_t flags = read_enabled ? ( FTDM_READ | FTDM_WRITE ) : 0;
-
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
-
- ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
- R2CALL(ftdmchan)->chanstate = ftdmchan->state;
-
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted &&
- (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
- ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
- ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) {
- /* if an accept ack will be required we should not acknowledge the state change just yet,
- it will be done below after processing the MF signals, 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(FTDM_LOG_DEBUG, "State ack in chan %d:%d for state %s will have to wait a bit\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
- } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
- /* the down state will be completed in ftdm_channel_done below */
- ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
- ftdm_channel_complete_state(ftdmchan);
- }
-
- switch (ftdmchan->state) {
-
- /* starting an incoming call */
- case FTDM_CHANNEL_STATE_COLLECT:
- {
- ftdm_log(FTDM_LOG_DEBUG, "COLLECT: Starting processing of incoming call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval);
- }
- break;
-
- /* starting an outgoing call */
- case FTDM_CHANNEL_STATE_DIALING:
- {
- // FIXME: use user defined calling party
- ftdm_channel_use(ftdmchan);
- ftdm_log(FTDM_LOG_DEBUG, "DIALING: Starting processing of outgoing call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval);
- if (openr2_chan_make_call(r2chan, ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.dnis.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER)) {
- ftdm_log(FTDM_LOG_ERROR, "%d:%d Failed to make call in R2 channel, openr2_chan_make_call failed\n", ftdmchan->span_id, ftdmchan->chan_id);
- ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- }
- }
- break;
-
- /* the call is ringing */
- case FTDM_CHANNEL_STATE_PROGRESS:
- case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
- {
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- if (!R2CALL(ftdmchan)->accepted) {
- ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Accepting call on channel %d\n", ftdmchan->physical_chan_id);
- ft_r2_accept_call(ftdmchan);
- }
- } else {
- ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Notifying progress in channel %d\n", ftdmchan->physical_chan_id);
- sigev.event_id = FTDM_SIGEVENT_PROGRESS;
- if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- }
- }
- }
- break;
-
- /* the call was answered */
- case FTDM_CHANNEL_STATE_UP:
- {
- ftdm_log(FTDM_LOG_DEBUG, "UP: Call was answered on channel %d\n", ftdmchan->physical_chan_id);
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- if (!R2CALL(ftdmchan)->accepted) {
- ftdm_log(FTDM_LOG_DEBUG, "UP: 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(ftdmchan)->answer_pending = 1;
- } else {
- ft_r2_answer_call(ftdmchan);
- }
- } else {
- ftdm_log(FTDM_LOG_DEBUG, "UP: Notifying of call answered in channel %d\n", ftdmchan->physical_chan_id);
- sigev.event_id = FTDM_SIGEVENT_UP;
- if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- }
- }
- }
- break;
-
- /* just got hangup */
- case FTDM_CHANNEL_STATE_HANGUP:
- {
- /* FIXME: the cause should be retrieved from ftdmchan->caller_data.hangup_cause and translated from Q931 to R2 cause */
- ftdm_log(FTDM_LOG_DEBUG, "HANGUP: Clearing call on channel %d\n", ftdmchan->physical_chan_id);
- if (!R2CALL(ftdmchan)->disconnect_rcvd) {
- /* this will disconnect the call, but need to wait for the call end before moving to DOWN */
- openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
- } else {
- /* at this point on_call_end possibly was already called,
- * but we needed to wait for the freetdm confirmation before moving to DOWN */
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
- }
- }
- break;
-
- /* just got hangup from the freetdm side due to abnormal failure */
- case FTDM_CHANNEL_STATE_CANCEL:
- {
- ftdm_log(FTDM_LOG_DEBUG, "CANCEL: Unable to receive call on channel %d\n", ftdmchan->physical_chan_id);
- openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
- }
- break;
-
- /* finished call for good */
- case FTDM_CHANNEL_STATE_DOWN:
- {
- ftdm_log(FTDM_LOG_DEBUG, "DOWN: Placing channel %d back to the pool of available channels\n", ftdmchan->physical_chan_id);
- ftdm_channel_done(ftdmchan);
- goto endthread;
- }
- break;
-
- default:
- {
- ftdm_log(FTDM_LOG_ERROR, "%s: Unhandled channel state change in channel %d\n", ftdm_channel_state2str(ftdmchan->state), ftdmchan->physical_chan_id);
- }
- break;
-
- }
- }
-
- if (flags) {
- if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_DEBUG, "ftdm_channel_wait did not return FTDM_SUCCESS\n");
- continue;
- }
-
- /* handle timeout events first if any */
- openr2_chan_run_schedule(r2chan);
-
- /* openr2 will now try to detect MF tones, make sense out of them, reply if necessary with another tone and trigger
- * telephony events via the call event interface we provided when creating the R2 context.
- * openr2 will also call our I/O callbacks to retrieve audio from the channel and call our wait poll I/O registered callback
- * and will not return from this function until the I/O poll callback returns no pending events
- * */
- openr2_chan_process_mf_signaling(r2chan);
- if (R2CALL(ftdmchan)->state_ack_pending) {
- ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
- ftdm_channel_complete_state(ftdmchan);
- R2CALL(ftdmchan)->state_ack_pending = 0;
- }
- } else {
- /* once the MF signaling has end we just loop here waiting for state changes */
- ftdm_sleep(interval);
- }
+ ret = 0;
+ if (R2CALL(ftdmchan)->state_ack_pending) {
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_channel_complete_state(ftdmchan);
+ R2CALL(ftdmchan)->state_ack_pending = 0;
}
-endthread:
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
- closed_chan = ftdmchan;
- ftdm_channel_close(&closed_chan);
- ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INTHREAD);
- ftdm_log(FTDM_LOG_DEBUG, "R2 channel %d thread ended.\n", ftdmchan->physical_chan_id);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
+ R2CALL(ftdmchan)->chanstate = ftdmchan->state;
- ftdm_mutex_lock(g_thread_count_mutex);
- g_thread_count--;
- ftdm_mutex_unlock(g_thread_count_mutex);
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted &&
+ (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
+ ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) {
+ /* if an accept ack will be required we should not acknowledge the state change just yet,
+ it will be done below after processing the MF signals, 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);
+ }
- return NULL;
+ 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);
+ }
+ 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);
+ }
+ break;
+
+ /* incoming call was offered */
+ case FTDM_CHANNEL_STATE_RING:
+
+ /* notify the user about the new call */
+ sigev.event_id = FTDM_SIGEVENT_START;
+
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Failed to handle call offered\n");
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+ break;
+ }
+ R2CALL(ftdmchan)->ftdm_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(ftdmchan)->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_PROGRESS_MEDIA;
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ 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(ftdmchan)->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(ftdmchan)->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;
+ if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ }
+ }
+ }
+ break;
+
+ /* just got hangup */
+ case FTDM_CHANNEL_STATE_HANGUP:
+ {
+ 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));
+ openr2_chan_enable_read(r2chan);
+ if (!R2CALL(ftdmchan)->disconnect_rcvd) {
+ /* 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 {
+ /* just ack the hangup, on_call_end will be called by openr2 right after */
+ openr2_chan_disconnect_call(r2chan, disconnect_cause);
+ }
+ }
+ break;
+
+ /* just got hangup from the freetdm side due to abnormal failure */
+ case FTDM_CHANNEL_STATE_CANCEL:
+ {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Unable to receive call\n");
+ openr2_chan_enable_read(r2chan);
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ }
+ break;
+
+ /* finished call for good */
+ case FTDM_CHANNEL_STATE_DOWN:
+ {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call is down\n");
+ if (R2CALL(ftdmchan)->txdrops) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "dropped %d tx packets\n", R2CALL(ftdmchan)->txdrops);
+ }
+ ret = 1;
+ }
+ break;
+
+ default:
+ {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
+ }
+ break;
+
+ }
+ }
+
+ if (ret) {
+ ftdm_channel_t *closed_chan;
+ closed_chan = ftdmchan;
+ ftdm_channel_close(&closed_chan);
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n");
+ }
+ return ret;
}
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
{
openr2_chan_t *r2chan;
+ ftdm_r2_call_t *r2call = NULL;
+ ftdm_channel_t *ftdmchan = NULL;
ftdm_status_t status;
ftdm_span_t *span = (ftdm_span_t *) obj;
ftdm_r2_data_t *r2data = span->signal_data;
- int waitms = 1000;
- int i;
+ int waitms = 20;
+ int i, res;
+ int ms;
+ struct timeval start, end;
+ short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count);
- ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread started.\n");
- r2chan = NULL;
+#ifdef __linux__
+ r2data->monitor_thread_id = syscall(SYS_gettid);
+#endif
+
+ ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread %lu started.\n", r2data->monitor_thread_id);
+ r2chan = NULL;
for (i = 1; i <= span->chan_count; i++) {
r2chan = R2CALL(span->channels[i])->r2chan;
openr2_chan_set_idle(r2chan);
openr2_chan_process_cas_signaling(r2chan);
}
+ memset(&start, 0, sizeof(start));
+ memset(&end, 0, sizeof(end));
while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
- status = ftdm_span_poll_event(span, waitms);
+ r2data->loops++;
+ res = gettimeofday(&end, NULL);
+ if (start.tv_sec) {
+ ms = ((end.tv_sec - start.tv_sec) * 1000)
+ + ((( 1000000 + end.tv_usec - start.tv_usec) / 1000) - 1000);
+ if (ms > r2data->jobmax) {
+ r2data->jobmax = ms;
+ }
+ }
+
+#ifndef WIN32
+ /* figure out what event to poll each channel for. POLLPRI when the channel is down,
+ * POLLPRI|POLLIN|POLLOUT otherwise.
+ */
+ memset(poll_events, 0, sizeof(short)*span->chan_count);
+ for (i = 0; i < span->chan_count; i++) {
+ r2chan = R2CALL(span->channels[(i+1)])->r2chan;
+ ftdmchan = openr2_chan_get_client_data(r2chan);
+
+ poll_events[i] = ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ? POLLPRI : (POLLPRI | POLLIN | POLLOUT);
+ }
+
+ status = ftdm_span_poll_event(span, waitms, poll_events);
+#else
+ status = ftdm_span_poll_event(span, waitms, NULL);
+#endif
+
+ res = gettimeofday(&start, NULL);
+ if (res) {
+ ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno));
+ }
+
if (FTDM_FAIL == status) {
- ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+ ftdm_log(FTDM_LOG_CRIT, "Failure waiting I/O! [%s]\n", span->channels[1]->last_error);
continue;
}
- if (FTDM_SUCCESS == status) {
+
+ if (FTDM_SUCCESS == status) {
ftdm_event_t *event;
while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
if (event->enum_id == FTDM_OOB_CAS_BITS_CHANGE) {
- r2chan = R2CALL(event->channel)->r2chan;
+ r2call = R2CALL(event->channel);
+ r2chan = r2call->r2chan;
+
ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
// we only expect CAS and other OOB events on this thread/loop, once a call is started
// the MF events (in-band signaling) are handled in the call thread
openr2_chan_process_cas_signaling(r2chan);
+
} else {
ftdm_log(FTDM_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
// XXX TODO: handle alarms here XXX
}
}
+
+ /* XXX
+ * when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span.
+ * is it possible to know on which channels those events are pending, without trasvering the span?
+ * XXX
+ */
+ for (i = 1; i <= span->chan_count; i++) {
+ r2chan = R2CALL(span->channels[i])->r2chan;
+ ftdmchan = openr2_chan_get_client_data(r2chan);
+ r2call = R2CALL(ftdmchan);
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+ ftdm_set_flag(r2call, FTDM_R2_PROCESSING);
+
+ if (ftdm_r2_state_advance(ftdmchan)) {
+ ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ continue;
+ }
+
+ /* handle timeout events first if any */
+ openr2_chan_run_schedule(r2chan);
+
+ /* process mf tones, if any */
+ if (openr2_chan_get_read_enabled(r2chan))
+ openr2_chan_process_mf_signaling(r2chan);
+
+ if (ftdm_r2_state_advance(ftdmchan)) {
+ ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ continue;
+ }
+
+ ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
+ ftdm_mutex_unlock(ftdmchan->mutex);
+ }
} else if (status != FTDM_TIMEOUT) {
ftdm_log(FTDM_LOG_ERROR, "ftdm_span_poll_event returned %d.\n", status);
- } else {
- //ftdm_log(FTDM_LOG_DEBUG, "timed out waiting for event on span %d\n", span->span_id);
- }
+ }
+ ftdm_sleep(20);
}
- /*
- FIXME: we should set BLOCKED but at this point I/O routines of freetdm caused segfault
for (i = 1; i <= span->chan_count; i++) {
r2chan = R2CALL(span->channels[i])->r2chan;
openr2_chan_set_blocked(r2chan);
}
- */
ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n");
return NULL;
+}
+static void __inline__ block_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t *stream)
+{
+ openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
+ ftdm_mutex_lock(fchan->mutex);
+ if (fchan->state != FTDM_CHANNEL_STATE_DOWN) {
+ stream->write_function(stream, "cannot block channel %d:%d because has a call in progress\n",
+ fchan->span_id, fchan->chan_id);
+ } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
+ stream->write_function(stream, "cannot block channel %d:%d because is already blocked\n",
+ fchan->span_id, fchan->chan_id);
+ } else {
+ if (!openr2_chan_set_blocked(r2chan)) {
+ ftdm_set_flag(fchan, FTDM_CHANNEL_SUSPENDED);
+ stream->write_function(stream, "blocked channel %d:%d\n",
+ fchan->span_id, fchan->chan_id);
+ } else {
+ stream->write_function(stream, "failed to block channel %d:%d\n",
+ fchan->span_id, fchan->chan_id);
+ }
+ }
+ ftdm_mutex_unlock(fchan->mutex);
+}
+
+static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t *stream)
+{
+ openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
+ ftdm_mutex_lock(fchan->mutex);
+ if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
+ if (!openr2_chan_set_idle(r2chan)) {
+ ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED);
+ stream->write_function(stream, "unblocked channel %d:%d\n",
+ fchan->span_id, fchan->chan_id);
+ } else {
+ stream->write_function(stream, "failed to unblock channel %d:%d\n",
+ fchan->span_id, fchan->chan_id);
+ }
+ } else {
+ stream->write_function(stream, "cannot unblock channel %d:%d because is not blocked\n",
+ fchan->span_id, fchan->chan_id);
+ }
+ ftdm_mutex_unlock(fchan->mutex);
}
static FIO_API_FUNCTION(ftdm_r2_api)
{
+ ftdm_span_t *span = NULL;
char *mycmd = NULL, *argv[10] = { 0 };
int argc = 0;
+ int span_id = 0;
+ int chan_id = 0;
+ int i = 0;
+ ftdm_r2_data_t *r2data = NULL;
+ openr2_chan_t *r2chan = NULL;
+ openr2_context_t *r2context = NULL;
+ openr2_variant_t r2variant;
if (data) {
mycmd = ftdm_strdup(data);
argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
- if (argc == 2) {
- if (!strcasecmp(argv[0], "kill")) {
+ if (argc >= 2) {
+ if (!strcasecmp(argv[0], "block")) {
int span_id = atoi(argv[1]);
- ftdm_span_t *span = NULL;
if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
- ftdm_r2_data_t *r2data = span->signal_data;
if (span->start != ftdm_r2_start) {
stream->write_function(stream, "-ERR invalid span.\n");
goto done;
}
- ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
- stream->write_function(stream, "+OK killed.\n");
+ if (argc > 2) {
+ chan_id = atoi(argv[2]);
+ if (chan_id && chan_id <= span->chan_count) {
+ block_channel(span->channels[chan_id], stream);
+ } else {
+ stream->write_function(stream, "-ERR invalid chan %d.\n", chan_id);
+ }
+ } else {
+ for (i = 1; i <= span->chan_count; i++) {
+ block_channel(span->channels[i], stream);
+ }
+ }
+ stream->write_function(stream, "+OK blocked.\n");
goto done;
} else {
stream->write_function(stream, "-ERR invalid span.\n");
@@ -1204,13 +1547,40 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
}
+ if (!strcasecmp(argv[0], "unblock")) {
+ span_id = atoi(argv[1]);
+ if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+
+ if (span->start != ftdm_r2_start) {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+
+ if (argc > 2) {
+ chan_id = atoi(argv[2]);
+ if (chan_id && chan_id <= span->chan_count) {
+ unblock_channel(span->channels[chan_id], stream);
+ } else {
+ stream->write_function(stream, "-ERR invalid chan %d.\n", chan_id);
+ }
+ } else {
+ for (i = 1; i <= span->chan_count; i++) {
+ unblock_channel(span->channels[i], stream);
+ }
+ }
+
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+
+ }
+
if (!strcasecmp(argv[0], "status")) {
- int span_id = atoi(argv[1]);
- ftdm_r2_data_t *r2data = NULL;
- ftdm_span_t *span = NULL;
- openr2_chan_t *r2chan = NULL;
- openr2_context_t *r2context = NULL;
- int i = 0;
+ //openr2_chan_stats_t stats;
+ span_id = atoi(argv[1]);
if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
if (span->start != ftdm_r2_start) {
@@ -1222,27 +1592,43 @@ static FIO_API_FUNCTION(ftdm_r2_api)
goto done;
}
r2context = r2data->r2context;
- openr2_variant_t r2variant = openr2_context_get_variant(r2context);
+ r2variant = openr2_context_get_variant(r2context);
stream->write_function(stream,
"Variant: %s\n"
"Max ANI: %d\n"
"Max DNIS: %d\n"
"ANI First: %s\n"
- "Immediate Accept: %s\n",
+ "Immediate Accept: %s\n"
+ "Side: %s\n"
+ "Job Max ms: %d\n"
+ "Job Loops: %lu\n"
+ "Monitor Thread: %lu\n",
openr2_proto_get_variant_string(r2variant),
openr2_context_get_max_ani(r2context),
openr2_context_get_max_dnis(r2context),
openr2_context_get_ani_first(r2context) ? "Yes" : "No",
- openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+ openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
+ "no side",
+ r2data->jobmax,
+ r2data->loops,
+ r2data->monitor_thread_id);
stream->write_function(stream, "\n");
- stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
+ stream->write_function(stream, "%4s %-12.12s %-12.12s %6s %6s %6s %6s\n", "Channel", "Tx CAS", "Rx CAS",
+ "Rx Avg", "Tx Avg", "Rx", "Tx");
for (i = 1; i <= span->chan_count; i++) {
- if (i == 16) continue;
+ char rx_str[25];
+ char tx_str[25];
+ char rxavg_str[25];
+ char txavg_str[25];
r2chan = R2CALL(span->channels[i])->r2chan;
- stream->write_function(stream, "%4d %-12.12s %-12.12s\n",
- span->channels[i]->physical_chan_id,
+ stream->write_function(stream, "%4d %-12.12s %-12.12s %6s %6s %6s %6s\n",
+ span->channels[i]->chan_id,
openr2_chan_get_tx_cas_string(r2chan),
- openr2_chan_get_rx_cas_string(r2chan));
+ openr2_chan_get_rx_cas_string(r2chan),
+ rxavg_str,
+ txavg_str,
+ rx_str,
+ tx_str);
}
stream->write_function(stream, "\n");
stream->write_function(stream, "+OK.\n");
@@ -1341,7 +1727,7 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
return FTDM_SUCCESS;
}
-ftdm_module_t ftdm_module = {
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
"r2",
ftdm_r2_io_init,
NULL,
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
index 7234e67183..a975204b62 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
@@ -1725,7 +1725,7 @@ static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout)
ftdm_status_t status;
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
- status = ftdm_span_poll_event(span, ms_timeout);
+ status = ftdm_span_poll_event(span, ms_timeout, NULL);
switch(status) {
case FTDM_SUCCESS:
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
index f2e34e6c2c..970d006756 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
@@ -335,7 +335,26 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan)
acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF;
acm.bckCallInd.isdnAccInd.val = ISDNACC_NONISDN;
acm.bckCallInd.echoCtrlDevInd.pres = PRSNT_NODEF;
- acm.bckCallInd.echoCtrlDevInd.val = 0x1; /* ec device present */
+ switch (ftdmchan->caller_data.bearer_capability) {
+ /**********************************************************************/
+ case (FTDM_BEARER_CAP_SPEECH):
+ acm.bckCallInd.echoCtrlDevInd.val = 0x1;
+ break;
+ /**********************************************************************/
+ case (FTDM_BEARER_CAP_64K_UNRESTRICTED):
+ acm.bckCallInd.echoCtrlDevInd.val = 0x0;
+ break;
+ /**********************************************************************/
+ case (FTDM_BEARER_CAP_3_1KHZ_AUDIO):
+ acm.bckCallInd.echoCtrlDevInd.val = 0x1;
+ break;
+ /**********************************************************************/
+ default:
+ SS7_ERROR_CHAN(ftdmchan, "Unknown Bearer capability falling back to speech%s\n", " ");
+ acm.bckCallInd.echoCtrlDevInd.val = 0x1;
+ break;
+ /**********************************************************************/
+ } /* switch (ftdmchan->caller_data.bearer_capability) */
acm.bckCallInd.sccpMethInd.pres = PRSNT_NODEF;
acm.bckCallInd.sccpMethInd.val = SCCPMTH_NOIND;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
index 4d514caf86..4d497b599d 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
@@ -132,7 +132,8 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum)
tmp[0] = ftdm->cid_num.digits[k];
/* check if the digit is a number and that is not null */
- while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) {
+ while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
/* move on to the next value */
k++;
tmp[0] = ftdm->cid_num.digits[k];
@@ -141,14 +142,15 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum)
/* check if tmp is null or a digit */
if (tmp[0] != '\0') {
/* push it into the lower nibble */
- lower = atoi(&tmp[0]);
+ lower = strtol(&tmp[0], (char **)NULL, 16);
/* move to the next digit */
k++;
/* grab a digit from the ftdm digits */
tmp[0] = ftdm->cid_num.digits[k];
/* check if the digit is a number and that is not null */
- while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) {
+ while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
k++;
tmp[0] = ftdm->cid_num.digits[k];
} /* while(!(isdigit(tmp))) */
@@ -156,7 +158,7 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum)
/* check if tmp is null or a digit */
if (tmp[0] != '\0') {
/* push the digit into the upper nibble */
- upper = (atoi(&tmp[0])) << 4;
+ upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4;
} else {
/* there is no upper ... fill in 0 */
upper = 0x0;
@@ -243,7 +245,8 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum)
tmp[0] = ftdm->dnis.digits[k];
/* check if the digit is a number and that is not null */
- while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) {
+ while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
/* move on to the next value */
k++;
tmp[0] = ftdm->dnis.digits[k];
@@ -252,14 +255,15 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum)
/* check if tmp is null or a digit */
if (tmp[0] != '\0') {
/* push it into the lower nibble */
- lower = atoi(&tmp[0]);
+ lower = strtol(&tmp[0], (char **)NULL, 16);
/* move to the next digit */
k++;
/* grab a digit from the ftdm digits */
tmp[0] = ftdm->dnis.digits[k];
/* check if the digit is a number and that is not null */
- while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) {
+ while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
k++;
tmp[0] = ftdm->dnis.digits[k];
} /* while(!(isdigit(tmp))) */
@@ -267,7 +271,7 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum)
/* check if tmp is null or a digit */
if (tmp[0] != '\0') {
/* push the digit into the upper nibble */
- upper = (atoi(&tmp[0])) << 4;
+ upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4;
} else {
/* there is no upper ... fill in ST */
upper = 0xF0;
@@ -984,6 +988,7 @@ ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int ty
/* confirm it is a digit */
if (!isdigit(tmp[0])) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
/* move to the next character in subAddr */
x++;
@@ -1068,6 +1073,7 @@ ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int typ
/* confirm it is a hex digit */
while ((!isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
/* move to the next character in subAddr */
x++;
tmp[0] = subAddr[x];
@@ -1084,6 +1090,7 @@ ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int typ
/* check if the digit is a hex digit and that is not null */
while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+ SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
x++;
tmp[0] = subAddr[x];
} /* while(!(isdigit(tmp))) */
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
index 23463e9088..86940107e7 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
@@ -899,11 +899,11 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
continue; /* should never happen but happens when shutting down */
}
pfds[j] = ftdmchan->mod_data;
- inflags[j] = POLLPRI;
+ inflags[j] = poll_events ? poll_events[j] : POLLPRI;
#else
memset(&pfds[j], 0, sizeof(pfds[j]));
pfds[j].fd = span->channels[i]->sockfd;
- pfds[j].events = POLLPRI;
+ pfds[j].events = poll_events ? poll_events[j] : POLLPRI;
#endif
/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index 1efe459032..64ecc2e357 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -459,7 +459,7 @@ struct ftdm_memory_handler {
#define FIO_CHANNEL_GET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status)
#define FIO_SPAN_SET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status)
#define FIO_SPAN_GET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
-#define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms)
+#define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms, short *poll_events)
#define FIO_SPAN_NEXT_EVENT_ARGS (ftdm_span_t *span, ftdm_event_t **event)
#define FIO_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg)
#define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event)
@@ -817,12 +817,13 @@ FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan);
*
* \param span The span to wait events for
* \param ms Milliseconds timeout
+ * \param poll_events Array of events to poll for, for each channel on the span
*
* \retval FTDM_SUCCESS success (at least one event available)
* \retval FTDM_TIMEOUT Timed out waiting for events
* \retval FTDM_FAIL failure
*/
-FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms);
+FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms, short *poll_events);
/*!
* \brief Find a span by its id