]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: add MF dumping support to ftmod_r2
authorMoises Silva <moy@sangoma.com>
Fri, 3 Dec 2010 21:50:03 +0000 (16:50 -0500)
committerMoises Silva <moy@sangoma.com>
Fri, 3 Dec 2010 21:50:03 +0000 (16:50 -0500)
         improve sample configuration documentation for MFC-R2

libs/freetdm/conf/freetdm.conf
libs/freetdm/conf/freetdm.conf.xml
libs/freetdm/src/ftdm_io.c
libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c

index bbaf1e36873a6fc999b9b8ae5527bfd2becb3b11..a6573204482bb9c8deecfbe15774ae377e26895e 100644 (file)
@@ -45,3 +45,17 @@ fxs-channel => 1
 number => 2
 fxo-channel => 3
 
+; MFC-R2 typical span configuration
+
+; MFC-R2 with wanpipe (Sangoma)
+[span wanpipe myWanpipeSpan]
+trunk_type => E1
+cas-channel => 1-15:1101
+cas-channel => 17-31:1101
+
+; MFC-R2 with Zaptel/DAHDI
+[span zt myWanpipeSpan]
+trunk_type => E1
+cas-channel => 1-15:1101
+cas-channel => 17-31:1101
+
index 986074dffb23631f718314151d3f054fa3c7aa3c..63a3ea62cd7bfac832e1a42e97c3eff0d1b9d484 100644 (file)
 <!-- Please refer to http://wiki.freeswitch.org/wiki/FreeTDM for further documentation  -->
 
+<!-- 
+This is a sample FreeSWITCH XML configuration for FreeTDM
+Remember you still need to configure freetdm.conf (no XML extension) in $prefix/conf/
+directory of FreeSWITCH. The freetdm.conf (no XML extension) is a simple text file
+definining the I/O interfaces (Sangoma, DAHDI etc). This file (freetdm.conf.xml) deals
+with the signaling protocols that you can run on top of your I/O interfaces.
+-->
 <configuration name="freetdm.conf" description="FreeTDM Configuration">
-  <settings>
-    <param name="debug" value="0"/>
-    <!--<param name="hold-music" value="$${moh_uri}"/>-->
-    <!--<param name="enable-analog-option" value="call-swap"/>-->
-    <!--<param name="enable-analog-option" value="3-way"/>-->
-  </settings>
-
-  <!-- use the <pri_spans> tag for native ISDN support (most likely broken at this point, check sangoma_pri_spans or libpri_spans for alternatives) -->
-   <pri_spans>
-     <span name="PRI_1">
-       <!-- Log Levels: none, alert, crit, err, warning, notice, info, debug -->
-       <param name="q921loglevel" value="alert"/>
-       <param name="q931loglevel" value="alert"/>
-       <param name="mode" value="user"/>
-       <param name="dialect" value="5ess"/>
-       <param name="dialplan" value="XML"/>
-       <param name="context" value="default"/>
-     </span>
-     <span name="PRI_2">
-       <param name="q921loglevel" value="alert"/>
-       <param name="q931loglevel" value="alert"/>
-       <param name="mode" value="user"/>
-       <param name="dialect" value="5ess"/>
-       <param name="dialplan" value="XML"/>
-       <param name="context" value="default"/>
-     </span>
-   </pri_spans>
-
-
-  <!-- Analog spans go here -->
-  <analog_spans>
-    <span name="myAnalog">
-      <!--<param name="hold-music" value="$${moh_uri}"/>-->
-      <!--<param name="enable-analog-option" value="call-swap"/>-->
-      <!--<param name="enable-analog-option" value="3-way"/>-->
-      <param name="tonegroup" value="us"/>
-      <param name="digit-timeout" value="2000"/>
-      <param name="max-digits" value="11"/>
-      <param name="dialplan" value="XML"/>
-      <param name="context" value="default"/>
-      <param name="enable-callerid" value="true"/>
-      <!-- regex to stop dialing when it matches -->
-      <!--<param name="dial-regex" value="5555"/>-->
-      <!-- regex to stop dialing when it does not match -->
-      <!--<param name="fail-dial-regex" value="^5"/>-->
-    </span>
-  </analog_spans>
+       
+       <settings>
+               <param name="debug" value="0"/>
+               <!--<param name="hold-music" value="$${moh_uri}"/>-->
+               <!--<param name="enable-analog-option" value="call-swap"/>-->
+               <!--<param name="enable-analog-option" value="3-way"/>-->
+       </settings>
 
+       <!-- Sample analog configuration -->
+       <analog_spans>
+               <!-- The span name must match the name in your freetdm.conf -->
+               <span name="myAnalog">
+                       <!--<param name="hold-music" value="$${moh_uri}"/>-->
+                       <!--<param name="enable-analog-option" value="call-swap"/>-->
+                       <!--<param name="enable-analog-option" value="3-way"/>-->
+                       <param name="tonegroup" value="us"/>
+                       <param name="digit-timeout" value="2000"/>
+                       <param name="max-digits" value="11"/>
+                       <param name="dialplan" value="XML"/>
+                       <param name="context" value="default"/>
+                       <param name="enable-callerid" value="true"/>
+                       <!-- regex to stop dialing when it matches -->
+                       <!--<param name="dial-regex" value="5555"/>-->
+                       <!-- regex to stop dialing when it does not match -->
+                       <!--<param name="fail-dial-regex" value="^5"/>-->
+               </span>
+       </analog_spans>
+
+       <!-- openr2 (MFC-R2 signaling) spans 
+       MFC-R2 signaling has lots of variants from country to country and even sometimes
+       minor variants inside the same country. The only mandatory parameters here are:
+       variant, but typically you also want to set max_ani and max_dnis.
+       IT IS RECOMMENDED that you leave the default values (leaving them commented) for the 
+       other parameters unless you have problems or you have been instructed to change some 
+       parameter. OpenR2 library uses the 'variant' parameter to try to determine the 
+       best defaults for your country.  If you want to contribute your configs for a particular 
+       country send them to the e-mail of the primary OpenR2 developer that you can find in the 
+       AUTHORS file of the OpenR2 package, they will be added to the samples directory of openr2.
+       -->
+       <r2_spans>
+               <span name="wp1" cfgprofile="testr2">
+                       
+                       <!--
+                       MFC/R2 variant. This depends on the OpenR2 supported variants
+                       A list of values can be found by executing the openr2 command r2test -l
+                       some valid values are:
+                       mx (Mexico)
+                       ar (Argentina)
+                       br (Brazil)
+                       ph (Philippines)
+                       itu (per ITU spec)
+                       -->
+                       <param name="variant" value="mx"/>
+
+                       <!-- switch parameters (required), where to send calls to -->
+                       <param name="dialplan" value="XML"/>
+                       <param name="context" value="default"/>
+
+                       <!-- 
+                       Max amount of ANI (caller id digits) to ask for
+                       <param name="max_ani" value="4"/> 
+                       -->
+                       <!-- 
+                       Max amount of DNIS to ask for 
+                       <param name="max_dnis" value="4"/> 
+                       -->
+
+                       <!-- Do not set parameters below this line unless you desire to tweak it because is not working -->
+                       
+                       <!-- 
+                       Whether or not to get the ANI before getting DNIS (only affects incoming calls)
+                       Some telcos require ANI first some others do not care, if default go wrong on 
+                       incoming calls, change this value
+                       <param name="get_ani_first" value="yes"/>
+                       -->
+
+                       <!--
+                       Caller Category to send. Accepted values:
+                               - national_subscriber
+                               - national_priority_subscriber
+                               - international_subscriber
+                               - international_priority_subscriber
+                               - collect_call
+                       Usually national_subscriber (the default) works just fine
+                       <param name="category" value="national_subscriber"/>
+                       -->
+
+                       <!--
+                       Brazil uses a special calling party category for collect calls (llamadas por cobrar)
+                       instead of using the operator (as in Mexico). The R2 spec in Brazil says a special GB tone
+                       should be used to reject collect calls. If you want to ALLOW collect calls specify 'yes',
+                       if you want to BLOCK collect calls then say 'no'. Default is to block collect calls.
+                       (see also 'double_answer')
+                       <param name="allow_collect_calls" value="yes"/>
+                       -->
+
+                       <!--
+                       This feature is related but independent of allow_collect_calls
+                       Some PBX's require a double-answer process to block collect calls, if
+                       you ever have problems blocking collect calls using Group B signals (allow_collect_calls=no)
+                       then you may want to try with double_answer=yes, this will cause that every answer signal
+                       is changed to perform 'answer -> clear back -> answer' (sort of a flash)
+                       (see also 'allow_collect_calls')
+                       <param name="double_answer" value="yes"/>
+                       -->
+
+                       <!--
+                       This feature allows to skip the use of Group B/II signals and go directly
+                       to the accepted state for incoming calls
+                       <param name="immediate_accept" value="yes"/>
+                       -->
+
+                       <!--
+                       Skip request of calling party category and ANI
+                       <param name="skip_category" value="yes"/>
+                       -->
+
+                       <!--
+                       Brazil use a special signal to force the release of the line (hangup) from the
+                       backward perspective. When forced_release=no, the normal clear back signal
+                       will be sent on hangup, which is OK for all mfcr2 variants I know of, except for
+                       Brazilian variant, where the central will leave the line up for several seconds (30, 60)
+                       which sometimes is not what people really want. When forced_release=yes, a different
+                       signal will be sent to hangup the call indicating that the line should be released immediately
+                       <param name="forced_release" value="yes"/>
+                       -->
+
+                       <!--
+                       Whether or not report to the other end 'accept call with charge'
+                       This setting has no effect with most telecos, usually is safe
+                       leave the default (yes), but once in a while when interconnecting with
+                       old PBXs this may be useful.
+                       Concretely this affects the Group B signal used to accept calls
+                       <param name="charge_calls" value="yes"/>
+                       -->
+
+                       <!--
+                       MFC/R2 value in milliseconds for the MF timeout. Any negative value
+                       means 'default', smaller values than 500ms are not recommended
+                       and can cause malfunctioning. If you experience protocol error
+                       due to MF timeout try incrementing this value in 500ms steps
+                       <param name="mfback_timeout" value="1500"/>
+                       -->
+
+                       <!--
+                       MFC/R2 value in milliseconds for the metering pulse timeout.
+                       Metering pulses are sent by some telcos for some R2 variants
+                       during a call presumably for billing purposes to indicate costs,
+                       however this pulses use the same signal that is used to indicate
+                       call hangup, therefore a timeout is sometimes required to distinguish
+                       between a *real* hangup and a billing pulse that should not
+                       last more than 500ms, If you experience call drops after some
+                       minutes of being stablished try setting a value of some ms here,
+                       values greater than 500ms are not recommended.
+                       BE AWARE that choosing the proper protocol variant parameter
+                       implicitly sets a good recommended value for this timer, use this
+                       parameter only when you *really* want to override the default, otherwise
+                       just comment out this value.
+                       <param name="metering_pulse_timeout" value="1000"/>
+                       -->
+
+                       <!--
+                       WARNING: advanced users only! I really mean it
+                       this parameter is commented by default because
+                       YOU DON'T NEED IT UNLESS YOU REALLY GROK MFC/R2
+                       READ COMMENTS on doc/r2proto.conf in openr2 package 
+                       for more info
+                       <param name="advanced_protocol_file" value="/usr/local/freeswitch/conf/r2proto.conf"/>
+                       -->
+
+                       <!-- USE THIS FOR DEBUGGING MFC-R2 PROTOCOL -->
+                       <!-- 
+                       Where to dump advanced call file protocol logs
+                       <param name="logdir" value="$${base_dir}/log/mfcr2"/>
+                       -->
+
+                       <!-- 
+                       MFC/R2 valid logging values are: all,error,warning,debug,notice,cas,mf,nothing
+                       error,warning,debug and notice are self-descriptive
+                       'cas' is for logging ABCD CAS tx and rx
+                       'mf' is for logging of the Multi Frequency tones
+                       You can mix up values, like: loglevel=error,debug,mf to log just error, debug and 
+                       multi frequency messages
+                       'all' is a special value to log all the activity
+                       'nothing' is a clean-up value, in case you want to not log any activity for
+                       a channel or group of channels
+                       BE AWARE that the level of output logged will ALSO depend on
+                       the value you have in FreeSWITCH logging configurations, if you disable output FreeSWITCH
+                       then it does not matter if you specify 'all' here, nothing will be logged
+                       so FreeSWITCH has the last word on what is going to be logged
+                       <param name="logging" value="debug,notice,warning,error,mf,cas"/>
+                       -->
+
+                       <!-- 
+                       whether or not to drop protocol call files into 'logdir'
+                       <param name="call_files" value="yes"/>
+                       -->
+
+                       <!--
+                       Use only for very technical debugging
+                       This is the size (if 0, dumps are disabled) of MF dump files. MF dump files
+                       are audio files that are dumped when a protocol error occurs.
+                       The files are dumped in whatever you set in the logdir parameter.
+                       Value -1 uses a default recommended size (which stores 5 seconds of audio)
+                       <param name="mf_dump_size" value="-1"/>
+                       -->
+               </span>
+       </r2_spans>
 </configuration>
+
index c43d694dee266e605db5c9a0ec4694c59d4f2355..d2ad2498a0339823e9c45cb26566bb1a8092cc5f 100644 (file)
@@ -91,6 +91,10 @@ static void write_chan_io_dump(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, char
        int windex = dump->windex;
        int avail = dump->size - windex;
 
+       if (!dump->buffer) {
+               return;
+       }
+
        if (dlen > avail) {
                int diff = dlen - avail;
                
@@ -101,7 +105,7 @@ static void write_chan_io_dump(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, char
                memcpy(&dump->buffer[0], &dataptr[avail], diff);
                windex = diff;
 
-               ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p up to index %d\n\n", dump, windex);
+               /*ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p up to index %d\n\n", dump, windex);*/
                dump->wrapped = 1;
        } else {
                memcpy(&dump->buffer[windex], dataptr, dlen);
@@ -109,7 +113,7 @@ static void write_chan_io_dump(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, char
        }
 
        if (windex == dump->size) {
-               ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p\n", dump);
+               /*ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p\n", dump);*/
                windex = 0;
                dump->wrapped = 1;
        }
@@ -2525,7 +2529,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
        ftdm_buffer_destroy(&ftdmchan->pre_buffer);
        ftdmchan->pre_buffer_size = 0;
        ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
-       disable_dtmf_debug(ftdmchan);
        ftdm_channel_clear_vars(ftdmchan);
        if (ftdmchan->hangup_timer) {
                ftdm_sched_cancel_timer(globals.timingsched, ftdmchan->hangup_timer);
@@ -2534,8 +2537,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
        ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
        ftdmchan->state = FTDM_CHANNEL_STATE_DOWN;
 
-       stop_chan_io_dump(&ftdmchan->txdump);
-       stop_chan_io_dump(&ftdmchan->rxdump);
+       ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
+       ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
+       ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_DEBUG_DTMF, NULL);
 
        if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
                ftdm_sigmsg_t sigmsg;
@@ -2741,6 +2745,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
        case FTDM_COMMAND_ENABLE_INPUT_DUMP:
                {
                        ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
+                       if (ftdmchan->rxdump.buffer) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Input dump is already enabled\n");
+                               GOTO_STATUS(done, FTDM_FAIL);
+                       }
                        if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, size)) {
                                ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump\n");   
                                GOTO_STATUS(done, FTDM_FAIL);
@@ -2753,6 +2761,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
        /*!< Stop dumping all input to a circular buffer. */
        case FTDM_COMMAND_DISABLE_INPUT_DUMP:
                {
+                       if (!ftdmchan->rxdump.buffer) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable input dump\n");
+                               GOTO_STATUS(done, FTDM_SUCCESS);
+                       }
                        ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %zd\n", ftdmchan->rxdump.size);
                        stop_chan_io_dump(&ftdmchan->rxdump);
                        GOTO_STATUS(done, FTDM_SUCCESS);
@@ -2763,6 +2775,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
        case FTDM_COMMAND_ENABLE_OUTPUT_DUMP:
                {
                        ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
+                       if (ftdmchan->txdump.buffer) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Output dump is already enabled\n");
+                               GOTO_STATUS(done, FTDM_FAIL);
+                       }
                        if (start_chan_io_dump(ftdmchan, &ftdmchan->txdump, size)) {
                                ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump\n");  
                                GOTO_STATUS(done, FTDM_FAIL);
@@ -2775,6 +2791,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
        /*!< Stop dumping all output to a circular buffer. */
        case FTDM_COMMAND_DISABLE_OUTPUT_DUMP:
                {
+                       if (!ftdmchan->txdump.buffer) {
+                               ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable output dump\n");
+                               GOTO_STATUS(done, FTDM_SUCCESS);
+                       }
                        ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %zd\n", ftdmchan->rxdump.size);
                        stop_chan_io_dump(&ftdmchan->txdump);
                        GOTO_STATUS(done, FTDM_SUCCESS);
@@ -3349,12 +3369,13 @@ skipdebug:
 
 static FIO_WRITE_FUNCTION(ftdm_raw_write)
 {
+       int dlen = (int) *datalen;
        if (ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] > -1) {
-               int dlen = (int) *datalen;
                if ((write(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX], data, dlen)) != dlen) {
                        ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %zd bytes\n", dlen);
                }
        }
+       write_chan_io_dump(ftdmchan, &ftdmchan->txdump, data, dlen);
        return ftdmchan->fio->write(ftdmchan, data, datalen);
 }
 
index 5a36f05e8e5be4655821d5883c676fa1a323fdea..9ece0362450a1fb47f6af8943a320a1763ff3865 100644 (file)
@@ -68,6 +68,7 @@ typedef struct ftdm_r2_call_t {
        ftdm_channel_state_t chanstate;
        ftdm_size_t dnis_index;
        ftdm_size_t ani_index;
+       char logname[255];
        char name[10];
        unsigned long txdrops;
 } ftdm_r2_call_t;
@@ -88,13 +89,13 @@ typedef struct ft_r2_conf_s {
        int32_t max_dnis;
        int32_t mfback_timeout; 
        int32_t metering_pulse_timeout;
+       int32_t mf_dump_size;
 
        /* booleans */
        int immediate_accept;
        int skip_category;
        int get_ani_first;
        int call_files;
-       int mf_files;
        int double_answer;
        int charge_calls;
        int forced_release;
@@ -117,6 +118,8 @@ typedef struct ftdm_r2_data_s {
        int forced_release:1;
        /* whether accept the call when offered, or wait until the user decides to accept */
        int accept_on_offer:1;
+       /* Size of multi-frequency (or any media) dumps used during protocol errors */
+       int32_t mf_dump_size;
        /* max time spent in ms doing real work in a single loop */
        int32_t jobmax;
        /* Total number of loops performed so far */
@@ -125,6 +128,8 @@ typedef struct ftdm_r2_data_s {
        uint64_t loops[11];
        /* LWP */
        uint32_t monitor_thread_id;
+       /* Logging directory */
+       char logdir[512];
 } ftdm_r2_data_t;
 
 /* one element per span will be stored in g_mod_data_hash global var to keep track of them
@@ -409,10 +414,11 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
 }
 
 /* always called from the monitor thread */
-static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
+static void ftdm_r2_on_call_init(openr2_chan_t *r2chan, const char *logname)
 {
        ftdm_r2_call_t *r2call;
        ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+       ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
 
        ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n");
 
@@ -441,12 +447,16 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
        ft_r2_clean_call(ftdmchan->call_data);
        r2call = R2CALL(ftdmchan);
 
-       if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
-               R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
-       } else {
-               R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DIALING;
+       snprintf(r2call->logname, sizeof(r2call->logname), "%s", logname);
+       ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Set logname for call to %s\n", r2call->logname);
+
+       /* start io dump */
+       if (r2data->mf_dump_size) {
+               ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
+               ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
        }
 
+       R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
        ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
 }
 
@@ -484,6 +494,32 @@ static void clear_accept_pending(ftdm_channel_t *fchan)
        }
 }
 
+static void dump_mf(openr2_chan_t *r2chan)
+{
+       char dfile[512];
+       FILE *f = NULL;
+       ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+       ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
+       if (r2data->mf_dump_size) {
+               char *logname = R2CALL(ftdmchan)->logname;
+               
+               ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in prefix %s\n", logname);
+               snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.input.alaw" : "%s/s%dc%d.input.alaw", 
+                               logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
+               f = fopen(dfile, "w");
+               ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO input in file %s\n", dfile);
+               ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, f);
+               fclose(f);
+
+               snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.output.alaw" : "%s/s%dc%d.output.alaw", 
+                               logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
+               f = fopen(dfile, "w");
+               ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in file %s\n", dfile);
+               ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_OUTPUT, f);
+               fclose(f);
+       }
+}
+
 static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
 {
        ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
@@ -493,6 +529,7 @@ static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t m
 
        /* at this point the MF signaling has ended and there is no point on keep reading */
        openr2_chan_disable_read(r2chan);
+       
        R2CALL(ftdmchan)->accepted = 1;
 
        if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
@@ -579,7 +616,7 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
                return;
        }
 
-       ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n");
+       dump_mf(r2chan);
 
        clear_accept_pending(ftdmchan);
 
@@ -1042,24 +1079,28 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
                /* .variant */ OR2_VAR_ITU,
                /* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
                /* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING,
-               /* .logdir */ (char *)"/usr/local/freeswitch/log/", /* FIXME: get PREFIX variable */
+#ifdef WIN32
+               /* .logdir */ (char *)"c:\\", 
+#else
+               /* .logdir */ (char *)"/tmp", 
+#endif
                /* .advanced_protocol_file */ NULL,
                /* .max_ani */ 10,
                /* .max_dnis */ 4,
                /* .mfback_timeout */ -1,
                /* .metering_pulse_timeout */ -1,
+               /* .mf_dump_size */ 0,
                /* .immediate_accept */ -1,
                /* .skip_category */ -1,
                /* .get_ani_first */ -1,
                /* .call_files */ 0,
-               /* .mf_files */ 0,
                /* .double_answer */ -1,
                /* .charge_calls */ -1,
                /* .forced_release */ -1,
                /* .allow_collect_calls */ -1
        };
 
-       assert(sig_cb != NULL);
+       ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling cb provided\n");
 
        if (span->signal_type) {
                snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
@@ -1119,6 +1160,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
                                continue;
                        }
                        log_level = val;
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with loglevel %s\n", span->name, val);
                } else if (!strcasecmp(var, "advanced_protocol_file")) {
                        if (!val) {
                                break;
@@ -1128,46 +1170,51 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
                                continue;
                        }
                        r2conf.advanced_protocol_file = (char *)val;
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with advanced protocol file %s\n", span->name, val);
+               } else if (!strcasecmp(var, "mf_dump_size")) {
+                       r2conf.mf_dump_size = atoi(val);
+                       if (r2conf.mf_dump_size < 0) {
+                               r2conf.mf_dump_size = FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
+                               ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with default mf_dumps = %d bytes\n", span->name, r2conf.mf_dump_size);
+                       } else {
+                               ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with mf_dump_size = %d bytes\n", span->name, r2conf.mf_dump_size);
+                       }
                } else if (!strcasecmp(var, "allow_collect_calls")) {
                        r2conf.allow_collect_calls = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with allow collect calls max ani = %d\n", span->name, r2conf.allow_collect_calls);
                } else if (!strcasecmp(var, "double_answer")) {
                        r2conf.double_answer = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with double answer = %d\n", span->name, r2conf.double_answer);
                } else if (!strcasecmp(var, "immediate_accept")) {
                        r2conf.immediate_accept = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with immediate accept = %d\n", span->name, r2conf.immediate_accept);
                } else if (!strcasecmp(var, "skip_category")) {
                        r2conf.skip_category = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with skip category = %d\n", span->name, r2conf.skip_category);
                } else if (!strcasecmp(var, "forced_release")) {
                        r2conf.forced_release = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with forced release = %d\n", span->name, r2conf.forced_release);
                } else if (!strcasecmp(var, "charge_calls")) {
                        r2conf.charge_calls = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with charge calls = %d\n", span->name, r2conf.charge_calls);
                } else if (!strcasecmp(var, "get_ani_first")) {
                        r2conf.get_ani_first = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with get ani first = %d\n", span->name, r2conf.get_ani_first);
                } else if (!strcasecmp(var, "call_files")) {
                        r2conf.call_files = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
-               } else if (!strcasecmp(var, "mf_files")) {
-                       r2conf.mf_files = ftdm_true(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with mf files = %d\n", span->span_id, r2conf.mf_files);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with call files = %d\n", span->name, r2conf.call_files);
                } else if (!strcasecmp(var, "mfback_timeout")) {
                        r2conf.mfback_timeout = atoi(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with MF backward timeout = %dms\n", span->name, r2conf.mfback_timeout);
                } else if (!strcasecmp(var, "metering_pulse_timeout")) {
                        r2conf.metering_pulse_timeout = atoi(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with metering pulse timeout = %dms\n", span->name, r2conf.metering_pulse_timeout);
                } else if (!strcasecmp(var, "max_ani")) {
                        r2conf.max_ani = atoi(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max ani = %d\n", span->name, r2conf.max_ani);
                } else if (!strcasecmp(var, "max_dnis")) {
                        r2conf.max_dnis = atoi(val);
-                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis);
+                       ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max dnis = %d\n", span->name, r2conf.max_dnis);
                } else {
                        snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
                        return FTDM_FAIL;
@@ -1211,10 +1258,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
        openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
        openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
 
-       if (r2conf.logdir && r2conf.logdir[0]) {
-               ftdm_log(FTDM_LOG_DEBUG, "Setting openr2 for span %s logdir to %s\n", span->name, r2conf.logdir);
-               openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
-       }
+       ftdm_log(FTDM_LOG_DEBUG, "Setting span %s logdir to %s\n", span->name, r2conf.logdir);
+       openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
+       snprintf(r2data->logdir, sizeof(r2data->logdir), "%s", r2conf.logdir);
+
        if (r2conf.advanced_protocol_file) {
                openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
        }
@@ -1252,6 +1299,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
                hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
 
        }
+       r2data->mf_dump_size = r2conf.mf_dump_size;
        r2data->flags = 0;
        spanpvt->r2context = r2data->r2context;