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; }