diff --git a/Makefile.am b/Makefile.am
index eb43ba4029..10e35c8694 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -566,6 +566,7 @@ update-clean: clean modwipe uninstall libs/openzap/Makefile python-reconf
cd libs/portaudio && $(MAKE) clean
cd libs/speex && $(MAKE) clean
cd libs/esl && $(MAKE) clean
+ cd libs/sqlite && $(MAKE) clean
swigall:
@echo reswigging all
diff --git a/conf/autoload_configs/sofia.conf.xml b/conf/autoload_configs/sofia.conf.xml
index 24252d08ce..a5e8614322 100644
--- a/conf/autoload_configs/sofia.conf.xml
+++ b/conf/autoload_configs/sofia.conf.xml
@@ -4,6 +4,7 @@
+
+
diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml
index 2dd094a656..3b19b6ecc6 100644
--- a/conf/sip_profiles/internal.xml
+++ b/conf/sip_profiles/internal.xml
@@ -42,7 +42,8 @@
-
+
+
diff --git a/libs/freetdm/conf/freetdm.conf b/libs/freetdm/conf/freetdm.conf
index cd269b7736..eb506bef8d 100644
--- a/libs/freetdm/conf/freetdm.conf
+++ b/libs/freetdm/conf/freetdm.conf
@@ -34,6 +34,12 @@ trunk_type => FXS
; add FXS channels from 3 to 4 at wanpipe span 1 to this freetdm span
fxs-channel => 1:3-4
+; IO stats. Defaults to yes, you can print the stats with ftdm iostats print
+; This feature depends on the span IO type, currently only Wanpipe spans support it
+; This may cause a warning to be printed once in a while if audio is not provided fast enough
+; and causes the driver to transmit an idle frame (when there is no data provided by the application)
+iostats => yes
+
[span wanpipe myWanpipe2]
trunk_type => FXO
; This number will be used as DNIS for FXO devices
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index d4c85d3998..5117c6dbe8 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -3790,588 +3790,713 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
switch_channel_cause2str(caller_data->hangup_cause));
}
-#define FT_SYNTAX "USAGE:\n" \
-"--------------------------------------------------------------------------------\n" \
-"ftdm list\n" \
-"ftdm start|stop \n" \
-"ftdm restart []\n" \
-"ftdm dump []\n" \
-"ftdm sigstatus get|set [] [] []\n" \
-"ftdm trace []\n" \
-"ftdm notrace []\n" \
-"ftdm q931_pcap on|off [pcapfilename without suffix]\n" \
-"ftdm gains []\n" \
-"ftdm dtmf on|off []\n" \
-"ftdm queuesize []\n" \
-"--------------------------------------------------------------------------------\n"
+
+static switch_status_t ftdm_cmd_voice_detect(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ stream->write_function(stream, "IMPLEMENT ME!\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_list(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ int j;
+ for (j = 0 ; j < FTDM_MAX_SPANS_INTERFACE; j++) {
+ ftdm_channel_t *fchan;
+ ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE;
+ const char *flags = "none";
+ ftdm_signaling_status_t sigstatus;
+
+ if (!SPAN_CONFIG[j].span) {
+ continue;
+ }
+
+ if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) {
+ flags = "3way";
+ } else if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_CALL_SWAP) {
+ flags = "call swap";
+ }
+ fchan = ftdm_span_get_channel(SPAN_CONFIG[j].span, 1);
+ ftdm_channel_get_alarms(fchan, &alarmbits);
+
+ if ((FTDM_SUCCESS == ftdm_span_get_sig_status(SPAN_CONFIG[j].span, &sigstatus))) {
+ stream->write_function(stream,
+ "+OK\n"
+ "span: %u (%s)\n"
+ "type: %s\n"
+ "physical_status: %s\n"
+ "signaling_status: %s\n"
+ "chan_count: %u\n"
+ "dialplan: %s\n"
+ "context: %s\n"
+ "dial_regex: %s\n"
+ "fail_dial_regex: %s\n"
+ "hold_music: %s\n"
+ "analog_options: %s\n",
+ j,
+ ftdm_span_get_name(SPAN_CONFIG[j].span),
+ SPAN_CONFIG[j].type,
+ alarmbits ? "alarmed" : "ok",
+ ftdm_signaling_status2str(sigstatus),
+ ftdm_span_get_chan_count(SPAN_CONFIG[j].span),
+ SPAN_CONFIG[j].dialplan,
+ SPAN_CONFIG[j].context,
+ SPAN_CONFIG[j].dial_regex,
+ SPAN_CONFIG[j].fail_dial_regex,
+ SPAN_CONFIG[j].hold_music,
+ flags
+ );
+ } else {
+ stream->write_function(stream,
+ "+OK\n"
+ "span: %u (%s)\n"
+ "type: %s\n"
+ "physical_status: %s\n"
+ "chan_count: %u\n"
+ "dialplan: %s\n"
+ "context: %s\n"
+ "dial_regex: %s\n"
+ "fail_dial_regex: %s\n"
+ "hold_music: %s\n"
+ "analog_options: %s\n",
+ j,
+ ftdm_span_get_name(SPAN_CONFIG[j].span),
+ SPAN_CONFIG[j].type,
+ alarmbits ? "alarmed" : "ok",
+ ftdm_span_get_chan_count(SPAN_CONFIG[j].span),
+ SPAN_CONFIG[j].dialplan,
+ SPAN_CONFIG[j].context,
+ SPAN_CONFIG[j].dial_regex,
+ SPAN_CONFIG[j].fail_dial_regex,
+ SPAN_CONFIG[j].hold_music,
+ flags);
+ }
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_start_stop(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ char *span_name = argv[1];
+ ftdm_span_t *span = NULL;
+ ftdm_status_t status;
+
+ if (span_name) {
+ ftdm_span_find_by_name(span_name, &span);
+ }
+
+ if (!span) {
+ stream->write_function(stream, "-ERR no span\n");
+ goto end;
+ }
+
+ if (!strcasecmp(argv[0], "stop")) {
+ status = ftdm_span_stop(span);
+ } else {
+ status = ftdm_span_start(span);
+ }
+
+ stream->write_function(stream, status == FTDM_SUCCESS ? "+OK\n" : "-ERR failure\n");
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_reset(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ uint32_t chan_id = 0;
+ uint32_t ccount = 0;
+ ftdm_channel_t *chan;
+ ftdm_span_t *span = NULL;
+ if (argc < 2) {
+ stream->write_function(stream, "-ERR Usage: ftdm reset []\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[1], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ if (argc > 2) {
+ chan_id = atoi(argv[2]);
+ if (chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ if (chan_id) {
+ chan = ftdm_span_get_channel(span, chan_id);
+ if (!chan) {
+ stream->write_function(stream, "-ERR Could not find chan\n");
+ goto end;
+ }
+ stream->write_function(stream, "Resetting channel %s:%s\n", argv[1], argv[2]);
+ ftdm_channel_reset(chan);
+ } else {
+ uint32_t i = 0;
+ ccount = ftdm_span_get_chan_count(span);
+ for (i = 1; i < ccount; i++) {
+ chan = ftdm_span_get_channel(span, i);
+ stream->write_function(stream, "Resetting channel %s:%d\n", argv[1], i);
+ ftdm_channel_reset(chan);
+ }
+ }
+
+end:
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_dump(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *curr = NULL;
+ uint32_t chan_id = 0;
+ ftdm_span_t *span;
+ char *as = NULL;
+
+ if (argc < 2) {
+ stream->write_function(stream, "-ERR Usage: ftdm dump []\n");
+ goto end;
+ }
+
+ ftdm_span_find_by_name(argv[1], &span);
+
+ if (argc > 2) {
+ if (argv[3] && !strcasecmp(argv[2], "as")) {
+ as = argv[3];
+ } else {
+ chan_id = atoi(argv[2]);
+ }
+ }
+
+ if (argv[4] && !strcasecmp(argv[3], "as")) {
+ as = argv[4];
+ }
+
+ if (!zstr(as) && !strcasecmp(as, "xml")) {
+ stream->write_function(stream, "\n");
+ if (!span) {
+ stream->write_function(stream, "invalid span\n");
+ } else {
+ if (chan_id) {
+ if(chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "invalid channel\n");
+ } else {
+ dump_chan_xml(span, chan_id, stream);
+ }
+ } else {
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+ dump_chan_xml(span, ftdm_channel_get_id(ftdm_iterator_current(curr)), stream);
+ }
+ ftdm_iterator_free(chaniter);
+ }
+ }
+ stream->write_function(stream, "\n");
+ } else {
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ } else {
+ if (chan_id) {
+ if(chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "-ERR invalid channel\n");
+ } else {
+ char *dbgstr = NULL;
+ ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
+ dump_chan(span, chan_id, stream);
+ dbgstr = ftdm_channel_get_history_str(fchan);
+ stream->write_function(stream, "%s\n", dbgstr);
+ ftdm_free(dbgstr);
+ }
+ } else {
+ stream->write_function(stream, "+OK\n");
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+ dump_chan(span, ftdm_channel_get_id(ftdm_iterator_current(curr)), stream);
+ }
+ ftdm_iterator_free(chaniter);
+ }
+ }
+ }
+
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_sigstatus(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ ftdm_span_t *span = NULL;
+ ftdm_signaling_status_t sigstatus;
+
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [] [] []\n");
+ goto end;
+ }
+ if (!strcasecmp(argv[1], "get") && argc < 3) {
+ stream->write_function(stream, "-ERR sigstatus get usage: get \n");
+ goto end;
+ }
+ if (!strcasecmp(argv[1], "set") && argc != 5) {
+ stream->write_function(stream, "-ERR sigstatus set usage: set |all \n");
+ goto end;
+ }
+
+ ftdm_span_find_by_name(argv[2], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ if (!strcasecmp(argv[1], "get")) {
+ if (argc == 4) {
+ uint32_t chan_id = atol(argv[3]);
+ ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
+ if (!fchan) {
+ stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
+ goto end;
+ }
+
+ if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) {
+ stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to get channel sigstatus\n");
+ }
+ goto end;
+ } else {
+ if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) {
+ stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span));
+ }
+ }
+ goto end;
+ }
+ if (!strcasecmp(argv[1], "set")) {
+ sigstatus = ftdm_str2ftdm_signaling_status(argv[4]);
+
+ if (!strcasecmp(argv[3], "all")) {
+ if ((FTDM_SUCCESS == ftdm_span_set_sig_status(span, sigstatus))) {
+ stream->write_function(stream, "Signaling status of all channels from span %s set to %s\n",
+ ftdm_span_get_name(span), ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
+ }
+ goto end;
+ } else {
+ uint32_t chan_id = atol(argv[3]);
+ ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
+ if (!fchan) {
+ stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
+ goto end;
+ }
+
+ if ((FTDM_SUCCESS == ftdm_channel_set_sig_status(fchan, sigstatus))) {
+ stream->write_function(stream, "Signaling status of channel %d set to %s\n", chan_id,
+ ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
+ }
+ goto end;
+ }
+ }
+
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_trace(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ char tracepath[255];
+ unsigned i = 0;
+ uint32_t chan_id = 0;
+ uint32_t span_id = 0;
+ uint32_t chan_count = 0;
+ ftdm_span_t *span = NULL;
+ ftdm_channel_t *chan = NULL;
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ftdm trace []\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[2], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ chan_count = ftdm_span_get_chan_count(span);
+ if (argc > 3) {
+ chan_id = atoi(argv[3]);
+ if (chan_id > chan_count) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ span_id = ftdm_span_get_id(span);
+ if (chan_id) {
+ chan = ftdm_span_get_channel(span, chan_id);
+ snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, chan_id);
+ ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
+ snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, chan_id);
+ ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
+ } else {
+ for (i = 1; i <= chan_count; i++) {
+ chan = ftdm_span_get_channel(span, i);
+ snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, i);
+ ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
+ snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, i);
+ ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
+ }
+ }
+ stream->write_function(stream, "+OK trace enabled with prefix path %s\n", argv[1]);
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_notrace(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ uint32_t i = 0;
+ uint32_t chan_id = 0;
+ uint32_t chan_count = 0;
+ ftdm_channel_t *fchan = NULL;
+ ftdm_span_t *span = NULL;
+ if (argc < 2) {
+ stream->write_function(stream, "-ERR Usage: ftdm notrace []\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[1], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ chan_count = ftdm_span_get_chan_count(span);
+ if (argc > 2) {
+ chan_id = atoi(argv[2]);
+ if (chan_id > chan_count) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ if (chan_id) {
+ fchan = ftdm_span_get_channel(span, chan_id);
+ ftdm_channel_command(fchan, FTDM_COMMAND_TRACE_END_ALL, NULL);
+ } else {
+ for (i = 1; i <= chan_count; i++) {
+ fchan = ftdm_span_get_channel(span, i);
+ ftdm_channel_command(fchan, FTDM_COMMAND_TRACE_END_ALL, NULL);
+ }
+ }
+ stream->write_function(stream, "+OK trace disabled\n");
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_gains(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ unsigned int i = 0;
+ float txgain = 0.0;
+ float rxgain = 0.0;
+ uint32_t chan_id = 0;
+ uint32_t ccount = 0;
+ ftdm_channel_t *chan;
+ ftdm_span_t *span = NULL;
+ if (argc < 4) {
+ stream->write_function(stream, "-ERR Usage: ftdm gains []\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[3], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ if (argc > 4) {
+ chan_id = atoi(argv[4]);
+ if (chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ i = sscanf(argv[1], "%f", &rxgain);
+ i += sscanf(argv[2], "%f", &txgain);
+ if (i != 2) {
+ stream->write_function(stream, "-ERR invalid gains\n");
+ goto end;
+ }
+
+ if (chan_id) {
+ chan = ftdm_span_get_channel(span, chan_id);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_GAIN, &rxgain);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_GAIN, &txgain);
+ } else {
+ ccount = ftdm_span_get_chan_count(span);
+ for (i = 1; i < ccount; i++) {
+ chan = ftdm_span_get_channel(span, i);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_GAIN, &rxgain);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_GAIN, &txgain);
+ }
+ }
+ stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_dtmf(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ unsigned i = 0;
+ uint32_t chan_id = 0;
+ unsigned schan_count = 0;
+ ftdm_span_t *span = NULL;
+ ftdm_command_t fcmd = FTDM_COMMAND_ENABLE_DTMF_DETECT;
+ ftdm_channel_t *fchan;
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: dtmf on|off []\n");
+ goto end;
+ }
+
+ if (switch_true(argv[1])) {
+ fcmd = FTDM_COMMAND_ENABLE_DTMF_DETECT;
+ } else {
+ fcmd = FTDM_COMMAND_DISABLE_DTMF_DETECT;
+ }
+
+ ftdm_span_find_by_name(argv[2], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ schan_count = ftdm_span_get_chan_count(span);
+ if (argc > 3) {
+ chan_id = atoi(argv[3]);
+ if (chan_id > schan_count) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+
+ if (chan_id) {
+ fchan = ftdm_span_get_channel(span, chan_id);
+ ftdm_channel_command(fchan, fcmd, NULL);
+ } else {
+ for (i = 1; i <= schan_count; i++) {
+ fchan = ftdm_span_get_channel(span, i);
+ ftdm_channel_command(fchan, fcmd, NULL);
+ }
+ }
+
+ stream->write_function(stream, "+OK DTMF detection was %s\n", fcmd == FTDM_COMMAND_ENABLE_DTMF_DETECT ? "enabled" : "disabled");
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t ftdm_cmd_queuesize(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ unsigned int i = 0;
+ uint32_t rxsize = 10;
+ uint32_t txsize = 10;
+ uint32_t chan_id = 0;
+ uint32_t ccount = 0;
+ ftdm_channel_t *chan;
+ ftdm_span_t *span = NULL;
+ if (argc < 4) {
+ stream->write_function(stream, "-ERR Usage: ftdm queuesize []\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[3], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ if (argc > 4) {
+ chan_id = atoi(argv[4]);
+ if (chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ }
+ i = sscanf(argv[1], "%u", &rxsize);
+ i += sscanf(argv[2], "%u", &txsize);
+ if (i != 2) {
+ stream->write_function(stream, "-ERR invalid queue sizes provided\n");
+ goto end;
+ }
+
+ if (chan_id) {
+ chan = ftdm_span_get_channel(span, chan_id);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_QUEUE_SIZE, &rxsize);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txsize);
+ } else {
+ ccount = ftdm_span_get_chan_count(span);
+ for (i = 1; i < ccount; i++) {
+ chan = ftdm_span_get_channel(span, i);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_QUEUE_SIZE, &rxsize);
+ ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txsize);
+ }
+ }
+ stream->write_function(stream, "+OK queue sizes set to Rx %d and Tx %d\n", rxsize, txsize);
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static void exec_io_command(const char *cmd, switch_stream_handle_t *stream, ftdm_channel_t *fchan)
+{
+ int enable = 0;
+ ftdm_channel_iostats_t stats;
+ if (!strcasecmp("enable", cmd)) {
+ enable = 1;
+ ftdm_channel_command(fchan, FTDM_COMMAND_SWITCH_IOSTATS, &enable);
+ } else if (!strcasecmp("disable", cmd)) {
+ enable = 0;
+ ftdm_channel_command(fchan, FTDM_COMMAND_SWITCH_IOSTATS, &enable);
+ } else if (!strcasecmp("flush", cmd)) {
+ ftdm_channel_command(fchan, FTDM_COMMAND_FLUSH_IOSTATS, NULL);
+ } else {
+ ftdm_channel_command(fchan, FTDM_COMMAND_GET_IOSTATS, &stats);
+ stream->write_function(stream, "-- IO statistics for channel %d:%d --\n",
+ ftdm_channel_get_span_id(fchan), ftdm_channel_get_id(fchan));
+ stream->write_function(stream, "Rx errors: %u\n", stats.rx.errors);
+ stream->write_function(stream, "Rx queue size: %u\n", stats.rx.queue_size);
+ stream->write_function(stream, "Rx queue len: %u\n", stats.rx.queue_len);
+ stream->write_function(stream, "Rx count: %lu\n", stats.rx.packets);
+
+ stream->write_function(stream, "Tx errors: %u\n", stats.tx.errors);
+ stream->write_function(stream, "Tx queue size: %u\n", stats.tx.queue_size);
+ stream->write_function(stream, "Tx queue len: %u\n", stats.tx.queue_len);
+ stream->write_function(stream, "Tx count: %lu\n", stats.tx.packets);
+ stream->write_function(stream, "Tx idle: %u\n", stats.tx.idle_packets);
+ }
+}
+
+static switch_status_t ftdm_cmd_iostats(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[])
+{
+ uint32_t chan_id = 0;
+ ftdm_channel_t *chan;
+ ftdm_iterator_t *iter = NULL;
+ ftdm_iterator_t *curr = NULL;
+ ftdm_span_t *span = NULL;
+
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ftdm iostats enable|disable|flush|print []\n");
+ goto end;
+ }
+
+ ftdm_span_find_by_name(argv[2], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ if (argc > 3) {
+ chan_id = atoi(argv[3]);
+ if (chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ chan = ftdm_span_get_channel(span, chan_id);
+ exec_io_command(argv[1], stream, chan);
+ } else {
+ iter = ftdm_span_get_chan_iterator(span, NULL);
+ for (curr = iter; curr; curr = ftdm_iterator_next(curr)) {
+ chan = ftdm_iterator_current(curr);
+ exec_io_command(argv[1], stream, chan);
+ }
+ ftdm_iterator_free(iter);
+ }
+ stream->write_function(stream, "+OK\n");
+end:
+ return SWITCH_STATUS_SUCCESS;
+}
+
+typedef switch_status_t (*ftdm_cli_function_t)(const char *cmd, switch_core_session_t *session,
+ switch_stream_handle_t *stream, int argc, char *argv[]);
+typedef struct ftdm_cli_entry {
+ const char *name;
+ const char *args;
+ const char *complete;
+ ftdm_cli_function_t execute;
+} ftdm_cli_entry_t;
+
+static ftdm_cli_entry_t ftdm_cli_options[] =
+{
+ { "list", "", "", ftdm_cmd_list },
+ { "start", "", "", ftdm_cmd_start_stop },
+ { "stop", "", "", ftdm_cmd_start_stop },
+ { "reset", " []", "", ftdm_cmd_reset },
+ { "dump", " []", "", ftdm_cmd_dump },
+ { "sigstatus", "get|set [] []", "::[set:get", ftdm_cmd_sigstatus },
+ { "trace", " []", "", ftdm_cmd_trace },
+ { "notrace", " []", "", ftdm_cmd_notrace },
+ { "gains", " []", "", ftdm_cmd_gains },
+ { "dtmf", "on|off []", "::[on:off", ftdm_cmd_dtmf },
+ { "queuesize", " []", "", ftdm_cmd_queuesize },
+ { "iostats", "enable|disable|flush|print ", "::[enable:disable:flush:print", ftdm_cmd_iostats },
+ { "voice_detect", "[on|off] []", "::[on:off", ftdm_cmd_voice_detect },
+
+ /* Fake handlers as they are handled within freetdm library,
+ * we should provide a way inside freetdm to query for completions from signaling modules */
+ { "core state", "[!]", "", NULL },
+ { "core flag", "[!]", "", NULL },
+ { "core calls", "", "", NULL },
+};
+
+static void print_full_usage(switch_stream_handle_t *stream)
+{
+ int i = 0;
+ ftdm_cli_entry_t *entry = NULL;
+ stream->write_function(stream, "USAGE:\n");
+ stream->write_function(stream, "--------------------------------------------------------------------------------\n");
+ for (i = 0 ; i < ftdm_array_len(ftdm_cli_options); i++) {
+ entry = &ftdm_cli_options[i];
+ stream->write_function(stream, "ftdm %s %s\n", entry->name, entry->args);
+ }
+ stream->write_function(stream, "--------------------------------------------------------------------------------\n");
+}
+
SWITCH_STANDARD_API(ft_function)
{
char *mycmd = NULL, *argv[10] = { 0 };
int argc = 0;
- ftdm_iterator_t *chaniter = NULL;
- ftdm_iterator_t *curr = NULL;
+ int i = 0;
+ ftdm_cli_entry_t *entry = NULL;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (!argc) {
- stream->write_function(stream, "%s", FT_SYNTAX);
+ print_full_usage(stream);
goto end;
}
- if (!strcasecmp(argv[0], "sigstatus")) {
- ftdm_span_t *span = NULL;
- ftdm_signaling_status_t sigstatus;
-
- if (argc < 3) {
- stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [] [] []\n");
- goto end;
+ for (i = 0 ; i < ftdm_array_len(ftdm_cli_options); i++) {
+ entry = &ftdm_cli_options[i];
+ if (!strcasecmp(argv[0], entry->name) && entry->execute) {
+ entry->execute(cmd, session, stream, argc, argv);
+ break;
}
- if (!strcasecmp(argv[1], "get") && argc < 3) {
- stream->write_function(stream, "-ERR sigstatus get usage: get \n");
- goto end;
- }
- if (!strcasecmp(argv[1], "set") && argc != 5) {
- stream->write_function(stream, "-ERR sigstatus set usage: set |all \n");
- goto end;
- }
-
- ftdm_span_find_by_name(argv[2], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
-
- if (!strcasecmp(argv[1], "get")) {
- if (argc == 4) {
- uint32_t chan_id = atol(argv[3]);
- ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
- if (!fchan) {
- stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
- goto end;
- }
-
- if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) {
- stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus));
- } else {
- stream->write_function(stream, "-ERR failed to get channel sigstatus\n");
- }
- goto end;
- } else {
- if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) {
- stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus));
- } else {
- stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span));
- }
- }
- goto end;
- }
- if (!strcasecmp(argv[1], "set")) {
- sigstatus = ftdm_str2ftdm_signaling_status(argv[4]);
-
- if (!strcasecmp(argv[3], "all")) {
- if ((FTDM_SUCCESS == ftdm_span_set_sig_status(span, sigstatus))) {
- stream->write_function(stream, "Signaling status of all channels from span %s set to %s\n",
- ftdm_span_get_name(span), ftdm_signaling_status2str(sigstatus));
- } else {
- stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
- }
- goto end;
- } else {
- uint32_t chan_id = atol(argv[3]);
- ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
- if (!fchan) {
- stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
- goto end;
- }
-
- if ((FTDM_SUCCESS == ftdm_channel_set_sig_status(fchan, sigstatus))) {
- stream->write_function(stream, "Signaling status of channel %d set to %s\n", chan_id,
- ftdm_signaling_status2str(sigstatus));
- } else {
- stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
- }
- goto end;
- }
- }
-
- } else if (!strcasecmp(argv[0], "dump")) {
- if (argc < 2) {
- stream->write_function(stream, "-ERR Usage: ftdm dump []\n");
- goto end;
- } else {
- uint32_t chan_id = 0;
- ftdm_span_t *span;
- char *as = NULL;
-
- ftdm_span_find_by_name(argv[1], &span);
-
- if (argc > 2) {
- if (argv[3] && !strcasecmp(argv[2], "as")) {
- as = argv[3];
- } else {
- chan_id = atoi(argv[2]);
- }
- }
-
- if (argv[4] && !strcasecmp(argv[3], "as")) {
- as = argv[4];
- }
-
- if (!zstr(as) && !strcasecmp(as, "xml")) {
- stream->write_function(stream, "\n");
- if (!span) {
- stream->write_function(stream, "invalid span\n");
- } else {
- if (chan_id) {
- if(chan_id > ftdm_span_get_chan_count(span)) {
- stream->write_function(stream, "invalid channel\n");
- } else {
- dump_chan_xml(span, chan_id, stream);
- }
- } else {
- chaniter = ftdm_span_get_chan_iterator(span, NULL);
- for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
- dump_chan_xml(span, ftdm_channel_get_id(ftdm_iterator_current(curr)), stream);
- }
- ftdm_iterator_free(chaniter);
-
- }
- }
- stream->write_function(stream, "\n");
- } else {
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- } else {
- if (chan_id) {
- if(chan_id > ftdm_span_get_chan_count(span)) {
- stream->write_function(stream, "-ERR invalid channel\n");
- } else {
- char *dbgstr = NULL;
- ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
- dump_chan(span, chan_id, stream);
- dbgstr = ftdm_channel_get_history_str(fchan);
- stream->write_function(stream, "%s\n", dbgstr);
- ftdm_free(dbgstr);
- }
- } else {
- stream->write_function(stream, "+OK\n");
- chaniter = ftdm_span_get_chan_iterator(span, NULL);
- for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
- dump_chan(span, ftdm_channel_get_id(ftdm_iterator_current(curr)), stream);
- }
- ftdm_iterator_free(chaniter);
-
- }
- }
- }
- }
- } else if (!strcasecmp(argv[0], "list")) {
- int j;
- for (j = 0 ; j < FTDM_MAX_SPANS_INTERFACE; j++) {
- if (SPAN_CONFIG[j].span) {
- ftdm_channel_t *fchan;
- ftdm_alarm_flag_t alarmbits = FTDM_ALARM_NONE;
- const char *flags = "none";
- ftdm_signaling_status_t sigstatus;
-
- if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) {
- flags = "3way";
- } else if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_CALL_SWAP) {
- flags = "call swap";
- }
- fchan = ftdm_span_get_channel(SPAN_CONFIG[j].span, 1);
- ftdm_channel_get_alarms(fchan, &alarmbits);
-
- if ((FTDM_SUCCESS == ftdm_span_get_sig_status(SPAN_CONFIG[j].span, &sigstatus))) {
- stream->write_function(stream,
- "+OK\n"
- "span: %u (%s)\n"
- "type: %s\n"
- "physical_status: %s\n"
- "signaling_status: %s\n"
- "chan_count: %u\n"
- "dialplan: %s\n"
- "context: %s\n"
- "dial_regex: %s\n"
- "fail_dial_regex: %s\n"
- "hold_music: %s\n"
- "analog_options: %s\n",
- j,
- ftdm_span_get_name(SPAN_CONFIG[j].span),
- SPAN_CONFIG[j].type,
- alarmbits ? "alarmed" : "ok",
- ftdm_signaling_status2str(sigstatus),
- ftdm_span_get_chan_count(SPAN_CONFIG[j].span),
- SPAN_CONFIG[j].dialplan,
- SPAN_CONFIG[j].context,
- SPAN_CONFIG[j].dial_regex,
- SPAN_CONFIG[j].fail_dial_regex,
- SPAN_CONFIG[j].hold_music,
- flags
- );
- } else {
- stream->write_function(stream,
- "+OK\n"
- "span: %u (%s)\n"
- "type: %s\n"
- "physical_status: %s\n"
- "chan_count: %u\n"
- "dialplan: %s\n"
- "context: %s\n"
- "dial_regex: %s\n"
- "fail_dial_regex: %s\n"
- "hold_music: %s\n"
- "analog_options: %s\n",
- j,
- ftdm_span_get_name(SPAN_CONFIG[j].span),
- SPAN_CONFIG[j].type,
- alarmbits ? "alarmed" : "ok",
- ftdm_span_get_chan_count(SPAN_CONFIG[j].span),
- SPAN_CONFIG[j].dialplan,
- SPAN_CONFIG[j].context,
- SPAN_CONFIG[j].dial_regex,
- SPAN_CONFIG[j].fail_dial_regex,
- SPAN_CONFIG[j].hold_music,
- flags
- );
- }
- }
- }
- } else if (!strcasecmp(argv[0], "stop") || !strcasecmp(argv[0], "start")) {
- char *span_name = argv[1];
- ftdm_span_t *span = NULL;
- ftdm_status_t status;
-
- if (span_name) {
- ftdm_span_find_by_name(span_name, &span);
- }
-
- if (!span) {
- stream->write_function(stream, "-ERR no span\n");
- goto end;
- }
-
- if (!strcasecmp(argv[0], "stop")) {
- status = ftdm_span_stop(span);
- } else {
- status = ftdm_span_start(span);
- }
-
- stream->write_function(stream, status == FTDM_SUCCESS ? "+OK\n" : "-ERR failure\n");
-
- goto end;
-
- /*Q931ToPcap enhancement*/
- } else if (!strcasecmp(argv[0], "q931_pcap")) {
- int32_t span_id = 0;
- ftdm_span_t *span;
- const char *pcapfn = NULL;
- char *tmp_path = NULL;
-
- if (argc < 3) {
- stream->write_function(stream, "-ERR Usage: ftdm q931_pcap on|off [pcapfilename without suffix]\n");
- goto end;
- }
- span_id = atoi(argv[1]);
- if (!(span_id && (span = SPAN_CONFIG[span_id].span))) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
-
- /*Look for a given file name or use default file name*/
- if (argc > 3) {
- if(argv[3]){
- pcapfn=argv[3];
- }
- }
- else {
- pcapfn="q931";
- }
-
- /*Add log directory path to file name*/
- tmp_path=switch_mprintf("%s%s%s.pcap", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, pcapfn);
-
- if(!strcasecmp(argv[2], "on")) {
- if (ftdm_configure_span(span, "isdn", on_clear_channel_signal, "q931topcap", 1, "pcapfilename", tmp_path, FTDM_TAG_END) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_WARNING, "Error couldn't (re-)enable Q931-To-Pcap!\n");
- goto end;
- } else {
- stream->write_function(stream, "+OK\n");
- }
- } else if(!strcasecmp(argv[2], "off")) {
- if (ftdm_configure_span(span, "isdn", on_clear_channel_signal, "q931topcap", 0, FTDM_TAG_END) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_ERROR, "Error couldn't enable Q931-To-Pcap!\n");
- goto end;
- } else {
- stream->write_function(stream, "+OK\n");
- }
- } else {
- stream->write_function(stream, "-ERR Usage: ft q931_pcap on|off [pcapfilename without suffix]\n");
- goto end;
- }
-
- } else if (!strcasecmp(argv[0], "dtmf")) {
- unsigned i = 0;
- uint32_t chan_id = 0;
- unsigned schan_count = 0;
- ftdm_span_t *span = NULL;
- ftdm_command_t fcmd = FTDM_COMMAND_ENABLE_DTMF_DETECT;
- ftdm_channel_t *fchan;
- if (argc < 3) {
- stream->write_function(stream, "-ERR Usage: dtmf on|off []\n");
- goto end;
- }
-
- if (switch_true(argv[1])) {
- fcmd = FTDM_COMMAND_ENABLE_DTMF_DETECT;
- } else {
- fcmd = FTDM_COMMAND_DISABLE_DTMF_DETECT;
- }
-
- ftdm_span_find_by_name(argv[2], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
- schan_count = ftdm_span_get_chan_count(span);
- if (argc > 3) {
- chan_id = atoi(argv[3]);
- if (chan_id > schan_count) {
- stream->write_function(stream, "-ERR invalid chan\n");
- goto end;
- }
- }
-
- if (chan_id) {
- fchan = ftdm_span_get_channel(span, chan_id);
- ftdm_channel_command(fchan, fcmd, NULL);
- } else {
- for (i = 1; i <= schan_count; i++) {
- fchan = ftdm_span_get_channel(span, i);
- ftdm_channel_command(fchan, fcmd, NULL);
- }
- }
-
- stream->write_function(stream, "+OK DTMF detection was %s\n", fcmd == FTDM_COMMAND_ENABLE_DTMF_DETECT ? "enabled" : "disabled");
- } else if (!strcasecmp(argv[0], "trace")) {
- char tracepath[255];
- unsigned i = 0;
- uint32_t chan_id = 0;
- uint32_t span_id = 0;
- uint32_t chan_count = 0;
- ftdm_span_t *span = NULL;
- ftdm_channel_t *chan = NULL;
- if (argc < 3) {
- stream->write_function(stream, "-ERR Usage: ftdm trace []\n");
- goto end;
- }
- ftdm_span_find_by_name(argv[2], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
- chan_count = ftdm_span_get_chan_count(span);
- if (argc > 3) {
- chan_id = atoi(argv[3]);
- if (chan_id > chan_count) {
- stream->write_function(stream, "-ERR invalid chan\n");
- goto end;
- }
- }
- span_id = ftdm_span_get_id(span);
- if (chan_id) {
- chan = ftdm_span_get_channel(span, chan_id);
- snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, chan_id);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
- snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, chan_id);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
- } else {
- for (i = 1; i <= chan_count; i++) {
- chan = ftdm_span_get_channel(span, i);
- snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, i);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
- snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, i);
- ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
- }
- }
- stream->write_function(stream, "+OK trace enabled with prefix path %s\n", argv[1]);
- } else if (!strcasecmp(argv[0], "notrace")) {
- uint32_t i = 0;
- uint32_t chan_id = 0;
- uint32_t chan_count = 0;
- ftdm_channel_t *fchan = NULL;
- ftdm_span_t *span = NULL;
- if (argc < 2) {
- stream->write_function(stream, "-ERR Usage: ftdm notrace []\n");
- goto end;
- }
- ftdm_span_find_by_name(argv[1], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
- chan_count = ftdm_span_get_chan_count(span);
- if (argc > 2) {
- chan_id = atoi(argv[2]);
- if (chan_id > chan_count) {
- stream->write_function(stream, "-ERR invalid chan\n");
- goto end;
- }
- }
- if (chan_id) {
- fchan = ftdm_span_get_channel(span, chan_id);
- ftdm_channel_command(fchan, FTDM_COMMAND_TRACE_END_ALL, NULL);
- } else {
- for (i = 1; i <= chan_count; i++) {
- fchan = ftdm_span_get_channel(span, i);
- ftdm_channel_command(fchan, FTDM_COMMAND_TRACE_END_ALL, NULL);
- }
- }
- stream->write_function(stream, "+OK trace disabled\n");
- } else if (!strcasecmp(argv[0], "gains")) {
- unsigned int i = 0;
- float txgain = 0.0;
- float rxgain = 0.0;
- uint32_t chan_id = 0;
- uint32_t ccount = 0;
- ftdm_channel_t *chan;
- ftdm_span_t *span = NULL;
- if (argc < 4) {
- stream->write_function(stream, "-ERR Usage: ftdm gains []\n");
- goto end;
- }
- ftdm_span_find_by_name(argv[3], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
- if (argc > 4) {
- chan_id = atoi(argv[4]);
- if (chan_id > ftdm_span_get_chan_count(span)) {
- stream->write_function(stream, "-ERR invalid chan\n");
- goto end;
- }
- }
- i = sscanf(argv[1], "%f", &rxgain);
- i += sscanf(argv[2], "%f", &txgain);
- if (i != 2) {
- stream->write_function(stream, "-ERR invalid gains\n");
- goto end;
- }
-
- if (chan_id) {
- chan = ftdm_span_get_channel(span, chan_id);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_GAIN, &rxgain);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_GAIN, &txgain);
- } else {
- ccount = ftdm_span_get_chan_count(span);
- for (i = 1; i < ccount; i++) {
- chan = ftdm_span_get_channel(span, i);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_GAIN, &rxgain);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_GAIN, &txgain);
- }
- }
- stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
- } else if (!strcasecmp(argv[0], "queuesize")) {
- unsigned int i = 0;
- uint32_t rxsize = 10;
- uint32_t txsize = 10;
- uint32_t chan_id = 0;
- uint32_t ccount = 0;
- ftdm_channel_t *chan;
- ftdm_span_t *span = NULL;
- if (argc < 4) {
- stream->write_function(stream, "-ERR Usage: ftdm queuesize []\n");
- goto end;
- }
- ftdm_span_find_by_name(argv[3], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
- if (argc > 4) {
- chan_id = atoi(argv[4]);
- if (chan_id > ftdm_span_get_chan_count(span)) {
- stream->write_function(stream, "-ERR invalid chan\n");
- goto end;
- }
- }
- i = sscanf(argv[1], "%u", &rxsize);
- i += sscanf(argv[2], "%u", &txsize);
- if (i != 2) {
- stream->write_function(stream, "-ERR invalid queue sizes provided\n");
- goto end;
- }
-
- if (chan_id) {
- chan = ftdm_span_get_channel(span, chan_id);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_QUEUE_SIZE, &rxsize);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txsize);
- } else {
- ccount = ftdm_span_get_chan_count(span);
- for (i = 1; i < ccount; i++) {
- chan = ftdm_span_get_channel(span, i);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_RX_QUEUE_SIZE, &rxsize);
- ftdm_channel_command(chan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txsize);
- }
- }
- stream->write_function(stream, "+OK queue sizes set to Rx %d and Tx %d\n", rxsize, txsize);
- } else if (!strcasecmp(argv[0], "restart")) {
- uint32_t chan_id = 0;
- uint32_t ccount = 0;
- ftdm_channel_t *chan;
- ftdm_span_t *span = NULL;
- if (argc < 2) {
- stream->write_function(stream, "-ERR Usage: ftdm restart []\n");
- goto end;
- }
- ftdm_span_find_by_name(argv[1], &span);
- if (!span) {
- stream->write_function(stream, "-ERR invalid span\n");
- goto end;
- }
-
- if (argc > 2) {
- chan_id = atoi(argv[2]);
- if (chan_id > ftdm_span_get_chan_count(span)) {
- stream->write_function(stream, "-ERR invalid chan\n");
- goto end;
- }
- }
- if (chan_id) {
- chan = ftdm_span_get_channel(span, chan_id);
- if (!chan) {
- stream->write_function(stream, "-ERR Could not find chan\n");
- goto end;
- }
- stream->write_function(stream, "Resetting channel %s:%s\n", argv[1], argv[2]);
- ftdm_channel_reset(chan);
- } else {
- uint32_t i = 0;
- ccount = ftdm_span_get_chan_count(span);
- for (i = 1; i < ccount; i++) {
- chan = ftdm_span_get_channel(span, i);
- stream->write_function(stream, "Resetting channel %s:%d\n", argv[1], i);
- ftdm_channel_reset(chan);
- }
- }
-
- } else {
-
+ }
+
+ /* if the command was not found in the main CLI entries, try to execute it as a FreeTDM API */
+ if (i == ftdm_array_len(ftdm_cli_options)) {
char *rply = ftdm_api_execute(cmd);
-
if (rply) {
stream->write_function(stream, "%s", rply);
ftdm_free(rply);
} else {
- stream->write_function(stream, "-ERR Usage: %s\n", FT_SYNTAX);
+ print_full_usage(stream);
}
}
- /*Q931ToPcap enhancement done*/
- end:
+end:
switch_safe_free(mycmd);
@@ -4441,9 +4566,10 @@ SWITCH_STANDARD_APP(disable_ec_function)
SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
{
-
- switch_api_interface_t *commands_api_interface;
- switch_application_interface_t *app_interface;
+ int i = 0;
+ ftdm_cli_entry_t *entry = NULL;
+ switch_api_interface_t *commands_api_interface = NULL;
+ switch_application_interface_t *app_interface = NULL;
module_pool = pool;
@@ -4474,23 +4600,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
freetdm_endpoint_interface->io_routines = &freetdm_io_routines;
freetdm_endpoint_interface->state_handler = &freetdm_state_handlers;
- SWITCH_ADD_API(commands_api_interface, "ftdm", "FreeTDM commands", ft_function, FT_SYNTAX);
- switch_console_set_complete("add ftdm start");
- switch_console_set_complete("add ftdm stop");
- switch_console_set_complete("add ftdm restart");
- switch_console_set_complete("add ftdm dump");
- switch_console_set_complete("add ftdm sigstatus get");
- switch_console_set_complete("add ftdm sigstatus set");
- switch_console_set_complete("add ftdm trace");
- switch_console_set_complete("add ftdm notrace");
- switch_console_set_complete("add ftdm q931_pcap");
- switch_console_set_complete("add ftdm gains");
- switch_console_set_complete("add ftdm queuesize");
- switch_console_set_complete("add ftdm dtmf on");
- switch_console_set_complete("add ftdm dtmf off");
- switch_console_set_complete("add ftdm core state");
- switch_console_set_complete("add ftdm core flag");
- switch_console_set_complete("add ftdm core calls");
+ SWITCH_ADD_API(commands_api_interface, "ftdm", "FreeTDM commands", ft_function, " ");
+ for (i = 0 ; i < ftdm_array_len(ftdm_cli_options); i++) {
+ char complete_cli[512];
+ entry = &ftdm_cli_options[i];
+ snprintf(complete_cli, sizeof(complete_cli), "add ftdm %s %s", entry->name, entry->complete);
+ switch_console_set_complete(complete_cli);
+ }
SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "disable_dtmf", "Disable DTMF Detection", "Disable DTMF Detection", disable_dtmf_function, "", SAF_NONE);
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 1e7c682e02..0205ab36b1 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -2825,9 +2825,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n");
ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No IO attached to channel\n");
- ftdm_mutex_lock(ftdmchan->mutex);
+ ftdm_channel_lock(ftdmchan);
- switch(command) {
+ switch (command) {
case FTDM_COMMAND_ENABLE_CALLERID_DETECT:
{
@@ -3278,12 +3278,31 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
+ case FTDM_COMMAND_GET_IOSTATS:
+ {
+ if (!obj) {
+ GOTO_STATUS(done, FTDM_EINVAL);
+ }
+ memcpy(obj, &ftdmchan->iostats, sizeof(ftdmchan->iostats));
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+ case FTDM_COMMAND_SWITCH_IOSTATS:
+ {
+ ftdm_bool_t enable = *(ftdm_bool_t *)obj;
+ if (enable) {
+ ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
+ } else {
+ ftdm_channel_clear_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
+ }
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
default:
break;
}
if (!ftdmchan->fio->command) {
- snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
ftdm_log(FTDM_LOG_ERROR, "no command function defined by the I/O freetdm module!\n");
GOTO_STATUS(done, FTDM_FAIL);
}
@@ -3291,11 +3310,12 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
status = ftdmchan->fio->command(ftdmchan, command, obj);
if (status == FTDM_NOTIMPL) {
- snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "I/O command %d not implemented in backend", command);
ftdm_log(FTDM_LOG_ERROR, "I/O backend does not support command %d!\n", command);
}
+
done:
- ftdm_mutex_unlock(ftdmchan->mutex);
+ ftdm_channel_unlock(ftdmchan);
+
return status;
}
@@ -4564,14 +4584,20 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
return FTDM_FAIL;
}
- if (chan_config->debugdtmf) {
- for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
- if (!FTDM_IS_VOICE_CHANNEL(span->channels[chan_index])) {
- continue;
- }
- span->channels[chan_index]->dtmfdbg.requested = 1;
+ for (chan_index = currindex + 1; chan_index <= span->chan_count; chan_index++) {
+ if (chan_config->iostats) {
+ ftdm_channel_set_feature(span->channels[chan_index], FTDM_CHANNEL_FEATURE_IO_STATS);
+ }
+
+ if (!FTDM_IS_VOICE_CHANNEL(span->channels[chan_index])) {
+ continue;
+ }
+
+ if (chan_config->debugdtmf) {
+ span->channels[chan_index]->dtmfdbg.requested = 1;
}
}
+
return FTDM_SUCCESS;
}
@@ -4638,6 +4664,8 @@ static ftdm_status_t load_config(void)
/* it is confusing that parameters from one span affect others, so let's clear them */
memset(&chan_config, 0, sizeof(chan_config));
sprintf(chan_config.group_name, "__default");
+ /* default to storing iostats */
+ chan_config.iostats = FTDM_TRUE;
} else {
ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
span = NULL;
@@ -4764,6 +4792,13 @@ static ftdm_status_t load_config(void)
} else if (!strcasecmp(var, "debugdtmf")) {
chan_config.debugdtmf = ftdm_true(val);
ftdm_log(FTDM_LOG_DEBUG, "Setting debugdtmf to '%s'\n", chan_config.debugdtmf ? "yes" : "no");
+ } else if (!strncasecmp(var, "iostats", sizeof("iostats")-1)) {
+ if (ftdm_true(val)) {
+ chan_config.iostats = FTDM_TRUE;
+ } else {
+ chan_config.iostats = FTDM_FALSE;
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "Setting iostats to '%s'\n", chan_config.iostats ? "yes" : "no");
} else if (!strcasecmp(var, "group")) {
len = strlen(val);
if (len >= FTDM_MAX_NAME_STR_SZ) {
diff --git a/libs/freetdm/src/ftdm_threadmutex.c b/libs/freetdm/src/ftdm_threadmutex.c
index f2524727ca..56653811fa 100644
--- a/libs/freetdm/src/ftdm_threadmutex.c
+++ b/libs/freetdm/src/ftdm_threadmutex.c
@@ -111,7 +111,7 @@ FT_DECLARE(void) ftdm_thread_override_default_stacksize(ftdm_size_t size)
static void * FTDM_THREAD_CALLING_CONVENTION thread_launch(void *args)
{
void *exit_val;
- ftdm_thread_t *thread = (ftdm_thread_t *)args;
+ ftdm_thread_t *thread = (ftdm_thread_t *)args;
exit_val = thread->function(thread, thread->private_data);
#ifndef WIN32
pthread_attr_destroy(&thread->attribute);
@@ -247,6 +247,10 @@ FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex)
FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(const char *file, int line, const char *func, ftdm_mutex_t *mutex)
{
#ifdef WIN32
+ UNREFERENCED_PARAMETER(file);
+ UNREFERENCED_PARAMETER(line);
+ UNREFERENCED_PARAMETER(func);
+
EnterCriticalSection(&mutex->mutex);
#else
int err;
@@ -264,6 +268,10 @@ FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(const char *file, int line, const cha
FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(const char *file, int line, const char *func, ftdm_mutex_t *mutex)
{
#ifdef WIN32
+ UNREFERENCED_PARAMETER(file);
+ UNREFERENCED_PARAMETER(line);
+ UNREFERENCED_PARAMETER(func);
+
if (!TryEnterCriticalSection(&mutex->mutex))
return FTDM_FAIL;
#else
@@ -297,6 +305,10 @@ FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(const char *file, int line, const c
mutex->reentrancy--;
#endif
#ifdef WIN32
+ UNREFERENCED_PARAMETER(file);
+ UNREFERENCED_PARAMETER(line);
+ UNREFERENCED_PARAMETER(func);
+
LeaveCriticalSection(&mutex->mutex);
#else
if (pthread_mutex_unlock(&mutex->mutex)) {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
index 6acbe3047a..8d36511b91 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
@@ -63,6 +63,10 @@
#define SNGISDN_NUM_LOCAL_NUMBERS 8
#define SNGISDN_DCHAN_QUEUE_LEN 200
+#ifndef MI_NOTIFY
+#define MI_NOTIFY 0x14
+#endif
+
/* TODO: rename all *_cc_* to *_an_* */
typedef enum {
@@ -380,6 +384,7 @@ void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan);
void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
+void sngisdn_snd_notify_req(ftdm_channel_t *ftdmchan);
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare);
@@ -480,7 +485,7 @@ ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr
ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len);
ftdm_status_t set_user_to_user_ie(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr);
ftdm_status_t set_cause_ie(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
-
+ftdm_status_t set_not_ind_ie(ftdm_channel_t *ftdmchan, NotInd *notInd);
ftdm_status_t sngisdn_add_var(sngisdn_chan_data_t *sngisdn_info, const char* var, const char* val);
ftdm_status_t sngisdn_add_raw_data(sngisdn_chan_data_t *sngisdn_info, uint8_t* data, ftdm_size_t data_len);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
index 308e0abac4..e95a582a45 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
@@ -361,8 +361,9 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
(evntType == MI_CALLPROC)?"PROCEED":
(evntType == MI_PROGRESS)?"PROGRESS":
(evntType == MI_SETUPACK)?"SETUP ACK":
- (evntType == MI_INFO)?"INFO":"UNKNOWN",
- suId, suInstId, spInstId, ces);
+ (evntType == MI_NOTIFY)?"NOTIFY":
+ (evntType == MI_INFO)?"INFO":"UNKNOWN",
+ suId, suInstId, spInstId, ces);
switch(evntType) {
case MI_CALLPROC:
@@ -493,7 +494,10 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
break;
}
}
-
+ break;
+ case MI_NOTIFY:
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing NOTIFY (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId);
+ /* Do nothing */
break;
default:
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Unhandled STATUS event\n");
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
index 94c4f03e7e..c2305e445f 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
@@ -317,11 +317,7 @@ void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan)
}
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
- //ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ\n");
-
-
-
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, sngisdn_info->ces);
if (sng_isdn_con_status(signal_data->cc_id, 0, 0, &cnStEvnt, MI_INFO, signal_data->dchan_id, sngisdn_info->ces)) {
@@ -330,6 +326,32 @@ void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan)
return;
}
+void sngisdn_snd_notify_req(ftdm_channel_t *ftdmchan)
+{
+ CnStEvnt cnStEvnt;
+
+ sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending NOTIFY, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+ sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ return;
+ }
+
+ memset(&cnStEvnt, 0, sizeof(cnStEvnt));
+
+ set_not_ind_ie(ftdmchan, &cnStEvnt.notInd);
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending NOTIFY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
+
+ if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_NOTIFY, signal_data->dchan_id, sngisdn_info->ces)) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused NOTIFY request\n");
+ }
+ return;
+}
+
void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan)
{
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
index df791ef3cb..3788a9c25b 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
@@ -168,7 +168,8 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C
(evntType == MI_CALLPROC)?"PROCEED":
(evntType == MI_PROGRESS)?"PROGRESS":
(evntType == MI_SETUPACK)?"SETUP ACK":
- (evntType == MI_INFO)?"INFO":"UNKNOWN",
+ (evntType == MI_NOTIFY)?"NOTIFY":
+ (evntType == MI_INFO)?"INFO":"UNKNOWN",
suId, suInstId, spInstId, ces);
sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event));
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
index 39c756a2c2..9a633b902a 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
@@ -1021,6 +1021,14 @@ ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd)
return FTDM_SUCCESS;
}
+ftdm_status_t set_not_ind_ie(ftdm_channel_t *ftdmchan, NotInd *notInd)
+{
+ notInd->eh.pres = PRSNT_NODEF;
+ notInd->notDesc.pres = PRSNT_NODEF;
+ notInd->notDesc.val = 0x71; /* Call information event */
+ return FTDM_SUCCESS;
+}
+
void sngisdn_t3_timeout(void *p_sngisdn_info)
{
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
index abb6577924..467ac7f9d8 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
@@ -737,8 +737,16 @@ uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset
calling_subaddr_string, (j-1), get_code_2_str(type, dcodQ931TypeOfSubaddressTable), type);
}
break;
- case PROT_Q931_IE_REDIRECTION_NUMBER:
case PROT_Q931_IE_NOTIFICATION_IND:
+ {
+ uint8_t desc;
+
+ desc = get_bits(OCTET(3),1,7);
+ *str_len += sprintf(&str[*str_len], "%s (%d)\n",
+ get_code_2_str(desc, dcodQ931NotificationIndTable), desc);
+ }
+ break;
+ case PROT_Q931_IE_REDIRECTION_NUMBER:
case PROT_Q931_IE_DATE_TIME:
case PROT_Q931_IE_INFORMATION_REQUEST:
case PROT_Q931_IE_SIGNAL:
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
index 37b799d007..b09bcbd33a 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
@@ -591,4 +591,9 @@ struct code2str dcodQ931AssocInfoTable[] = {
{ -1, "Invalid"},
};
+
+struct code2str dcodQ931NotificationIndTable[] = {
+ { 0x71, "Call Information/event"},
+ { -1, "Invalid"},
+};
#endif /* __FTMOD_SANGOMA_ISDN_TRACE_H__ */
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 a9029d45e4..613ad6d95e 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
@@ -144,14 +144,16 @@ ftdm_status_t copy_cgPtyNum_from_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cg
ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPtyNum)
{
- const char *val;
+ const char *val = NULL;
+ const char *clg_nadi = NULL;
+ sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
cgPtyNum->eh.pres = PRSNT_NODEF;
cgPtyNum->natAddrInd.pres = PRSNT_NODEF;
- cgPtyNum->natAddrInd.val = 0x03;
+ cgPtyNum->natAddrInd.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].clg_nadi;
cgPtyNum->scrnInd.pres = PRSNT_NODEF;
@@ -178,6 +180,14 @@ ftdm_status_t copy_cgPtyNum_to_sngss7(ftdm_channel_t *ftdmchan, SiCgPtyNum *cgPt
cgPtyNum->niInd.pres = PRSNT_NODEF;
cgPtyNum->niInd.val = 0x00;
+ /* check if the user would like a custom NADI value for the calling Pty Num */
+ clg_nadi = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_clg_nadi");
+ if (!ftdm_strlen_zero(clg_nadi)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Found user supplied Calling NADI value \"%s\"\n", clg_nadi);
+ cgPtyNum->natAddrInd.val = atoi(clg_nadi);
+ }
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Calling Party Number Presentation Ind %d\n", cgPtyNum->presRest.val);
+
return copy_tknStr_to_sngss7(caller_data->cid_num.digits, &cgPtyNum->addrSig, &cgPtyNum->oddEven);
}
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index ca16219e49..0948f16e29 100755
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -487,6 +487,7 @@ typedef struct ftdm_channel_config {
float rxgain;
float txgain;
uint8_t debugdtmf;
+ uint8_t iostats;
} ftdm_channel_config_t;
/*!
@@ -707,7 +708,10 @@ typedef enum {
FTDM_COMMAND_FLUSH_TX_BUFFERS = 45,
FTDM_COMMAND_FLUSH_RX_BUFFERS = 46,
FTDM_COMMAND_FLUSH_BUFFERS = 47,
+
+ /*!< Flush IO statistics */
FTDM_COMMAND_FLUSH_IOSTATS = 48,
+
FTDM_COMMAND_SET_PRE_BUFFER_SIZE = 49,
FTDM_COMMAND_SET_LINK_STATUS = 50,
FTDM_COMMAND_GET_LINK_STATUS = 51,
@@ -719,6 +723,11 @@ typedef enum {
FTDM_COMMAND_START_MF_PLAYBACK = 57,
FTDM_COMMAND_STOP_MF_PLAYBACK = 58,
+ /*!< Get a copy of the current IO stats */
+ FTDM_COMMAND_GET_IOSTATS = 59,
+ /*!< Enable/disable IO stats in the channel */
+ FTDM_COMMAND_SWITCH_IOSTATS = 60,
+
FTDM_COMMAND_COUNT,
} ftdm_command_t;
@@ -903,6 +912,37 @@ typedef enum {
FTDM_MF_DIRECTION_BACKWARD = (1 << 9)
} ftdm_mf_direction_flag_t;
+/*! \brief IO Error statistics */
+typedef enum {
+ FTDM_IOSTATS_ERROR_CRC = (1 << 0),
+ FTDM_IOSTATS_ERROR_FRAME = (1 << 1),
+ FTDM_IOSTATS_ERROR_ABORT = (1 << 2),
+ FTDM_IOSTATS_ERROR_FIFO = (1 << 3),
+ FTDM_IOSTATS_ERROR_DMA = (1 << 4),
+ FTDM_IOSTATS_ERROR_QUEUE_THRES = (1 << 5), /* Queue reached high threshold */
+ FTDM_IOSTATS_ERROR_QUEUE_FULL = (1 << 6), /* Queue is full */
+} ftdm_iostats_error_type_t;
+
+/*! \brief IO statistics */
+typedef struct {
+ struct {
+ uint32_t errors;
+ uint16_t flags;
+ uint8_t queue_size; /*!< max queue size configured */
+ uint8_t queue_len; /*!< Current number of elements in queue */
+ uint64_t packets;
+ } rx;
+
+ struct {
+ uint32_t errors;
+ uint16_t flags;
+ uint8_t idle_packets;
+ uint8_t queue_size; /*!< max queue size configured */
+ uint8_t queue_len; /*!< Current number of elements in queue */
+ uint64_t packets;
+ } tx;
+} ftdm_channel_iostats_t;
+
/*! \brief Override the default queue handler */
FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler);
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index e4be27ce40..9c5c9ad468 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -359,35 +359,6 @@ typedef struct {
ftdm_mutex_t *mutex;
} ftdm_dtmf_debug_t;
-typedef enum {
- FTDM_IOSTATS_ERROR_CRC = (1 << 0),
- FTDM_IOSTATS_ERROR_FRAME = (1 << 1),
- FTDM_IOSTATS_ERROR_ABORT = (1 << 2),
- FTDM_IOSTATS_ERROR_FIFO = (1 << 3),
- FTDM_IOSTATS_ERROR_DMA = (1 << 4),
- FTDM_IOSTATS_ERROR_QUEUE_THRES = (1 << 5), /* Queue reached high threshold */
- FTDM_IOSTATS_ERROR_QUEUE_FULL = (1 << 6), /* Queue is full */
-} ftdm_iostats_error_type_t;
-
-typedef struct {
- struct {
- uint32_t errors;
- uint16_t flags;
- uint8_t queue_size; /* max queue size configured */
- uint8_t queue_len; /* Current number of elements in queue */
- uint64_t packets;
- } rx;
-
- struct {
- uint32_t errors;
- uint16_t flags;
- uint8_t idle_packets;
- uint8_t queue_size; /* max queue size configured */
- uint8_t queue_len; /* Current number of elements in queue */
- uint64_t packets;
- } tx;
-} ftdm_channel_iostats_t;
-
/* 2^8 table size, one for each byte (sample) value */
#define FTDM_GAINS_TABLE_SIZE 256
struct ftdm_channel {
diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update
index 83502caf5f..c2a60933c6 100644
--- a/libs/sofia-sip/.update
+++ b/libs/sofia-sip/.update
@@ -1 +1 @@
-Wed Jul 6 15:11:41 CDT 2011
+Tue Aug 2 13:51:40 CDT 2011
diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h b/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
index b73561c915..60bc009423 100644
--- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
+++ b/libs/sofia-sip/libsofia-sip-ua/msg/msg_internal.h
@@ -114,6 +114,29 @@ struct msg_buffer_s {
msg_payload_t *b_chunks; /**< List of body chunks */
};
+
+struct hep_hdr{
+ uint8_t hp_v; /* version */
+ uint8_t hp_l; /* length */
+ uint8_t hp_f; /* family */
+ uint8_t hp_p; /* protocol */
+ uint16_t hp_sport; /* source port */
+ uint16_t hp_dport; /* destination port */
+};
+
+
+struct hep_iphdr{
+ struct in_addr hp_src;
+ struct in_addr hp_dst; /* source and dest address */
+};
+
+#if SU_HAVE_IN6
+struct hep_ip6hdr {
+ struct in6_addr hp6_src; /* source address */
+ struct in6_addr hp6_dst; /* destination address */
+};
+#endif
+
/** Maximum size when streaming. */
#define MSG_SSIZE_MAX (USIZE_MAX)
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h b/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
index 891d26b168..1390cc2f74 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h
@@ -301,6 +301,12 @@ TPORT_DLL extern tag_typedef_t tptag_dump;
TPORT_DLL extern tag_typedef_t tptag_dump_ref;
#define TPTAG_DUMP_REF(x) tptag_dump_ref, tag_str_vr(&(x))
+TPORT_DLL extern tag_typedef_t tptag_capt;
+#define TPTAG_CAPT(x) tptag_capt, tag_str_v((x))
+
+TPORT_DLL extern tag_typedef_t tptag_capt_ref;
+#define TPTAG_CAPT_REF(x) tptag_capt_ref, tag_str_vr(&(x))
+
SOFIA_END_DECLS
#endif /* !defined TPORT_TAG_H */
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
index 8ebab4fd31..cc94cf4681 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport.c
@@ -3554,6 +3554,10 @@ ssize_t tport_vsend(tport_t *self,
if (n > 0 && self->tp_master->mr_dump_file)
tport_dump_iovec(self, msg, n, iov, iovused, "sent", "to");
+
+ if (n > 0 && self->tp_master->mr_capt_sock)
+ tport_capt_msg(self, msg, n, iov, iovused, "sent");
+
if (tport_log->log_level >= 7) {
size_t i, m = 0;
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
index 683b79a360..d4693ad167 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
@@ -300,6 +300,9 @@ struct tport_master {
/** FILE to dump received and sent data */
FILE *mr_dump_file;
char *mr_dump; /**< Filename for dumping received/sent data */
+ /** SOCK to dump received and sent data */
+ su_socket_t mr_capt_sock;
+ char *mr_capt_name; /**< Servername for capturing received/sent data */
tport_primary_t *mr_primaries; /**< List of primary contacts */
tport_params_t mr_params[1];
@@ -478,6 +481,9 @@ void tport_dump_iovec(tport_t const *self, msg_t *msg,
size_t n, su_iovec_t const iov[], size_t iovused,
char const *what, char const *how);
+void tport_capt_msg(tport_t const *self, msg_t *msg, size_t n,
+ su_iovec_t const iov[], size_t iovused, char const *what);
+
int tport_tcp_ping(tport_t *self, su_time_t now);
int tport_tcp_pong(tport_t *self);
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
index af2a46d163..fe23ce433a 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c
@@ -33,9 +33,11 @@
*/
#include "config.h"
+#include "msg_internal.h"
#include "tport_internal.h"
+#include
#include
#include
#include
@@ -70,6 +72,21 @@ extern char const TPORT_LOG[]; /* dummy declaration for Doxygen */
extern char const TPORT_DUMP[]; /* dummy declaration for Doxygen */
#endif
+/**@var TPORT_CAPT
+ *
+ * Environment variable for transport data capturing.
+ *
+ * The received and sent data is dumped to the capture server specified by TPORT_CAPT
+ * environment variable. This can be used to save message traces into database and help
+ * hairy debugging tasks.
+ *
+ * @sa TPORT_LOG, TPORT_DEBUG, TPORT_CAPT, tport_log
+ */
+#ifdef DOXYGEN
+extern char const TPORT_CAPT[]; /* dummy declaration for Doxygen */
+#endif
+
+
/**@var TPORT_DEBUG
*
* Environment variable determining the debug log level for @b tport module.
@@ -93,31 +110,140 @@ su_log_t tport_log[] = {
};
+
/** Initialize logging. */
int tport_open_log(tport_master_t *mr, tagi_t *tags)
{
+ int n;
int log_msg = mr->mr_log != 0;
char const *dump = NULL;
- int n;
-
+ char const *capt = NULL;;
+
+ if(mr->mr_capt_name) capt = mr->mr_capt_name;
+
n = tl_gets(tags,
TPTAG_LOG_REF(log_msg),
TPTAG_DUMP_REF(dump),
+ TPTAG_CAPT_REF(capt),
TAG_END());
if (getenv("MSG_STREAM_LOG") != NULL || getenv("TPORT_LOG") != NULL)
log_msg = 1;
mr->mr_log = log_msg ? MSG_DO_EXTRACT_COPY : 0;
+ if (getenv("TPORT_CAPT"))
+ capt = getenv("TPORT_CAPT");
if (getenv("MSG_DUMP"))
dump = getenv("MSG_DUMP");
if (getenv("TPORT_DUMP"))
dump = getenv("TPORT_DUMP");
+
+ if(capt) {
+
+ char *captname, *p, *host_s;
+ char port[10];
+ su_addrinfo_t *ai = NULL, hints[1] = {{ 0 }};
+ unsigned len =0;
+
+ if (mr->mr_capt_name && mr->mr_capt_sock && strcmp(capt, mr->mr_capt_name) == 0)
+ return n;
+
+ captname = su_strdup(mr->mr_home, capt);
+ if (captname == NULL)
+ return n;
+
+ if(strncmp(captname, "udp:",4) != 0) {
+ su_log("tport_open_log: capturing. Only udp protocol supported [%s]\n", captname);
+ return n;
+ }
+
+ /* separate proto and host */
+ p = captname+4;
+ if( (*(p)) == '\0') {
+ su_log("malformed ip address\n");
+ return n;
+ }
+ host_s = p;
+
+ if( (p = strrchr(p+1, ':')) == 0 ) {
+ su_log("no host or port specified\n");
+ return n;
+ }
+
+ /*the address contains a port number*/
+ *p = '\0';
+ p++;
+
+ if (atoi(p) <1024 || atoi(p)>65536)
+ {
+ su_log("invalid port number; must be in [1024,65536]\n");
+ return n;
+ }
+
+ memcpy(port, p, sizeof(p));
+
+ *p = '\0';
+
+ /* check if we have [] */
+ if (host_s[0] == '[') {
+ len = strlen(host_s + 1) - 1;
+ if(host_s[len+1] != ']') {
+ su_log("bracket not closed\n");
+ return n;
+ }
+ memmove(host_s, host_s + 1, len);
+ host_s[len] = '\0';
+ }
+
+ /* and again */
+ captname = su_strdup(mr->mr_home, capt);
+ if (captname == NULL) return n;
+
+ su_free(mr->mr_home, mr->mr_capt_name);
+ mr->mr_capt_name = captname;
+
+ if (mr->mr_capt_sock)
+ su_close(mr->mr_capt_sock), mr->mr_capt_sock = 0;
+
+ /* HINTS && getaddrinfo */
+ hints->ai_flags = AI_NUMERICSERV;
+ hints->ai_family = AF_UNSPEC;
+ hints->ai_socktype = SOCK_DGRAM;
+ hints->ai_protocol = IPPROTO_UDP;
+
+
+ if (su_getaddrinfo(host_s, port, hints, &ai)) {
+ su_perror("capture: su_getaddrinfo()");
+ return n;
+ }
+
+ mr->mr_capt_sock = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (mr->mr_capt_sock == INVALID_SOCKET) {
+ su_perror("capture: invalid socket");
+ return n;
+ }
+
+ su_setblocking(mr->mr_capt_sock, 0); /* Don't block */
+
+ if (connect(mr->mr_capt_sock, ai->ai_addr, (socklen_t)(ai->ai_addrlen)) == -1) {
+ if (errno != EINPROGRESS) {
+ su_perror("capture: socket connect");
+ return n;
+ }
+ }
+
+ su_freeaddrinfo(ai);
+ }
+ else if(mr->mr_capt_sock) {
+ /* close capture server*/
+ su_close(mr->mr_capt_sock);
+ mr->mr_capt_sock = 0;
+ }
if (dump) {
time_t now;
char *dumpname;
-
+
if (mr->mr_dump && strcmp(dump, mr->mr_dump) == 0)
return n;
dumpname = su_strdup(mr->mr_home, dump);
@@ -213,6 +339,121 @@ void tport_dump_iovec(tport_t const *self, msg_t *msg,
fflush(mr->mr_dump_file);
}
+/** Capture the data from the iovec */
+void tport_capt_msg(tport_t const *self, msg_t *msg, size_t n,
+ su_iovec_t const iov[], size_t iovused, char const *what)
+{
+
+ int buflen = 0, error;
+ su_sockaddr_t const *su, *su_self;
+ struct hep_hdr hep_header;
+ struct hep_iphdr hep_ipheader = {{0}};
+#if SU_HAVE_IN6
+ struct hep_ip6hdr hep_ip6header = {{{{0}}}};
+#endif
+ int eth_frame_len = 8000;
+ char* buffer;
+ size_t i, dst = 0;
+ tport_master_t *mr;
+
+ assert(self); assert(msg);
+
+ su = msg_addr(msg);
+ su_self = self->tp_addr;
+
+ mr = self->tp_master;
+
+ /* If we don't have socket, go out */
+ if (!mr->mr_capt_sock) {
+ su_log("error: capture socket is not open\n");
+ return;
+ }
+
+ /*buffer for ethernet frame*/
+ buffer = (void*)malloc(eth_frame_len);
+
+ /* VOIP Header */
+ hep_header.hp_v = 1;
+ hep_header.hp_f = su->su_family;
+ /* Header Length */
+ hep_header.hp_l = sizeof(struct hep_hdr);
+
+ /* PROTOCOL */
+ if(strcmp(self->tp_name->tpn_proto, "tcp") == 0) hep_header.hp_p = IPPROTO_TCP;
+ else if(strcmp(self->tp_name->tpn_proto, "tls") == 0) hep_header.hp_p = IPPROTO_IDP; /* FAKE*/
+ else if(strcmp(self->tp_name->tpn_proto, "sctp") == 0) hep_header.hp_p = IPPROTO_SCTP;
+ else hep_header.hp_p = IPPROTO_UDP; /* DEFAULT UDP */
+
+ /* Check destination */
+ if(strncmp("recv", what, 4) == 0) dst = 1;
+
+ /* copy destination and source IPs*/
+ if(su->su_family == AF_INET) {
+
+ memcpy(dst ? &hep_ipheader.hp_dst : &hep_ipheader.hp_src, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
+ memcpy(dst ? &hep_ipheader.hp_src : &hep_ipheader.hp_dst, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
+ hep_header.hp_l += sizeof(struct hep_iphdr);
+ }
+#if SU_HAVE_IN6
+ else {
+ memcpy(dst ? &hep_ip6header.hp6_dst : &hep_ip6header.hp6_src, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr));
+ memcpy(dst ? &hep_ip6header.hp6_src : &hep_ip6header.hp6_dst, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr));
+ hep_header.hp_l += sizeof(struct hep_ip6hdr);
+ }
+#endif
+
+ hep_header.hp_dport = dst ? su->su_port : htons(atoi(self->tp_port));
+ hep_header.hp_sport = dst ? htons(atoi(self->tp_port)) : su->su_port;
+
+
+ /* Copy hepheader */
+ memset(buffer, '\0', eth_frame_len);
+ memcpy(buffer, &hep_header, sizeof(struct hep_hdr));
+ buflen = sizeof(struct hep_hdr);
+
+ if(su->su_family == AF_INET) {
+ memcpy(buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
+ buflen += sizeof(struct hep_iphdr);
+ }
+#if SU_HAVE_IN6
+ else if(su->su_family == AF_INET6) {
+ memcpy(buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
+ buflen += sizeof(struct hep_ip6hdr);
+ }
+#endif
+ else {
+ su_perror("error: tport_logging: capture: unsupported protocol family");
+ goto done;
+ }
+
+ for (i = 0; i < iovused && n > 0; i++) {
+ size_t len = iov[i].mv_len;
+ if (len > n)
+ len = n;
+ /* if the packet too big for us */
+ if((buflen + len) > eth_frame_len)
+ break;
+
+ memcpy(buffer + buflen , (void*)iov[i].mv_base, len);
+ buflen +=len;
+ n -= len;
+ }
+
+ /* check if we have error i.e. capture server is down */
+ if ((error = su_soerror(mr->mr_capt_sock))) {
+ su_perror("error: tport_logging: capture socket error");
+ goto done;
+ }
+
+ su_send(mr->mr_capt_sock, buffer, buflen, 0);
+
+done:
+ /* Now we release it */
+ if(buffer) free(buffer);
+ return;
+}
+
+
/** Log the message. */
void tport_log_msg(tport_t *self, msg_t *msg,
char const *what, char const *via,
@@ -224,6 +465,7 @@ void tport_log_msg(tport_t *self, msg_t *msg,
size_t linelen = 0, n, logged = 0, truncated = 0;
int skip_lf = 0;
+
#define MSG_SEPARATOR \
"------------------------------------------------------------------------\n"
#define MAX_LINELEN 2047
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
index 255eca1d86..433db157a5 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_sigcomp.c
@@ -453,6 +453,10 @@ static int tport_recv_sigcomp_r(tport_t *self,
if (self->tp_master->mr_dump_file && !self->tp_pri->pri_threadpool)
tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+ /* Send the received data to the capture server */
+ if (self->tp_master->mr_capt_sock && !self->tp_pri->pri_threadpool)
+ tport_dump_iovec(self, msg, 0);
+
msg_recv_commit(msg, dlen, eos); /* Mark buffer as used */
}
else {
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
index 2b8064c625..5b7f5fd53e 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c
@@ -554,6 +554,19 @@ tag_typedef_t tptag_log = INTTAG_TYPEDEF(log);
*/
tag_typedef_t tptag_dump = STRTAG_TYPEDEF(dump);
+/**@def TPTAG_CAPT(x)
+ *
+ * URL for capturing unparsed messages from transport.
+ *
+ * Use with tport_tcreate(), nta_agent_create(), nua_create(),
+ * nth_engine_create(), or initial nth_site_create().
+ *
+ * @sa #TPORT_CAPT environment variable, TPTAG_LOG().
+ *
+ */
+tag_typedef_t tptag_capt = STRTAG_TYPEDEF(capt);
+
+
/** Mark transport as trusted.
*
* @note Not implemented by tport module.
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
index 470178fdf8..fba193c957 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_sctp.c
@@ -260,6 +260,9 @@ int tport_recv_sctp(tport_t *self)
if (self->tp_master->mr_dump_file)
tport_dump_iovec(self, msg, N, iovec, veclen, "recv", "from");
+ if (self->tp_master->mr_capt_sock)
+ tport_capt_msg(self, msg, N, iovec, veclen, "recv");
+
msg_recv_commit(msg, N, 0); /* Mark buffer as used */
return 2;
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
index 23ce467f36..062af6e019 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c
@@ -334,6 +334,10 @@ int tport_recv_stream(tport_t *self)
/* Write the received data to the message dump file */
if (self->tp_master->mr_dump_file)
tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+ if (self->tp_master->mr_capt_sock)
+ tport_capt_msg(self, msg, n, iovec, veclen, "recv");
+
/* Mark buffer as used */
msg_recv_commit(msg, n, n == 0);
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
index 8d0f2de712..5a1715b3e5 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c
@@ -362,6 +362,9 @@ int tport_recv_dgram(tport_t *self)
if (self->tp_master->mr_dump_file)
tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
+
+ if (self->tp_master->mr_capt_sock)
+ tport_capt_msg(self, msg, n, iovec, veclen, "recv");
*sample = *((uint8_t *)iovec[0].mv_base);
diff --git a/libs/sqlite/.update b/libs/sqlite/.update
index b452a0325e..1943544f28 100644
--- a/libs/sqlite/.update
+++ b/libs/sqlite/.update
@@ -1 +1 @@
-Sat Jan 5 20:11:10 EST 2008
+Tue Aug 2 13:04:55 CDT 2011
diff --git a/libs/sqlite/Makefile.in b/libs/sqlite/Makefile.in
index 148a0b78fe..1d01aadf34 100644
--- a/libs/sqlite/Makefile.in
+++ b/libs/sqlite/Makefile.in
@@ -194,7 +194,8 @@ SRC += \
$(TOP)/ext/fts1/fts1_hash.h \
$(TOP)/ext/fts1/fts1_porter.c \
$(TOP)/ext/fts1/fts1_tokenizer.h \
- $(TOP)/ext/fts1/fts1_tokenizer1.c
+ $(TOP)/ext/fts1/fts1_tokenizer1.c \
+ $(TOP)/src/sqliteInt.h
# Source code to the test files.
diff --git a/libs/sqlite/src/sqliteInt.h b/libs/sqlite/src/sqliteInt.h
index 3686a091e7..f2914f6230 100644
--- a/libs/sqlite/src/sqliteInt.h
+++ b/libs/sqlite/src/sqliteInt.h
@@ -297,7 +297,7 @@ static inline char *strndup_lite(const char *s, size_t n)
#define sqliteMalloc(x) zmalloc(x)//sqlite3Malloc(x,1)
#define sqliteMallocRaw(x) malloc(x)//sqlite3MallocRaw(x,1)
#define sqliteRealloc(x,y) realloc(x, y)//sqlite3Realloc(x,y)
-#define sqliteStrDup(x) (x?strdup(x):NULL)//sqlite3StrDup(x)
+#define sqliteStrDup(x) (x?strdup(x):strdup(""))//sqlite3StrDup(x)
#define sqliteStrNDup(x,y) strndup_lite(x,y) //sqlite3StrNDup(x,y)
#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y)
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index 955252a3e8..785861457e 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -2317,17 +2317,25 @@ SWITCH_STANDARD_API(dual_transfer_function)
dest1 = argv[1];
dest2= argv[2];
- if ((dp1 = strchr(dest1, '/'))) {
+ if ((dp1 = strstr(dest1, "/inline")) && *(dp1 + 7) == '\0') {
*dp1++ = '\0';
- if ((context1 = strchr(dp1, '/'))) {
- *context1++ = '\0';
+ } else {
+ if ((dp1 = strchr(dest1, '/'))) {
+ *dp1++ = '\0';
+ if ((context1 = strchr(dp1, '/'))) {
+ *context1++ = '\0';
+ }
}
}
- if ((dp2 = strchr(dest2, '/'))) {
+ if ((dp2 = strstr(dest1, "/inline")) && *(dp2 + 7) == '\0') {
*dp2++ = '\0';
- if ((context2 = strchr(dp2, '/'))) {
- *context2++ = '\0';
+ } else {
+ if ((dp2 = strchr(dest2, '/'))) {
+ *dp2++ = '\0';
+ if ((context2 = strchr(dp2, '/'))) {
+ *context2++ = '\0';
+ }
}
}
@@ -3302,8 +3310,7 @@ SWITCH_STANDARD_API(break_function)
if (both) {
const char *quuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
- if (quuid) {
- qsession = switch_core_session_locate(quuid);
+ if (quuid && (qsession = switch_core_session_locate(quuid))) {
qchannel = switch_core_session_get_channel(qsession);
}
}
@@ -3899,7 +3906,7 @@ SWITCH_STANDARD_API(alias_function)
return SWITCH_STATUS_SUCCESS;
}
-#define SHOW_SYNTAX "codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count|like ]|distinct_channels|aliases|complete|chat|management|modules|nat_map|say|interfaces|interface_types|tasks|limits"
+#define SHOW_SYNTAX "codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count|like ]|calls|detailed_calls|bridged_calls|detailed_bridged_calls|aliases|complete|chat|management|modules|nat_map|say|interfaces|interface_types|tasks|limits"
SWITCH_STANDARD_API(show_function)
{
char sql[1024];
@@ -3988,7 +3995,7 @@ SWITCH_STANDARD_API(show_function)
sprintf(sql, "select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' order by type,name", hostname, command);
}
} else if (!strcasecmp(command, "calls")) {
- sprintf(sql, "select * from calls where hostname='%s' order by call_created_epoch", hostname);
+ sprintf(sql, "select * from basic_calls where hostname='%s' order by call_created_epoch", hostname);
if (argv[1] && !strcasecmp(argv[1], "count")) {
holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) {
@@ -4036,14 +4043,18 @@ SWITCH_STANDARD_API(show_function)
as = argv[3];
}
}
- } else if (!strcasecmp(command, "distinct_channels")) {
- sprintf(sql, "select * from channels left join calls on "
- "channels.uuid=calls.caller_uuid where channels.hostname='%s' and channels.uuid not in (select callee_uuid from calls where hostname='%s') order by created_epoch", hostname, hostname);
+ } else if (!strcasecmp(command, "detailed_calls")) {
+ sprintf(sql, "select * from detailed_calls where hostname='%s' order by created_epoch", hostname);
if (argv[2] && !strcasecmp(argv[1], "as")) {
as = argv[2];
}
- } else if (!strcasecmp(command, "detailed_calls")) {
- sprintf(sql, "select * from detailed_calls where hostname='%s' order by created_epoch", hostname);
+ } else if (!strcasecmp(command, "bridged_calls")) {
+ sprintf(sql, "select * from basic_calls where b_uuid is not null and hostname='%s' order by created_epoch", hostname);
+ if (argv[2] && !strcasecmp(argv[1], "as")) {
+ as = argv[2];
+ }
+ } else if (!strcasecmp(command, "detailed_bridged_calls")) {
+ sprintf(sql, "select * from detailed_calls where b_uuid is not null and hostname='%s' order by created_epoch", hostname);
if (argv[2] && !strcasecmp(argv[1], "as")) {
as = argv[2];
}
@@ -4433,6 +4444,9 @@ SWITCH_STANDARD_API(uuid_fileman_function)
if (switch_ivr_get_file_handle(psession, &fh) == SWITCH_STATUS_SUCCESS) {
switch_ivr_process_fh(psession, cmd, fh);
switch_ivr_release_file_handle(psession, &fh);
+ stream->write_function(stream, "+OK\n");
+ } else {
+ stream->write_function(stream, "-ERR No File Handle!\n");
}
switch_core_session_rwunlock(psession);
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index aa737596bd..aec526ca38 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -5992,7 +5992,7 @@ SWITCH_STANDARD_APP(conference_function)
}
if (pstatus != SWITCH_STATUS_SUCCESS && pstatus != SWITCH_STATUS_BREAK) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot ask the user for a pin, ending call");
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot ask the user for a pin, ending call\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c
index 59d76d110b..77dab2d092 100644
--- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c
+++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c
@@ -735,7 +735,9 @@ static void terminate_session(switch_core_session_t **session, int line, switch_
}
switch_mutex_lock(tech_pvt->flag_mutex);
- switch_set_flag(tech_pvt, TFLAG_TERM);
+ if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+ switch_set_flag(tech_pvt, TFLAG_TERM);
+ }
switch_set_flag(tech_pvt, TFLAG_BYE);
switch_clear_flag(tech_pvt, TFLAG_IO);
switch_mutex_unlock(tech_pvt->flag_mutex);
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 757ddd76a5..d77f298588 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -2016,8 +2016,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "SEND");
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Name", name);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Number", number);
+
+ switch_channel_set_profile_var(channel, "callee_id_name", name);
+ switch_channel_set_profile_var(channel, "callee_id_number", number);
+
if (uuid) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
}
@@ -3434,6 +3436,17 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
goto done;
}
+ if (!strcasecmp(argv[1], "capture")) {
+ if (argc > 2) {
+ int value = switch_true(argv[2]);
+ nua_set_params(profile->nua, TPTAG_CAPT(value ? mod_sofia_globals.capture_server : NULL), TAG_END());
+ stream->write_function(stream, "%s sip capturing on %s", value ? "Enabled" : "Disabled", profile->name);
+ } else {
+ stream->write_function(stream, "Usage: sofia profile capture \n");
+ }
+ goto done;
+ }
+
if (!strcasecmp(argv[1], "watchdog")) {
if (argc > 2) {
int value = switch_true(argv[2]);
@@ -3995,6 +4008,7 @@ SWITCH_STANDARD_API(sofia_function)
static const char usage_string[] = "USAGE:\n"
"--------------------------------------------------------------------------------\n"
"sofia global siptrace \n"
+ "sofia capture \n"
" watchdog \n\n"
"sofia profile [start | stop | restart | rescan]\n"
" flush_inbound_reg [ | <[user]@domain>] [reboot]\n"
@@ -4003,6 +4017,7 @@ SWITCH_STANDARD_API(sofia_function)
" killgw \n"
" [stun-auto-disable | stun-enabled] [true | false]]\n"
" siptrace \n"
+ " capture \n"
" watchdog \n\n"
"sofia profile [reg ] | [pres ] | [user ]\n"
"sofia gateway \n\n"
@@ -4062,6 +4077,7 @@ SWITCH_STANDARD_API(sofia_function)
goto done;
} else if (!strcasecmp(argv[0], "global")) {
int ston = -1;
+ int cton = -1;
int wdon = -1;
if (argc > 1) {
@@ -4098,6 +4114,12 @@ SWITCH_STANDARD_API(sofia_function)
}
}
+ if (!strcasecmp(argv[1], "capture")) {
+ if (argc > 2) {
+ cton = switch_true(argv[2]);
+ }
+ }
+
if (!strcasecmp(argv[1], "watchdog")) {
if (argc > 2) {
wdon = switch_true(argv[2]);
@@ -4108,11 +4130,14 @@ SWITCH_STANDARD_API(sofia_function)
if (ston != -1) {
sofia_glue_global_siptrace(ston);
stream->write_function(stream, "+OK Global siptrace %s", ston ? "on" : "off");
+ } else if (cton != -1) {
+ sofia_glue_global_capture(cton);
+ stream->write_function(stream, "+OK Global capture %s", cton ? "on" : "off");
} else if (wdon != -1) {
sofia_glue_global_watchdog(wdon);
stream->write_function(stream, "+OK Global watchdog %s", wdon ? "on" : "off");
} else {
- stream->write_function(stream, "-ERR Usage: siptrace |watchdog |debug write_function(stream, "-ERR Usage: siptrace |capture |watchdog |debug sip_to) {
+ number = (char *) switch_channel_get_variable(channel, "callee_id_number");
+ name = (char *) switch_channel_get_variable(channel, "callee_id_name");
+
+
+ if (zstr(number) && sip->sip_to) {
number = sip->sip_to->a_url->url_user;
}
@@ -738,18 +742,6 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
goto end;
}
- if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
- const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "RECV");
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Name", name);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Callee-Number", number);
- if (uuid) {
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
- }
- switch_channel_event_set_data(channel, event);
- switch_event_fire(&event);
- }
-
caller_profile = switch_channel_get_caller_profile(channel);
if (!strcmp(caller_profile->callee_id_name, name) && !strcmp(caller_profile->callee_id_number, number)) {
@@ -766,6 +758,17 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
}
if (send) {
+
+ if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
+ const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "RECV");
+ if (uuid) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
+ }
+ switch_channel_event_set_data(channel, event);
+ switch_event_fire(&event);
+ }
+
sofia_send_callee_id(session, NULL, NULL);
}
@@ -1789,6 +1792,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
NTATAG_SERVER_RPORT(profile->server_rport_level),
NTATAG_CLIENT_RPORT(profile->client_rport_level),
TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)),
+ TPTAG_CAPT(sofia_test_flag(profile, TFLAG_CAPTURE) ? mod_sofia_globals.capture_server : NULL),
TAG_IF(sofia_test_pflag(profile, PFLAG_SIPCOMPACT),
NTATAG_SIPFLAGS(MSG_DO_COMPACT)),
TAG_IF(profile->timer_t1, NTATAG_SIP_T1(profile->timer_t1)),
@@ -2709,6 +2713,9 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
}
}
+ else if (!strcasecmp(var, "capture-server")) {
+ mod_sofia_globals.capture_server = switch_core_strdup(mod_sofia_globals.pool, val);
+ }
}
}
@@ -2787,6 +2794,13 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
sofia_clear_flag(profile, TFLAG_TPORT_LOG);
}
nua_set_params(profile->nua, TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)), TAG_END());
+ } else if (!strcasecmp(var, "sip-capture")) {
+ if (switch_true(val)) {
+ sofia_set_flag(profile, TFLAG_CAPTURE);
+ } else {
+ sofia_clear_flag(profile, TFLAG_CAPTURE);
+ }
+ nua_set_params(profile->nua, TPTAG_CAPT(sofia_test_flag(profile, TFLAG_CAPTURE) ? mod_sofia_globals.capture_server : NULL), TAG_END());
} else if (!strcasecmp(var, "send-message-query-on-register")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
@@ -2954,6 +2968,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
} else {
profile->ndlb &= ~PFLAG_NDLB_ALLOW_BAD_IANANAME;
}
+ } else if (!strcasecmp(var, "NDLB-allow-nondup-sdp")) {
+ if (switch_true(val)) {
+ profile->ndlb |= PFLAG_NDLB_ALLOW_NONDUP_SDP;
+ } else {
+ profile->ndlb &= ~PFLAG_NDLB_ALLOW_NONDUP_SDP;
+ }
} else if (!strcasecmp(var, "aggressive-nat-detection")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
@@ -3384,6 +3404,9 @@ switch_status_t config_sofia(int reload, char *profile_name)
mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
}
}
+ else if (!strcasecmp(var, "capture-server")) {
+ mod_sofia_globals.capture_server = switch_core_strdup(mod_sofia_globals.pool, val);
+ }
}
}
@@ -3462,6 +3485,7 @@ switch_status_t config_sofia(int reload, char *profile_name)
profile->local_network = "localnet.auto";
sofia_set_flag(profile, TFLAG_ENABLE_SOA);
sofia_set_pflag(profile, PFLAG_CID_IN_1XX);
+ profile->ndlb |= PFLAG_NDLB_ALLOW_NONDUP_SDP;
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
@@ -3475,6 +3499,9 @@ switch_status_t config_sofia(int reload, char *profile_name)
profile->shutdown_type = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "sip-trace") && switch_true(val)) {
sofia_set_flag(profile, TFLAG_TPORT_LOG);
+ } else if (!strcasecmp(var, "sip-capture") && switch_true(val)) {
+ sofia_set_flag(profile, TFLAG_CAPTURE);
+ nua_set_params(profile->nua, TPTAG_CAPT(mod_sofia_globals.capture_server), TAG_END());
} else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
if (switch_odbc_available()) {
profile->odbc_dsn = switch_core_strdup(profile->pool, val);
@@ -3952,6 +3979,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
} else {
profile->ndlb &= ~PFLAG_NDLB_ALLOW_BAD_IANANAME;
}
+ } else if (!strcasecmp(var, "NDLB-allow-nondup-sdp")) {
+ if (switch_true(val)) {
+ profile->ndlb |= PFLAG_NDLB_ALLOW_NONDUP_SDP;
+ } else {
+ profile->ndlb &= ~PFLAG_NDLB_ALLOW_NONDUP_SDP;
+ }
} else if (!strcasecmp(var, "pass-rfc2833")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PASS_RFC2833);
@@ -5074,11 +5107,13 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
}
if (session) {
- if ((switch_channel_test_flag(channel, CF_EARLY_MEDIA) || switch_channel_test_flag(channel, CF_ANSWERED)) && (status == 180 || status == 183)) {
+ if ((switch_channel_test_flag(channel, CF_EARLY_MEDIA) || switch_channel_test_flag(channel, CF_ANSWERED)) && (status == 180 || status == 183) && !r_sdp) {
/* Must you send 180 after 183 w/sdp ? sheesh */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel %s skipping state [%s][%d]\n",
switch_channel_get_name(channel), nua_callstate_name(ss_state), status);
goto done;
+ } else if (switch_channel_test_flag(channel, CF_EARLY_MEDIA) && (status == 180 || status == 183) && r_sdp) {
+ sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel %s entering state [%s][%d]\n",
@@ -5088,7 +5123,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
sdp_parser_t *parser;
sdp_session_t *sdp;
- if (!zstr(tech_pvt->remote_sdp_str) && !strcmp(tech_pvt->remote_sdp_str, r_sdp)) {
+ if (!(profile->ndlb & PFLAG_NDLB_ALLOW_NONDUP_SDP) || (!zstr(tech_pvt->remote_sdp_str) && !strcmp(tech_pvt->remote_sdp_str, r_sdp))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Duplicate SDP\n%s\n", r_sdp);
is_dup_sdp = 1;
} else {
@@ -5176,7 +5211,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
switch_channel_mark_pre_answered(channel);
sofia_set_flag(tech_pvt, TFLAG_SDP);
- if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) || sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
goto done;
}
@@ -5597,6 +5632,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n");
+ sofia_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+
if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
@@ -5804,6 +5841,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
switch_snprintf(st, sizeof(st), "%d", cause);
switch_channel_set_variable(channel, "sip_term_cause", st);
switch_channel_hangup(channel, cause);
+ ss_state = nua_callstate_terminated;
}
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index 508e5b19dc..062da61a98 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -208,6 +208,7 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen,
if (!noptime) {
if (!cur_ptime) {
+#if 0
if (ptime) {
if (ptime != imp->microseconds_per_packet / 1000) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
@@ -225,6 +226,11 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen,
} else {
ptime = imp->microseconds_per_packet / 1000;
}
+#else
+ if (!ptime) {
+ ptime = imp->microseconds_per_packet / 1000;
+ }
+#endif
} else {
if ((imp->microseconds_per_packet / 1000) != cur_ptime) {
continue;
@@ -544,7 +550,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
} else if (tech_pvt->num_codecs) {
int i;
int cur_ptime = 0, this_ptime = 0, cng_type = 0;
-
+ const char *mult;
if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SUPPRESS_CNG) && tech_pvt->cng_pt && use_cng) {
cng_type = tech_pvt->cng_pt;
@@ -553,8 +559,10 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
tech_pvt->cng_pt = 0;
}
}
-
- if (!switch_true(switch_channel_get_variable(tech_pvt->channel, "sdp_m_per_ptime"))) {
+
+ mult = switch_channel_get_variable(tech_pvt->channel, "sdp_m_per_ptime");
+
+ if (mult && switch_false(mult)) {
char *bp = buf;
if ((!zstr(tech_pvt->local_crypto_key) && sofia_test_flag(tech_pvt, TFLAG_SECURE))) {
@@ -1855,7 +1863,12 @@ char *sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix
char *extra_headers = NULL;
switch_stream_handle_t stream = { 0 };
switch_event_header_t *hi = NULL;
+ const char *exclude_regex = NULL;
+ switch_regex_t *re = NULL;
+ int ovector[30] = {0};
+ int proceed;
+ exclude_regex = switch_channel_get_variable(channel, "exclude_outgoing_extra_header");
SWITCH_STANDARD_STREAM(stream);
if ((hi = switch_channel_variable_first(channel))) {
for (; hi; hi = hi->next) {
@@ -1863,8 +1876,13 @@ char *sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix
char *value = (char *) hi->value;
if (!strncasecmp(name, prefix, strlen(prefix))) {
- const char *hname = name + strlen(prefix);
- stream.write_function(&stream, "%s: %s\r\n", hname, value);
+ if ( !exclude_regex || !(proceed = switch_regex_perform(name, exclude_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+ const char *hname = name + strlen(prefix);
+ stream.write_function(&stream, "%s: %s\r\n", hname, value);
+ switch_regex_safe_free(re);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring Extra Header [%s] , matches exclude_outgoing_extra_header [%s]\n", name, exclude_regex);
+ }
}
}
switch_channel_variable_last(channel);
@@ -3031,7 +3049,6 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
flags &= ~SWITCH_RTP_FLAG_BYTESWAP;
}
-
if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
@@ -3099,7 +3116,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
const char *rport = NULL;
switch_port_t remote_rtcp_port = 0;
- sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+
if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) {
remote_rtcp_port = (switch_port_t)atoi(rport);
@@ -3580,6 +3597,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
end:
+ sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
sofia_glue_tech_track(tech_pvt->profile, tech_pvt->session);
@@ -5240,6 +5258,27 @@ void sofia_glue_global_siptrace(switch_bool_t on)
}
+void sofia_glue_global_capture(switch_bool_t on)
+{
+ switch_hash_index_t *hi;
+ const void *var;
+ void *val;
+ sofia_profile_t *pptr;
+
+ switch_mutex_lock(mod_sofia_globals.hash_mutex);
+ if (mod_sofia_globals.profile_hash) {
+ for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, &var, NULL, &val);
+ if ((pptr = (sofia_profile_t *) val)) {
+ nua_set_params(pptr->nua, TPTAG_CAPT(on ? mod_sofia_globals.capture_server : NULL), TAG_END());
+ }
+ }
+ }
+ switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+}
+
+
void sofia_glue_global_watchdog(switch_bool_t on)
{
switch_hash_index_t *hi;
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 88c5dd4ec6..520b4e6849 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -1831,8 +1831,17 @@ void sofia_reg_handle_sip_r_register(int status,
const char *new_expires;
uint32_t expi;
if (contact->m_next) {
- const char *sipip = profile->extsipip ? profile->extsipip : profile->sipip;
- for (; contact && strcasecmp(contact->m_url->url_host, sipip); contact = contact->m_next);
+ char *full;
+
+ for (; contact; contact = contact->m_next) {
+ if ((full = sip_header_as_string(nh->nh_home, (void *) contact))) {
+ if (switch_stristr(sofia_private->gateway->register_contact, full)) {
+ break;
+ }
+
+ su_free(nh->nh_home, full);
+ }
+ }
}
if (!contact) {
diff --git a/src/switch_channel.c b/src/switch_channel.c
index f5667100a8..3f96616794 100644
--- a/src/switch_channel.c
+++ b/src/switch_channel.c
@@ -2606,6 +2606,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc
SWITCH_DECLARE(void) switch_channel_flip_cid(switch_channel_t *channel)
{
+ switch_event_t *event;
+
switch_mutex_lock(channel->profile_mutex);
if (channel->caller_profile->callee_id_name) {
switch_channel_set_variable(channel, "pre_transfer_caller_id_name", channel->caller_profile->caller_id_name);
@@ -2620,6 +2622,19 @@ SWITCH_DECLARE(void) switch_channel_flip_cid(switch_channel_t *channel)
channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING;
switch_mutex_unlock(channel->profile_mutex);
+
+ if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
+ const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "RECV");
+
+ if (uuid) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
+ }
+ switch_channel_event_set_data(channel, event);
+ switch_event_fire(&event);
+ }
+
+
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(channel->session), SWITCH_LOG_INFO, "%s Flipping CID from \"%s\" <%s> to \"%s\" <%s>\n",
switch_channel_get_name(channel),
switch_str_nil(switch_channel_get_variable(channel, "pre_transfer_caller_id_name")),
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index 038dda1b83..168bec3695 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -503,7 +503,7 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
if (channel) {
const char *val;
switch_codec_t *vid_read_codec = NULL, *read_codec = switch_core_session_get_read_codec(session);
- const char *max_forwards = switch_core_session_sprintf(session, "%d", forwardval);
+ const char *ep, *max_forwards = switch_core_session_sprintf(session, "%d", forwardval);
switch_channel_set_variable(peer_channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
@@ -523,6 +523,9 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
switch_snprintf(tmp, sizeof(tmp), "%s%s", rc, vrc);
switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_CODEC_VARIABLE, tmp);
+ } else if ((ep = switch_channel_get_variable(channel, "ep_codec_string"))) {
+ printf("SET [%s] [%s]\n", switch_channel_get_name(peer_channel), ep);
+ switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_CODEC_VARIABLE, ep);
}
switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_VARIABLE, switch_core_session_get_uuid(session));
diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c
index c71b105633..3ef516a80b 100644
--- a/src/switch_core_sqldb.c
+++ b/src/switch_core_sqldb.c
@@ -1206,28 +1206,20 @@ static void core_event_handler(switch_event_t *event)
const char *uuid = switch_event_get_header(event, "unique-id");
if (uuid) {
- new_sql() = switch_mprintf("delete from channels where uuid='%q' and hostname='%q'",
- uuid, switch_core_get_switchname());
+ new_sql() = switch_mprintf("delete from channels where uuid='%q'",
+ uuid);
- new_sql() = switch_mprintf("delete from calls where (caller_uuid='%q' or callee_uuid='%q') and hostname='%q'",
- uuid, uuid, switch_core_get_switchname());
+ new_sql() = switch_mprintf("delete from calls where (caller_uuid='%q' or callee_uuid='%q')",
+ uuid, uuid);
}
}
break;
case SWITCH_EVENT_CHANNEL_UUID:
{
- new_sql() = switch_mprintf("update channels set uuid='%q' where uuid='%q' and hostname='%q';"
- "update calls set caller_uuid='%q' where caller_uuid='%q' and hostname='%q';"
- "update calls set callee_uuid='%q' where callee_uuid='%q' and hostname='%q'",
+ new_sql() = switch_mprintf("update channels set uuid='%q' where uuid='%q'",
switch_event_get_header_nil(event, "unique-id"),
- switch_event_get_header_nil(event, "old-unique-id"),
- switch_core_get_switchname(),
- switch_event_get_header_nil(event, "unique-id"),
- switch_event_get_header_nil(event, "old-unique-id"),
- switch_core_get_switchname(),
- switch_event_get_header_nil(event, "unique-id"),
- switch_event_get_header_nil(event, "old-unique-id"), switch_core_get_switchname()
+ switch_event_get_header_nil(event, "old-unique-id")
);
break;
}
@@ -1249,26 +1241,26 @@ static void core_event_handler(switch_event_t *event)
new_sql() =
switch_mprintf
- ("update channels set read_codec='%q',read_rate='%q',read_bit_rate='%q',write_codec='%q',write_rate='%q',write_bit_rate='%q' where uuid='%q' and hostname='%q'",
+ ("update channels set read_codec='%q',read_rate='%q',read_bit_rate='%q',write_codec='%q',write_rate='%q',write_bit_rate='%q' where uuid='%q'",
switch_event_get_header_nil(event, "channel-read-codec-name"),
switch_event_get_header_nil(event, "channel-read-codec-rate"),
switch_event_get_header_nil(event, "channel-read-codec-bit-rate"),
switch_event_get_header_nil(event, "channel-write-codec-name"),
switch_event_get_header_nil(event, "channel-write-codec-rate"),
switch_event_get_header_nil(event, "channel-write-codec-bit-rate"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
break;
case SWITCH_EVENT_CHANNEL_HOLD:
case SWITCH_EVENT_CHANNEL_UNHOLD:
case SWITCH_EVENT_CHANNEL_EXECUTE: {
new_sql() = switch_mprintf("update channels set application='%q',application_data='%q',"
- "presence_id='%q',presence_data='%q' where uuid='%q' and hostname='%q'",
+ "presence_id='%q',presence_data='%q' where uuid='%q'",
switch_event_get_header_nil(event, "application"),
switch_event_get_header_nil(event, "application-data"),
switch_event_get_header_nil(event, "channel-presence-id"),
switch_event_get_header_nil(event, "channel-presence-data"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname()
+ switch_event_get_header_nil(event, "unique-id")
);
}
@@ -1278,20 +1270,20 @@ static void core_event_handler(switch_event_t *event)
{
if ((extra_cols = parse_presence_data_cols(event))) {
new_sql() = switch_mprintf("update channels set "
- "presence_id='%q',presence_data='%q', call_uuid='%q',%s where uuid='%q' and hostname='%q'",
+ "presence_id='%q',presence_data='%q', call_uuid='%q',%s where uuid='%q'",
switch_event_get_header_nil(event, "channel-presence-id"),
switch_event_get_header_nil(event, "channel-presence-data"),
switch_event_get_header_nil(event, "channel-call-uuid"),
extra_cols,
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
free(extra_cols);
} else {
new_sql() = switch_mprintf("update channels set "
- "presence_id='%q',presence_data='%q', call_uuid='%q' where uuid='%q' and hostname='%q'",
+ "presence_id='%q',presence_data='%q', call_uuid='%q' where uuid='%q'",
switch_event_get_header_nil(event, "channel-presence-id"),
switch_event_get_header_nil(event, "channel-presence-data"),
switch_event_get_header_nil(event, "channel-call-uuid"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
}
}
@@ -1299,44 +1291,15 @@ static void core_event_handler(switch_event_t *event)
break;
case SWITCH_EVENT_CALL_UPDATE:
{
- const char *name = NULL, *number = NULL, *direction;
- int recv = 0;
-
- direction = switch_event_get_header(event, "direction");
-
- if (direction && strcasecmp(direction, "send")) {
- recv = 1;
- name = switch_event_get_header(event, "callee-name");
- number = switch_event_get_header(event, "callee-number");
- }
-
- if (!name) {
- name = switch_event_get_header(event, "caller-callee-id-name");
- }
-
- if (!number) {
- number = switch_event_get_header(event, "caller-callee-id-number");
- }
-
- if (!zstr(name) && !zstr(number)) {
- new_sql() = switch_mprintf("update channels set state='%s',callstate='%s',callee_name='%q',"
- "callee_num='%q',callee_direction='%q' where uuid='%s' and hostname='%q'",
- switch_event_get_header_nil(event, "channel-state"),
- switch_event_get_header_nil(event, "channel-call-state"),
- switch_str_nil(name),
- switch_str_nil(number),
- switch_event_get_header_nil(event, "direction"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
-
- name = switch_event_get_header(event, "callee-name");
- number = switch_event_get_header(event, "callee-number");
-
- if (name && number && recv) {
- new_sql() = switch_mprintf("update calls set callee_cid_name='%q',callee_cid_num='%q' where caller_uuid='%q'",
- name, number, switch_event_get_header_nil(event, "unique-id"));
-
- }
- }
+ new_sql() = switch_mprintf("update channels set callee_name='%q',callee_num='%q',callee_direction='%q',"
+ "cid_name='%q',cid_num='%q' where uuid='%s'",
+ switch_event_get_header_nil(event, "caller-callee-id-name"),
+ switch_event_get_header_nil(event, "caller-callee-id-number"),
+ switch_event_get_header_nil(event, "direction"),
+ switch_event_get_header_nil(event, "caller-caller-id-name"),
+ switch_event_get_header_nil(event, "caller-caller-id-number"),
+ switch_event_get_header_nil(event, "unique-id")
+ );
}
break;
case SWITCH_EVENT_CHANNEL_CALLSTATE:
@@ -1349,9 +1312,9 @@ static void core_event_handler(switch_event_t *event)
}
if (callstate != CCS_DOWN && callstate != CCS_HANGUP) {
- new_sql() = switch_mprintf("update channels set callstate='%q' where uuid='%q' and hostname='%q'",
+ new_sql() = switch_mprintf("update channels set callstate='%q' where uuid='%q'",
switch_event_get_header_nil(event, "channel-call-state"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
}
}
@@ -1373,12 +1336,14 @@ static void core_event_handler(switch_event_t *event)
break;
case CS_ROUTING:
if ((extra_cols = parse_presence_data_cols(event))) {
- new_sql() = switch_mprintf("update channels set state='%s',cid_name='%q',cid_num='%q',"
+ new_sql() = switch_mprintf("update channels set state='%s',cid_name='%q',cid_num='%q',callee_name='%q',callee_num='%q',"
"ip_addr='%s',dest='%q',dialplan='%q',context='%q',presence_id='%q',presence_data='%q',%s "
- "where uuid='%s' and hostname='%q'",
+ "where uuid='%s'",
switch_event_get_header_nil(event, "channel-state"),
switch_event_get_header_nil(event, "caller-caller-id-name"),
switch_event_get_header_nil(event, "caller-caller-id-number"),
+ switch_event_get_header_nil(event, "caller-callee-id-name"),
+ switch_event_get_header_nil(event, "caller-callee-id-number"),
switch_event_get_header_nil(event, "caller-network-addr"),
switch_event_get_header_nil(event, "caller-destination-number"),
switch_event_get_header_nil(event, "caller-dialplan"),
@@ -1386,28 +1351,30 @@ static void core_event_handler(switch_event_t *event)
switch_event_get_header_nil(event, "channel-presence-id"),
switch_event_get_header_nil(event, "channel-presence-data"),
extra_cols,
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
free(extra_cols);
} else {
- new_sql() = switch_mprintf("update channels set state='%s',cid_name='%q',cid_num='%q',"
+ new_sql() = switch_mprintf("update channels set state='%s',cid_name='%q',cid_num='%q',callee_name='%q',callee_num='%q',"
"ip_addr='%s',dest='%q',dialplan='%q',context='%q',presence_id='%q',presence_data='%q' "
- "where uuid='%s' and hostname='%q'",
+ "where uuid='%s'",
switch_event_get_header_nil(event, "channel-state"),
switch_event_get_header_nil(event, "caller-caller-id-name"),
switch_event_get_header_nil(event, "caller-caller-id-number"),
+ switch_event_get_header_nil(event, "caller-callee-id-name"),
+ switch_event_get_header_nil(event, "caller-callee-id-number"),
switch_event_get_header_nil(event, "caller-network-addr"),
switch_event_get_header_nil(event, "caller-destination-number"),
switch_event_get_header_nil(event, "caller-dialplan"),
switch_event_get_header_nil(event, "caller-context"),
switch_event_get_header_nil(event, "channel-presence-id"),
switch_event_get_header_nil(event, "channel-presence-data"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
}
break;
default:
- new_sql() = switch_mprintf("update channels set state='%s' where uuid='%s' and hostname='%q'",
+ new_sql() = switch_mprintf("update channels set state='%s' where uuid='%s'",
switch_event_get_header_nil(event, "channel-state"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
break;
}
@@ -1417,60 +1384,19 @@ static void core_event_handler(switch_event_t *event)
}
case SWITCH_EVENT_CHANNEL_BRIDGE:
{
- const char *callee_cid_name, *callee_cid_num, *direction;
- char *func_name;
- char *aleg_uuid, *bleg_uuid;
-
- direction = switch_event_get_header(event, "other-leg-direction");
- if (direction && !strcasecmp(direction, "outbound")) {
- callee_cid_name = switch_event_get_header_nil(event, "Other-Leg-callee-id-name");
- callee_cid_num = switch_event_get_header_nil(event, "Other-Leg-callee-id-number");
- } else {
- callee_cid_name = switch_event_get_header_nil(event, "Other-Leg-caller-id-name");
- callee_cid_num = switch_event_get_header_nil(event, "Other-Leg-caller-id-number");
- }
-
-
- new_sql() = switch_mprintf("update channels set call_uuid='%q' where uuid='%s' and hostname='%q'",
+ new_sql() = switch_mprintf("update channels set call_uuid='%q' where uuid='%s'",
switch_event_get_header_nil(event, "channel-call-uuid"),
- switch_event_get_header_nil(event, "unique-id"), switch_core_get_switchname());
+ switch_event_get_header_nil(event, "unique-id"));
- if (runtime.odbc_dbtype == DBTYPE_DEFAULT) {
- func_name = "function";
- }
- else {
- func_name = "call_function";
- }
-
- aleg_uuid = switch_event_get_header_nil(event, "caller-unique-id");
- bleg_uuid = switch_event_get_header_nil(event, "Other-Leg-unique-id");
-
-
- new_sql() = switch_mprintf("update channels set originatee='%s' where uuid='%s'", bleg_uuid, aleg_uuid);
- new_sql() = switch_mprintf("update channels set originator='%s' where uuid='%s'", aleg_uuid, bleg_uuid);
-
-
-
- new_sql() = switch_mprintf("insert into calls (call_uuid,call_created,call_created_epoch,%s,caller_cid_name,"
- "caller_cid_num,caller_dest_num,caller_chan_name,caller_uuid,callee_cid_name,"
- "callee_cid_num,callee_dest_num,callee_chan_name,callee_uuid,hostname) "
- "values ('%s', '%s', '%ld', '%s','%q','%q','%q','%q','%s','%q','%q','%q','%q','%s','%q')",
- func_name,
+ new_sql() = switch_mprintf("insert into calls (call_uuid,call_created,call_created_epoch,"
+ "caller_uuid,callee_uuid,hostname) "
+ "values ('%s','%s','%ld','%q','%q','%q')",
switch_event_get_header_nil(event, "channel-call-uuid"),
switch_event_get_header_nil(event, "event-date-local"),
(long) switch_epoch_time_now(NULL),
- switch_event_get_header_nil(event, "event-calling-function"),
- switch_event_get_header_nil(event, "caller-caller-id-name"),
- switch_event_get_header_nil(event, "caller-caller-id-number"),
- switch_event_get_header_nil(event, "caller-destination-number"),
- switch_event_get_header_nil(event, "caller-channel-name"),
- aleg_uuid,
- callee_cid_name,
- callee_cid_num,
- switch_event_get_header_nil(event, "Other-Leg-destination-number"),
- switch_event_get_header_nil(event, "Other-Leg-channel-name"),
- bleg_uuid,
+ switch_event_get_header_nil(event, "caller-unique-id"),
+ switch_event_get_header_nil(event, "Other-Leg-unique-id"),
switch_core_get_switchname()
);
}
@@ -1479,12 +1405,8 @@ static void core_event_handler(switch_event_t *event)
{
char *uuid = switch_event_get_header_nil(event, "caller-unique-id");
- new_sql() = switch_mprintf("delete from calls where (caller_uuid='%q' or callee_uuid='%q') and hostname='%q'",
- uuid, uuid, switch_core_get_switchname());
-
- new_sql() = switch_mprintf("update channels set originator=null,originatee=null where uuid='%s' or originator='%s' or originatee='%s'",
- uuid, uuid, uuid);
-
+ new_sql() = switch_mprintf("delete from calls where (caller_uuid='%q' or callee_uuid='%q')",
+ uuid, uuid);
break;
}
case SWITCH_EVENT_SHUTDOWN:
@@ -1531,8 +1453,8 @@ static void core_event_handler(switch_event_t *event)
if (zstr(type)) {
break;
}
- new_sql() = switch_mprintf("update channels set secure='%s' where uuid='%s' and hostname='%q'",
- type, switch_event_get_header_nil(event, "caller-unique-id"), switch_core_get_switchname()
+ new_sql() = switch_mprintf("update channels set secure='%s' where uuid='%s'",
+ type, switch_event_get_header_nil(event, "caller-unique-id")
);
break;
}
@@ -1632,35 +1554,22 @@ static char create_channels_sql[] =
" callee_name VARCHAR(1024),\n"
" callee_num VARCHAR(256),\n"
" callee_direction VARCHAR(5),\n"
- " call_uuid VARCHAR(256),\n"
- " originator VARCHAR(256),\n"
- " originatee VARCHAR(256)\n"
+ " call_uuid VARCHAR(256)\n"
");\n"
- "create index ch_hn_index on channels (hostname);\n"
+ "create index chidx1 on channels (hostname);\n"
"create index uuindex on channels (uuid);\n"
- "create index uuindex2 on channels (call_uuid);\n"
- "create index uuindex3 on channels (originator);\n"
- "create index uuindex4 on channels (originatee);\n";
+ "create index uuindex2 on channels (call_uuid);\n";
static char create_calls_sql[] =
"CREATE TABLE calls (\n"
" call_uuid VARCHAR(255),\n"
" call_created VARCHAR(128),\n"
" call_created_epoch INTEGER,\n"
- " function VARCHAR(1024),\n"
- " caller_cid_name VARCHAR(1024),\n"
- " caller_cid_num VARCHAR(256),\n"
- " caller_dest_num VARCHAR(256),\n"
- " caller_chan_name VARCHAR(1024),\n"
" caller_uuid VARCHAR(256),\n"
- " callee_cid_name VARCHAR(1024),\n"
- " callee_cid_num VARCHAR(256),\n"
- " callee_dest_num VARCHAR(256),\n"
- " callee_chan_name VARCHAR(1024),\n"
" callee_uuid VARCHAR(256),\n"
" hostname VARCHAR(256)\n"
");\n"
- "create index ca_hn_index on calls (hostname);\n"
+ "create index callsidx1 on calls (hostname);\n"
"create index eruuindex on calls (caller_uuid);\n"
"create index eeuuindex on calls (callee_uuid);\n"
"create index eeuuindex2 on calls (call_uuid);\n";
@@ -1709,67 +1618,119 @@ static char create_registrations_sql[] =
"create index regindex1 on registrations (reg_user,realm,hostname);\n";
-static char view_sql[] =
+
+static char detailed_calls_sql[] =
"create view detailed_calls as select "
- "a.uuid uuid,\n"
- "a.direction direction,\n"
- "a.created created,\n"
- "a.created_epoch created_epoch,\n"
- "a.name name,\n"
- "a.state state,\n"
- "a.cid_name cid_name,\n"
- "a.cid_num cid_num,\n"
- "a.ip_addr ip_addr,\n"
- "a.dest dest,\n"
- "a.application application,\n"
- "a.application_data application_data,\n"
- "a.dialplan dialplan,\n"
- "a.context context,\n"
- "a.read_codec read_codec,\n"
- "a.read_rate read_rate,\n"
- "a.read_bit_rate read_bit_rate,\n"
- "a.write_codec write_codec,\n"
- "a.write_rate write_rate,\n"
- "a.write_bit_rate write_bit_rate,\n"
- "a.secure secure,\n"
- "a.hostname hostname,\n"
- "a.presence_id presence_id,\n"
- "a.presence_data presence_data,\n"
- "a.callstate callstate,\n"
- "a.callee_name callee_name,\n"
- "a.callee_num callee_num,\n"
- "a.callee_direction callee_direction,\n"
- "a.call_uuid call_uuid,\n"
- "b.uuid b_uuid,\n"
- "b.direction b_direction,\n"
- "b.created b_created,\n"
- "b.created_epoch b_created_epoch,\n"
- "b.name b_name,\n"
- "b.state b_state,\n"
- "b.cid_name b_cid_name,\n"
- "b.cid_num b_cid_num,\n"
- "b.ip_addr b_ip_addr,\n"
- "b.dest b_dest,\n"
- "b.application b_application,\n"
- "b.application_data b_application_data,\n"
- "b.dialplan b_dialplan,\n"
- "b.context b_context,\n"
- "b.read_codec b_read_codec,\n"
- "b.read_rate b_read_rate,\n"
- "b.read_bit_rate b_read_bit_rate,\n"
- "b.write_codec b_write_codec,\n"
- "b.write_rate b_write_rate,\n"
- "b.write_bit_rate b_write_bit_rate,\n"
- "b.secure b_secure,\n"
- "b.hostname b_hostname,\n"
- "b.presence_id b_presence_id,\n"
- "b.presence_data b_presence_data,\n"
- "b.callstate b_callstate,\n"
- "b.callee_name b_callee_name,\n"
- "b.callee_num b_callee_num,\n"
- "b.callee_direction b_callee_direction,\n"
- "b.call_uuid b_call_uuid\n"
- "from channels a left join channels b on a.originatee = b.uuid where a.originator is null";
+ "a.uuid as uuid,"
+ "a.direction as direction,"
+ "a.created as created,"
+ "a.created_epoch as created_epoch,"
+ "a.name as name,"
+ "a.state as state,"
+ "a.cid_name as cid_name,"
+ "a.cid_num as cid_num,"
+ "a.ip_addr as ip_addr,"
+ "a.dest as dest,"
+ "a.application as application,"
+ "a.application_data as application_data,"
+ "a.dialplan as dialplan,"
+ "a.context as context,"
+ "a.read_codec as read_codec,"
+ "a.read_rate as read_rate,"
+ "a.read_bit_rate as read_bit_rate,"
+ "a.write_codec as write_codec,"
+ "a.write_rate as write_rate,"
+ "a.write_bit_rate as write_bit_rate,"
+ "a.secure as secure,"
+ "a.hostname as hostname,"
+ "a.presence_id as presence_id,"
+ "a.presence_data as presence_data,"
+ "a.callstate as callstate,"
+ "a.callee_name as callee_name,"
+ "a.callee_num as callee_num,"
+ "a.callee_direction as callee_direction,"
+ "a.call_uuid as call_uuid,"
+ "b.uuid as b_uuid,"
+ "b.direction as b_direction,"
+ "b.created as b_created,"
+ "b.created_epoch as b_created_epoch,"
+ "b.name as b_name,"
+ "b.state as b_state,"
+ "b.cid_name as b_cid_name,"
+ "b.cid_num as b_cid_num,"
+ "b.ip_addr as b_ip_addr,"
+ "b.dest as b_dest,"
+ "b.application as b_application,"
+ "b.application_data as b_application_data,"
+ "b.dialplan as b_dialplan,"
+ "b.context as b_context,"
+ "b.read_codec as b_read_codec,"
+ "b.read_rate as b_read_rate,"
+ "b.read_bit_rate as b_read_bit_rate,"
+ "b.write_codec as b_write_codec,"
+ "b.write_rate as b_write_rate,"
+ "b.write_bit_rate as b_write_bit_rate,"
+ "b.secure as b_secure,"
+ "b.hostname as b_hostname,"
+ "b.presence_id as b_presence_id,"
+ "b.presence_data as b_presence_data,"
+ "b.callstate as b_callstate,"
+ "b.callee_name as b_callee_name,"
+ "b.callee_num as b_callee_num,"
+ "b.callee_direction as b_callee_direction,"
+ "b.call_uuid as b_call_uuid,"
+ "c.call_created_epoch as call_created_epoch "
+ "from channels a "
+ "left join calls c on a.uuid = c.caller_uuid and a.hostname = c.hostname "
+ "left join channels b on b.uuid = c.callee_uuid and b.hostname = c.hostname "
+ "where a.uuid = c.caller_uuid or a.uuid not in (select callee_uuid from calls)";
+
+
+static char basic_calls_sql[] =
+ "create view basic_calls as select "
+ "a.uuid as uuid,"
+ "a.direction as direction,"
+ "a.created as created,"
+ "a.created_epoch as created_epoch,"
+ "a.name as name,"
+ "a.state as state,"
+ "a.cid_name as cid_name,"
+ "a.cid_num as cid_num,"
+ "a.ip_addr as ip_addr,"
+ "a.dest as dest,"
+
+ "a.presence_id as presence_id,"
+ "a.presence_data as presence_data,"
+ "a.callstate as callstate,"
+ "a.callee_name as callee_name,"
+ "a.callee_num as callee_num,"
+ "a.callee_direction as callee_direction,"
+ "a.call_uuid as call_uuid,"
+ "a.hostname as hostname,"
+
+ "b.uuid as b_uuid,"
+ "b.direction as b_direction,"
+ "b.created as b_created,"
+ "b.created_epoch as b_created_epoch,"
+ "b.name as b_name,"
+ "b.state as b_state,"
+ "b.cid_name as b_cid_name,"
+ "b.cid_num as b_cid_num,"
+ "b.ip_addr as b_ip_addr,"
+ "b.dest as b_dest,"
+
+ "b.presence_id as b_presence_id,"
+ "b.presence_data as b_presence_data,"
+ "b.callstate as b_callstate,"
+ "b.callee_name as b_callee_name,"
+ "b.callee_num as b_callee_num,"
+ "b.callee_direction as b_callee_direction,"
+ "c.call_created_epoch as call_created_epoch "
+
+ "from channels a "
+ "left join calls c on a.uuid = c.caller_uuid and a.hostname = c.hostname "
+ "left join channels b on b.uuid = c.callee_uuid and b.hostname = c.hostname "
+ "where a.uuid = c.caller_uuid or a.uuid not in (select callee_uuid from calls)";
SWITCH_DECLARE(switch_status_t) switch_core_add_registration(const char *user, const char *realm, const char *token, const char *url, uint32_t expires,
@@ -1911,8 +1872,9 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
case SCDB_TYPE_CORE_DB:
{
switch_cache_db_execute_sql(dbh, "drop table channels", NULL);
- switch_cache_db_execute_sql(dbh, "drop view detailed_calls", NULL);
switch_cache_db_execute_sql(dbh, "drop table calls", NULL);
+ switch_cache_db_execute_sql(dbh, "drop view detailed_calls", NULL);
+ switch_cache_db_execute_sql(dbh, "drop view basic_calls", NULL);
switch_cache_db_execute_sql(dbh, "drop table interfaces", NULL);
switch_cache_db_execute_sql(dbh, "drop table tasks", NULL);
switch_cache_db_execute_sql(dbh, "PRAGMA synchronous=OFF;", NULL);
@@ -1937,8 +1899,8 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
{
char *err;
switch_cache_db_test_reactive(dbh, "select call_uuid, read_bit_rate from channels", "DROP TABLE channels", create_channels_sql);
- switch_cache_db_test_reactive(dbh, "select * from detailed_calls", NULL, view_sql);
-
+ switch_cache_db_test_reactive(dbh, "select * from detailed_calls", "DROP VIEW detailed_calls", detailed_calls_sql);
+ switch_cache_db_test_reactive(dbh, "select * from basic_calls", "DROP VIEW basic_call", basic_calls_sql);
if (runtime.odbc_dbtype == DBTYPE_DEFAULT) {
switch_cache_db_test_reactive(dbh, "select call_uuid from calls", "DROP TABLE calls", create_calls_sql);
} else {
@@ -1971,11 +1933,11 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
case SCDB_TYPE_CORE_DB:
{
switch_cache_db_execute_sql(dbh, create_channels_sql, NULL);
- switch_cache_db_execute_sql(dbh, view_sql, NULL);
-
switch_cache_db_execute_sql(dbh, create_calls_sql, NULL);
switch_cache_db_execute_sql(dbh, create_interfaces_sql, NULL);
switch_cache_db_execute_sql(dbh, create_tasks_sql, NULL);
+ switch_cache_db_execute_sql(dbh, detailed_calls_sql, NULL);
+ switch_cache_db_execute_sql(dbh, basic_calls_sql, NULL);
}
break;
}
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index 7e70557191..0ce47d9231 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -1148,7 +1148,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
}
if (switch_socket_bind(new_sock, rtp_session->local_addr) != SWITCH_STATUS_SUCCESS) {
- *err = "Bind Error!";
+ char *em = switch_core_sprintf(rtp_session->pool, "Bind Error! %s:%d", host, port);
+ *err = em;
goto done;
}