From 9cf15ac04b6f47ced2e6be14690301f73bbb76e8 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Fri, 3 Dec 2010 16:50:03 -0500 Subject: [PATCH] freetdm: add MF dumping support to ftmod_r2 improve sample configuration documentation for MFC-R2 --- libs/freetdm/conf/freetdm.conf | 14 ++ libs/freetdm/conf/freetdm.conf.xml | 256 +++++++++++++++++---- libs/freetdm/src/ftdm_io.c | 33 ++- libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 108 ++++++--- 4 files changed, 331 insertions(+), 80 deletions(-) diff --git a/libs/freetdm/conf/freetdm.conf b/libs/freetdm/conf/freetdm.conf index bbaf1e3687..a657320448 100644 --- a/libs/freetdm/conf/freetdm.conf +++ b/libs/freetdm/conf/freetdm.conf @@ -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 + diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml index 986074dffb..63a3ea62cd 100644 --- a/libs/freetdm/conf/freetdm.conf.xml +++ b/libs/freetdm/conf/freetdm.conf.xml @@ -1,52 +1,220 @@ + - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index c43d694dee..d2ad2498a0 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -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); } diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 5a36f05e8e..9ece036245 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -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;