root/src/ftmod/ftmod_r2/ftmod_r2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gettimeofday
  2. strsep
  3. ftdm_r2_set_chan_sig_status
  4. ftdm_r2_cause_to_ftdm_cause
  5. ftdm_r2_ftdm_cause_to_openr2_cause
  6. ft_r2_clean_call
  7. ft_r2_accept_call
  8. ft_r2_answer_call
  9. ftdm_openr2_cpc_to_r2_ftdm_cpc
  10. ftdm_r2_ftdm_cpc_to_openr2_cpc
  11. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  12. ftdm_r2_start
  13. ftdm_r2_stop
  14. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  15. FIO_CHANNEL_SET_SIG_STATUS_FUNCTION
  16. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  17. FIO_SPAN_SET_SIG_STATUS_FUNCTION
  18. ftdm_r2_on_call_init
  19. ftdm_r2_on_call_offered
  20. clear_accept_pending
  21. dump_mf
  22. ftdm_r2_on_call_accepted
  23. ftdm_r2_on_call_answered
  24. ftdm_r2_on_call_disconnect
  25. ftdm_r2_on_call_end
  26. ftdm_r2_on_call_read
  27. ftdm_r2_on_hardware_alarm
  28. ftdm_r2_on_os_error
  29. ftdm_r2_recover_from_protocol_error
  30. ftdm_r2_on_protocol_error
  31. ftdm_r2_on_line_blocked
  32. ftdm_r2_on_line_idle
  33. ftdm_r2_write_log
  34. ftdm_r2_on_context_log
  35. ftdm_r2_on_chan_log
  36. ftdm_r2_on_dnis_digit_received
  37. ftdm_r2_on_ani_digit_received
  38. ftdm_r2_on_billing_pulse
  39. ftdm_r2_on_call_log_created
  40. ftdm_r2_on_call_proceed
  41. ftdm_r2_io_set_cas
  42. ftdm_r2_io_get_cas
  43. ftdm_r2_io_flush_write_buffers
  44. ftdm_r2_io_write
  45. ftdm_r2_io_read
  46. ftdm_r2_io_wait
  47. ftdm_r2_io_open
  48. ftdm_r2_io_close
  49. ftdm_r2_io_setup
  50. ftdm_r2_io_get_oob_event
  51. ftdm_r2_loglevel_from_string
  52. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
  53. ftdm_r2_state_advance
  54. ftdm_r2_run
  55. block_channel
  56. unblock_channel
  57. FIO_API_FUNCTION
  58. FIO_IO_LOAD_FUNCTION
  59. FIO_SIG_LOAD_FUNCTION
  60. FIO_SIG_UNLOAD_FUNCTION

   1 /*
   2  * Copyright (c) 2009, Moises Silva <moy@sangoma.com>
   3  * All rights reserved.
   4  * 
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 
   9  * * Redistributions of source code must retain the above copyright
  10  * notice, this list of conditions and the following disclaimer.
  11  * 
  12  * * Redistributions in binary form must reproduce the above copyright
  13  * notice, this list of conditions and the following disclaimer in the
  14  * documentation and/or other materials provided with the distribution.
  15  * 
  16  * * Neither the name of the original author; nor the names of any contributors
  17  * may be used to endorse or promote products derived from this software
  18  * without specific prior written permission.
  19  * 
  20  * 
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  *
  33  * Contributors: 
  34  *
  35  * Arnaldo Pereira <arnaldo@sangoma.com>
  36  * Ricardo BarroetaveƱa <rbarroetavena@anura.com.ar>
  37  *
  38  */
  39 
  40 #ifdef __linux__
  41 #ifndef _BSD_SOURCE
  42 #define _BSD_SOURCE /* for strsep() */
  43 #endif
  44 #include <syscall.h>
  45 #include <poll.h>
  46 #include <string.h>
  47 #endif
  48 #include <stdio.h>
  49 #include <openr2.h>
  50 #include "freetdm.h"
  51 #include "private/ftdm_core.h"
  52 
  53 /* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
  54  * knows it must stop, and we wait for FTDM_R2_RUNNING to be clear, which tells us the
  55  * signaling thread is done. */
  56 /* FIXME: what about the calls that are already up-and-running? */
  57 typedef enum {
  58         FTDM_R2_RUNNING = (1 << 0),
  59         FTDM_R2_SPAN_STARTED = (1 << 1),
  60 } ftdm_r2_flag_t;
  61 
  62 /* private call information stored in ftdmchan->call_data void* ptr,
  63  * remember that each time you add a new member to this structure
  64  * most likely you want to clear it in ft_r2_clean_call function
  65  * */
  66 #define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data))
  67 typedef struct ftdm_r2_call_t {
  68         openr2_chan_t *r2chan;
  69         int accepted:1;
  70         int answer_pending:1;
  71         int disconnect_rcvd:1;
  72         int protocol_error:1;
  73         ftdm_size_t dnis_index;
  74         ftdm_size_t ani_index;
  75         char logname[255];
  76         char name[10];
  77         ftdm_timer_id_t protocol_error_recovery_timer;
  78 } ftdm_r2_call_t;
  79 
  80 /* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
  81 typedef struct ft_r2_conf_s {
  82         /* openr2 types */
  83         openr2_variant_t variant;
  84         openr2_calling_party_category_t category;
  85         openr2_log_level_t loglevel;
  86 
  87         /* strings */
  88         char *logdir;
  89         char *advanced_protocol_file;
  90 
  91         /* ints */
  92         int32_t max_ani;
  93         int32_t max_dnis;
  94         int32_t mfback_timeout; 
  95         int32_t metering_pulse_timeout;
  96         ftdm_size_t mf_dump_size;
  97 
  98         /* booleans */
  99         int immediate_accept;
 100         int skip_category;
 101         int get_ani_first;
 102         int call_files;
 103         int double_answer;
 104         int charge_calls;
 105         int forced_release;
 106         int allow_collect_calls;
 107 } ft_r2_conf_t;
 108 
 109 /* r2 configuration stored in span->signal_data */
 110 typedef struct ftdm_r2_data_s {
 111         /* span flags */
 112         ftdm_r2_flag_t flags;
 113         /* openr2 handle for the R2 variant context */
 114         openr2_context_t *r2context;
 115         /* category to use when making calls */
 116         openr2_calling_party_category_t category;
 117         /* whether to use OR2_CALL_WITH_CHARGE or OR2_CALL_NO_CHARGE when accepting a call */
 118         int charge_calls:1;
 119         /* allow or reject collect calls */
 120         int allow_collect_calls:1;
 121         /* whether to use forced release when hanging up */
 122         int forced_release:1;
 123         /* whether accept the call when offered, or wait until the user decides to accept */
 124         int accept_on_offer:1;
 125         /* Size of multi-frequency (or any media) dumps used during protocol errors */
 126         ftdm_size_t mf_dump_size;
 127         /* max time spent in ms doing real work in a single loop */
 128         int32_t jobmax;
 129         /* Total number of loops performed so far */
 130         uint64_t total_loops;
 131         /* number of loops per 10ms increment from 0-9ms, 10-19ms .. 100ms and above */
 132         uint64_t loops[11];
 133         /* Total number of sleeps performed so far */
 134         uint64_t total_sleeps;
 135         /* number of sleeps per 10ms increment from 0-9ms, 10-19ms .. 100ms and above */
 136         uint64_t sleeps[11];
 137         /* max time spent in ms sleeping in a single loop */
 138         int32_t sleepmax;
 139         /* LWP */
 140         uint32_t monitor_thread_id;
 141         /* Logging directory */
 142         char logdir[512];
 143         /* scheduling context */
 144         ftdm_sched_t *sched;
 145 } ftdm_r2_data_t;
 146 
 147 /* one element per span will be stored in g_mod_data_hash global var to keep track of them
 148    and destroy them on module unload */
 149 typedef struct ftdm_r2_span_pvt_s {
 150         openr2_context_t *r2context; /* r2 context allocated for this span */
 151         ftdm_hash_t *r2calls; /* hash table of allocated call data per channel for this span */
 152         ftdm_sched_t *sched; /* schedule for the span */
 153 } ftdm_r2_span_pvt_t;
 154 
 155 /* span monitor thread */
 156 static void *ftdm_r2_run(ftdm_thread_t *me, void *obj);
 157 
 158 /* hash of all the private span allocations
 159    we need to keep track of them to destroy them when unloading the module 
 160    since freetdm does not notify signaling modules when destroying a span
 161    span -> ftdm_r2_mod_allocs_t */
 162 static ftdm_hash_t *g_mod_data_hash;
 163 
 164 /* IO interface for the command API */
 165 static ftdm_io_interface_t g_ftdm_r2_interface;
 166 
 167 static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
 168 
 169 /* whether R2 call accept process is pending */
 170 #define IS_ACCEPTING_PENDING(ftdmchan) \
 171                 ( (!ftdm_test_flag((ftdmchan), FTDM_CHANNEL_OUTBOUND)) && !R2CALL((ftdmchan))->accepted && \
 172                                 ((ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS || \
 173                                  (ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || \
 174                                  (ftdmchan)->state == FTDM_CHANNEL_STATE_UP) )
 175 
 176 /* functions not available on windows */
 177 #ifdef WIN32
 178 #include <mmsystem.h>
 179 
 180 static __inline int gettimeofday(struct timeval *tp, void *nothing)
 181 {
 182 #ifdef WITHOUT_MM_LIB
 183     SYSTEMTIME st;
 184     time_t tt;
 185     struct tm tmtm;
 186     /* mktime converts local to UTC */
 187     GetLocalTime (&st);
 188     tmtm.tm_sec = st.wSecond;
 189     tmtm.tm_min = st.wMinute;
 190     tmtm.tm_hour = st.wHour;
 191     tmtm.tm_mday = st.wDay;
 192     tmtm.tm_mon = st.wMonth - 1;
 193     tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
 194     tt = mktime (&tmtm);
 195     tp->tv_sec = tt;
 196     tp->tv_usec = st.wMilliseconds * 1000;
 197 #else
 198     /**
 199      ** The earlier time calculations using GetLocalTime
 200      ** had a time resolution of 10ms.The timeGetTime, part
 201      ** of multimedia apis offer a better time resolution
 202      ** of 1ms.Need to link against winmm.lib for this
 203      **/
 204     unsigned long Ticks = 0;
 205     unsigned long Sec =0;
 206     unsigned long Usec = 0;
 207     Ticks = timeGetTime();
 208 
 209     Sec = Ticks/1000;
 210     Usec = (Ticks - (Sec*1000))*1000;
 211     tp->tv_sec = Sec;
 212     tp->tv_usec = Usec;
 213 #endif /* WITHOUT_MM_LIB */
 214     (void)nothing;
 215     return 0;
 216 }
 217 
 218 static char *strsep(char **stringp, const char *delim)
 219 {
 220    char *start = *stringp;
 221    char *ptr;
 222 
 223    if (!start)
 224        return NULL;
 225 
 226    if (!*delim)
 227        ptr = start + strlen(start);
 228    else {
 229        ptr = strpbrk(start, delim);
 230        if (!ptr) {
 231            *stringp = NULL;
 232            return start;
 233        }
 234    }
 235 
 236    *ptr = '\0';
 237    *stringp = ptr + 1;
 238 
 239    return start;
 240 }
 241 #endif /* WIN32 */
 242 
 243 static void ftdm_r2_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
 244 {
 245         ftdm_sigmsg_t sig;
 246         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n", ftdm_signaling_status2str(status));
 247 
 248         memset(&sig, 0, sizeof(sig));
 249         sig.chan_id = ftdmchan->chan_id;
 250         sig.span_id = ftdmchan->span_id;
 251         sig.channel = ftdmchan;
 252         sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
 253         sig.ev_data.sigstatus.status = status;
 254         if (ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS) {
 255                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to change channel status to %s\n", ftdm_signaling_status2str(status));
 256         }
 257         return;
 258 }
 259 
 260 static ftdm_call_cause_t ftdm_r2_cause_to_ftdm_cause(ftdm_channel_t *fchan, openr2_call_disconnect_cause_t cause)
 261 {
 262         switch (cause) {
 263 
 264         case OR2_CAUSE_NORMAL_CLEARING:
 265                 return FTDM_CAUSE_NORMAL_CLEARING;
 266 
 267         case OR2_CAUSE_BUSY_NUMBER:
 268                 return FTDM_CAUSE_USER_BUSY;
 269 
 270         case OR2_CAUSE_NETWORK_CONGESTION:
 271                 return FTDM_CAUSE_SWITCH_CONGESTION;
 272 
 273         case OR2_CAUSE_UNALLOCATED_NUMBER:
 274                 return FTDM_CAUSE_NO_ROUTE_DESTINATION;
 275 
 276         case OR2_CAUSE_NUMBER_CHANGED:
 277                 return FTDM_CAUSE_NUMBER_CHANGED;
 278 
 279         case OR2_CAUSE_OUT_OF_ORDER:
 280                 return FTDM_CAUSE_NETWORK_OUT_OF_ORDER;
 281 
 282         case OR2_CAUSE_NO_ANSWER:
 283                 return FTDM_CAUSE_NO_ANSWER;
 284         
 285         case OR2_CAUSE_UNSPECIFIED:
 286                 return FTDM_CAUSE_NORMAL_UNSPECIFIED;
 287 
 288         case OR2_CAUSE_COLLECT_CALL_REJECTED:
 289                 return FTDM_CAUSE_CALL_REJECTED;
 290 
 291         case OR2_CAUSE_FORCED_RELEASE:
 292                 return FTDM_CAUSE_NORMAL_CLEARING;
 293 
 294         case OR2_CAUSE_GLARE:
 295                 return FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
 296         }
 297         ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Mapping openr2 cause %d to unspecified\n", cause);
 298         return FTDM_CAUSE_NORMAL_UNSPECIFIED;
 299 }
 300 
 301 static openr2_call_disconnect_cause_t ftdm_r2_ftdm_cause_to_openr2_cause(ftdm_channel_t *fchan)
 302 {
 303         switch (fchan->caller_data.hangup_cause) {
 304 
 305         case FTDM_CAUSE_NORMAL_CLEARING:
 306                 return OR2_CAUSE_NORMAL_CLEARING;
 307 
 308         case FTDM_CAUSE_USER_BUSY:
 309                 return OR2_CAUSE_BUSY_NUMBER;
 310 
 311         case FTDM_CAUSE_SWITCH_CONGESTION:
 312                 return OR2_CAUSE_NETWORK_CONGESTION;
 313 
 314         case FTDM_CAUSE_NO_ROUTE_DESTINATION:
 315                 return OR2_CAUSE_UNALLOCATED_NUMBER;
 316 
 317         case FTDM_CAUSE_NUMBER_CHANGED:
 318                 return OR2_CAUSE_NUMBER_CHANGED;
 319 
 320         case FTDM_CAUSE_NETWORK_OUT_OF_ORDER:
 321         case FTDM_CAUSE_SERVICE_UNAVAILABLE:
 322         case FTDM_CAUSE_PROTOCOL_ERROR:
 323                 return OR2_CAUSE_OUT_OF_ORDER;
 324 
 325         case FTDM_CAUSE_NO_ANSWER:
 326         case FTDM_CAUSE_NO_USER_RESPONSE:
 327                 return OR2_CAUSE_NO_ANSWER;
 328         
 329         case FTDM_CAUSE_NORMAL_UNSPECIFIED:
 330                 return OR2_CAUSE_UNSPECIFIED;
 331 
 332         case FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL:
 333                 return OR2_CAUSE_GLARE;
 334 
 335         }
 336         ftdm_log_chan(fchan, FTDM_LOG_WARNING, "freetdm hangup cause %d mapped to openr2 cause %s\n",
 337                         fchan->caller_data.hangup_cause, openr2_proto_get_disconnect_string(OR2_CAUSE_UNSPECIFIED));
 338         return OR2_CAUSE_UNSPECIFIED;
 339 }
 340 
 341 static void ft_r2_clean_call(ftdm_r2_call_t *call)
 342 {
 343         openr2_chan_t *r2chan = call->r2chan;
 344 
 345         /* Do not memset call structure, that clears values we do not want to clear, 
 346          * like the log name set in on_call_log_created() */
 347         call->r2chan = r2chan;
 348         call->accepted = 0;
 349         call->answer_pending = 0;
 350         call->disconnect_rcvd = 0;
 351         call->protocol_error = 0;
 352         call->dnis_index = 0;
 353         call->ani_index = 0;
 354         call->name[0] = 0;
 355         call->protocol_error_recovery_timer = 0;
 356 }
 357 
 358 static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
 359 {
 360         openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
 361         // FIXME: not always accept as no charge, let the user decide that
 362         // also we should check the return code from openr2_chan_accept_call and handle error condition
 363         // hanging up the call with protocol error as the reason, this openr2 API will fail only when there something
 364         // wrong at the I/O layer or the library itself
 365         openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
 366 }
 367 
 368 static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
 369 {
 370         openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
 371         // FIXME
 372         // 1. check openr2_chan_answer_call return code
 373         // 2. The openr2_chan_answer_call_with_mode should be used depending on user settings
 374         // openr2_chan_answer_call_with_mode(r2chan, OR2_ANSWER_SIMPLE);
 375         openr2_chan_answer_call(r2chan);
 376         R2CALL(ftdmchan)->answer_pending = 0;
 377 }
 378 
 379 static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc)
 380 {
 381         switch (cpc) {
 382         case OR2_CALLING_PARTY_CATEGORY_UNKNOWN:
 383                 return FTDM_CPC_UNKNOWN;
 384 
 385         case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER:
 386                 return FTDM_CPC_ORDINARY;
 387 
 388         case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER:
 389                 return FTDM_CPC_PRIORITY;
 390 
 391         case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER:
 392                 return FTDM_CPC_UNKNOWN;
 393 
 394         case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER:
 395                 return FTDM_CPC_UNKNOWN;
 396 
 397         case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT:
 398                 return FTDM_CPC_TEST;
 399 
 400         case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE:
 401                 return FTDM_CPC_PAYPHONE;
 402 
 403         case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL:
 404                 return FTDM_CPC_OPERATOR;
 405         }
 406         return FTDM_CPC_INVALID;
 407 }
 408 
 409 static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc)
 410 {
 411         switch (cpc) {
 412         case FTDM_CPC_UNKNOWN:
 413                 return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
 414 
 415         case FTDM_CPC_OPERATOR:
 416                 return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL;
 417 
 418         case FTDM_CPC_ORDINARY:
 419                 return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
 420 
 421         case FTDM_CPC_PRIORITY:
 422                 return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER;
 423 
 424         case FTDM_CPC_DATA:
 425                 return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
 426 
 427         case FTDM_CPC_TEST:
 428                 return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT;
 429 
 430         case FTDM_CPC_PAYPHONE:
 431                 return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE;
 432 
 433         case FTDM_CPC_INVALID:
 434                 return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
 435         }
 436         return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
 437 }
 438 
 439 /* this function must be called with the chan mutex held! */
 440 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
 441 {
 442         int ret;
 443         ftdm_r2_data_t *r2data;
 444         openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
 445 
 446         r2data = ftdmchan->span->signal_data;
 447 
 448         ft_r2_clean_call(ftdmchan->call_data);
 449 
 450         if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) {
 451                 category = r2data->category;
 452         } else {
 453                 category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc);
 454         }
 455 
 456         /* start io dump */
 457         if (r2data->mf_dump_size) {
 458                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
 459                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
 460         }
 461 
 462         ret = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan, 
 463                         ftdmchan->caller_data.cid_num.digits,
 464                         ftdmchan->caller_data.dnis.digits, 
 465                         category,
 466                         ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? 0 : 1);
 467 
 468         if (ret) {
 469                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
 470                 return FTDM_FAIL;
 471         }
 472 
 473         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
 474 
 475         ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
 476         ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
 477         ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_RX_BUFFERS, NULL);
 478 
 479         return FTDM_SUCCESS;
 480 }
 481 
 482 static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
 483 {
 484         ftdm_r2_data_t *r2_data = span->signal_data;
 485         ftdm_set_flag(r2_data, FTDM_R2_SPAN_STARTED);
 486         return ftdm_thread_create_detached(ftdm_r2_run, span);
 487 }
 488 
 489 static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
 490 {
 491         ftdm_r2_data_t *r2_data = span->signal_data;
 492         ftdm_clear_flag(r2_data, FTDM_R2_SPAN_STARTED);
 493         while (ftdm_test_flag(r2_data, FTDM_R2_RUNNING)) {
 494                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for R2 span %s\n", span->name);
 495                 ftdm_sleep(100);
 496         }
 497         return FTDM_SUCCESS;
 498 }
 499 
 500 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
 501 {
 502         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
 503                 *status = FTDM_SIG_STATE_UP;
 504         } else {
 505                 *status = FTDM_SIG_STATE_DOWN;
 506         }
 507 
 508         return FTDM_SUCCESS;
 509 }
 510 
 511 static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status)
 512 {
 513         openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
 514         openr2_cas_signal_t rxcas, txcas;
 515 
 516         /* get the current rx and tx cas bits */
 517         openr2_chan_get_cas(r2chan, &rxcas, &txcas);
 518 
 519         /* if we're already in the state the user asks us to be, we have nothing to do */
 520         if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) {
 521                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n");
 522                 return FTDM_SUCCESS;
 523         }
 524         if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) {
 525                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n");
 526                 return FTDM_SUCCESS;
 527         }
 528 
 529         /* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable.
 530          * see docs/sigstatus.txt for details */
 531         switch(status) {
 532                 case FTDM_SIG_STATE_SUSPENDED:
 533                         openr2_chan_set_blocked(r2chan);
 534                         if (rxcas == OR2_CAS_IDLE) {
 535                                 ftdm_r2_set_chan_sig_status(ftdmchan, status);
 536                         }
 537                         break;
 538                 case FTDM_SIG_STATE_UP:
 539                         openr2_chan_set_idle(r2chan);
 540                         if (rxcas == OR2_CAS_IDLE) {
 541                                 ftdm_r2_set_chan_sig_status(ftdmchan, status);
 542                         }
 543                         break;
 544                 default:
 545                         ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
 546                         return FTDM_FAIL;
 547         }
 548         return FTDM_SUCCESS;
 549 }
 550 
 551 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
 552 {
 553         ftdm_iterator_t *citer = NULL;
 554         ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL);
 555         if (!chaniter) {
 556                 ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
 557                 return FTDM_FAIL;
 558         }
 559         /* if ALL channels are non-idle, report SUSPENDED. UP otherwise. */
 560         *status = FTDM_SIG_STATE_SUSPENDED;
 561         for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
 562                 ftdm_channel_t *fchan = ftdm_iterator_current(citer);
 563                 ftdm_channel_lock(fchan);
 564                 if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) {
 565                         *status = FTDM_SIG_STATE_UP;
 566                         ftdm_channel_unlock(fchan);
 567                         break;
 568                 }
 569                 ftdm_channel_unlock(fchan);
 570         }
 571         ftdm_iterator_free(chaniter);
 572         return FTDM_SUCCESS;
 573 }
 574 
 575 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
 576 {
 577         ftdm_iterator_t *chaniter = NULL;
 578         ftdm_iterator_t *citer = NULL;
 579 
 580         chaniter = ftdm_span_get_chan_iterator(span, NULL);
 581         if (!chaniter) {
 582                 ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
 583                 return FTDM_FAIL;
 584         }
 585         /* iterate over all channels, setting them to the requested state */
 586         for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
 587                 ftdm_channel_t *fchan = ftdm_iterator_current(citer);
 588                 /* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes
 589                  * care of notifying the user when appropriate */
 590                 ftdm_channel_lock(fchan);
 591                 if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) {
 592                         ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status));
 593                 }
 594                 ftdm_channel_unlock(fchan);
 595         }
 596         ftdm_iterator_free(chaniter);
 597         return FTDM_SUCCESS;
 598 }
 599 
 600 /* always called from the monitor thread */
 601 static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
 602 {
 603         ftdm_r2_call_t *r2call;
 604         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 605         ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
 606 
 607         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n");
 608 
 609         if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
 610                 r2call = R2CALL(ftdmchan);
 611                 if (r2call->protocol_error) {
 612                         /* we had a protocol error and we were giving some recovery time, cancel the recovery timer now
 613                          * that is obvious that the other side recovered */
 614                         ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer);
 615                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n");
 616                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 617                         ftdm_channel_advance_states(ftdmchan);
 618                 }
 619         }
 620 
 621         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
 622                 ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state));
 623                 return;
 624         }
 625 
 626         if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
 627                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot handle request to start call in state %s\n", ftdm_channel_state2str(ftdmchan->state));
 628                 return;
 629         }
 630 
 631         if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
 632                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open channel during incoming call! [%s]\n", ftdmchan->last_error);
 633                 return;
 634         }
 635 
 636         /* mark the channel in use (so no outgoing calls can be placed here) */
 637         ftdm_channel_use(ftdmchan);     
 638 
 639         memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected));
 640         memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected));
 641 
 642         ft_r2_clean_call(ftdmchan->call_data);
 643         r2call = R2CALL(ftdmchan);
 644 
 645         /* start io dump */
 646         if (r2data->mf_dump_size) {
 647                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
 648                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
 649         }
 650 
 651         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
 652         ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
 653         ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
 654         ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_RX_BUFFERS, NULL);
 655 }
 656 
 657 static void dump_mf(openr2_chan_t *r2chan);
 658 /* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
 659 static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, 
 660                 openr2_calling_party_category_t category, int ani_restricted)
 661 {
 662         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 663         ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
 664 
 665         ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = %d, ANI restricted = %s\n", 
 666                         ani, dnis, category, ani_restricted ? "Yes" : "No");
 667 
 668         /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
 669         if (r2data->mf_dump_size) {
 670                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
 671                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
 672         }
 673 
 674         /* check if this is a collect call and if we should accept it */
 675         if (!r2data->allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
 676                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Rejecting collect call\n");
 677                 openr2_chan_disconnect_call(r2chan, OR2_CAUSE_COLLECT_CALL_REJECTED);
 678         } else {
 679                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
 680         }
 681         ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category);
 682         ftdmchan->caller_data.pres = ani_restricted ? FTDM_PRES_RESTRICTED : FTDM_PRES_ALLOWED;
 683 }
 684 
 685 /*
 686  * Accepting a call in R2 is a lengthy process due to MF tones,
 687  * when the user sends PROGRESS indication (implicitly moving the
 688  * ftdm channel to PROGRESS state) the R2 processing loop
 689  * does not clear FTDM_CHANNEL_STATE_CHANGE immediately as it does
 690  * for all the other states, instead has to wait for on_call_accepted
 691  * callback from openr2, which means the MF has ended and the progress
 692  * indication is done, in order to clear the flag. However, if
 693  * a protocol error or call disconnection (which is indicated using CAS bits)
 694  * occurrs while accepting, we must clear the pending flag, this function
 695  * takes care of that
 696  * */
 697 static void clear_accept_pending(ftdm_channel_t *fchan)
 698 {
 699         if (IS_ACCEPTING_PENDING(fchan)) {
 700                 ftdm_channel_complete_state(fchan);
 701         } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
 702                 ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n", 
 703                                 ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
 704                 ftdm_channel_complete_state(fchan);
 705         }
 706 }
 707 
 708 static void dump_mf(openr2_chan_t *r2chan)
 709 {
 710         char dfile[512];
 711         FILE *f = NULL;
 712         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 713         ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
 714         if (r2data->mf_dump_size) {
 715                 char *logname = R2CALL(ftdmchan)->logname;
 716                 
 717                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in prefix %s\n", logname);
 718                 snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.input.alaw" : "%s/s%dc%d.input.alaw", 
 719                                 logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
 720                 f = fopen(dfile, "wb");
 721                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO input in file %s\n", dfile);
 722                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, f);
 723                 fclose(f);
 724 
 725                 snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.output.alaw" : "%s/s%dc%d.output.alaw", 
 726                                 logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
 727                 f = fopen(dfile, "wb");
 728                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in file %s\n", dfile);
 729                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_OUTPUT, f);
 730                 fclose(f);
 731         }
 732 }
 733 
 734 static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
 735 {
 736         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 737         ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
 738 
 739         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n");
 740 
 741         clear_accept_pending(ftdmchan);
 742 
 743         /* at this point the MF signaling has ended and there is no point on keep reading */
 744         openr2_chan_disable_read(r2chan);
 745 
 746         /* at this point we are no longer responsible for reading and writing, 
 747          * we are not interested in the stats anymore */
 748         ftdm_channel_clear_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
 749 
 750         
 751         R2CALL(ftdmchan)->accepted = 1;
 752 
 753         if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
 754                 if (R2CALL(ftdmchan)->answer_pending) {
 755                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n");
 756                         ft_r2_answer_call(ftdmchan);
 757                         R2CALL(ftdmchan)->answer_pending = 0;
 758                         return;
 759                 }
 760         } else {
 761                 /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
 762                 if (r2data->mf_dump_size) {
 763                         ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
 764                         ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
 765                 }
 766                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
 767         }
 768 }
 769 
 770 static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan)
 771 {
 772         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 773         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call answered\n");
 774         /* notify the upper layer of progress in the outbound call */
 775         if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
 776                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
 777         }
 778 }
 779 
 780 /* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */
 781 static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
 782 {
 783         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 784 
 785         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call disconnected\n");
 786 
 787         clear_accept_pending(ftdmchan);
 788 
 789         R2CALL(ftdmchan)->disconnect_rcvd = 1;
 790 
 791         if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
 792                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call had been disconnected already by the user\n");
 793                 /* just ack the hangup to trigger the on_call_end callback and go down */
 794                 openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
 795                 return;
 796         }
 797 
 798         ftdmchan->caller_data.hangup_cause  = ftdm_r2_cause_to_ftdm_cause(ftdmchan, cause);
 799         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
 800 }
 801 
 802 static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
 803 {
 804         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 805         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call finished\n");
 806 
 807         /* the call is done as far as the stack is concerned, lets move to down here */
 808         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 809 
 810         /* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */
 811         ftdm_channel_advance_states(ftdmchan);
 812 }
 813 
 814 static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
 815 {
 816 #if 0
 817         ftdm_log(FTDM_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan));
 818 #endif
 819 }
 820 
 821 static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
 822 {
 823         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 824         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Alarm notification: %d\n", alarm);
 825 }
 826 
 827 static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
 828 {
 829         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 830         ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "OS error: %s\n", strerror(errorcode));
 831 }
 832 
 833 static void ftdm_r2_recover_from_protocol_error(void *data)
 834 {
 835         openr2_chan_t *r2chan = data;
 836         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 837         ftdm_channel_lock(ftdmchan);
 838         if (ftdmchan->state != FTDM_CHANNEL_STATE_HANGUP) {
 839                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Recovering from protocol error but state is %s!\n", ftdm_channel_state2str(ftdmchan->state));
 840                 goto done;
 841         }
 842         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 843         ftdm_channel_advance_states(ftdmchan);
 844 done:
 845         ftdm_channel_unlock(ftdmchan);
 846 }
 847 
 848 static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
 849 {
 850         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 851 
 852         if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
 853                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Got protocol error when we're already down!\n");
 854                 return;
 855         }
 856 
 857         dump_mf(r2chan);
 858 
 859         clear_accept_pending(ftdmchan);
 860 
 861         R2CALL(ftdmchan)->disconnect_rcvd = 1;
 862         R2CALL(ftdmchan)->protocol_error = 1;
 863 
 864         if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
 865                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "The user already hung up, finishing call in protocol error\n");
 866                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 867                 return;
 868         }
 869 
 870         ftdmchan->caller_data.hangup_cause  = FTDM_CAUSE_PROTOCOL_ERROR; 
 871         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
 872 }
 873 
 874 static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
 875 {
 876         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 877         ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end blocked in state %s\n", ftdm_channel_state2str(ftdmchan->state));
 878         ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED);
 879 }
 880 
 881 static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan)
 882 {
 883         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 884         ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end unblocked in state %s\n", ftdm_channel_state2str(ftdmchan->state));
 885         ftdm_r2_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP);
 886 }
 887 
 888 static void ftdm_r2_write_log(openr2_log_level_t level, const char *file, const char *function, int line, const char *message)
 889 {
 890         switch (level) {
 891                 case OR2_LOG_NOTICE:
 892                         ftdm_log(file, function, line, FTDM_LOG_LEVEL_NOTICE, "%s", message);
 893                         break;
 894                 case OR2_LOG_WARNING:
 895                         ftdm_log(file, function, line, FTDM_LOG_LEVEL_WARNING, "%s", message);
 896                         break;
 897                 case OR2_LOG_ERROR:
 898                         ftdm_log(file, function, line, FTDM_LOG_LEVEL_ERROR, "%s", message);
 899                         break;
 900                 case OR2_LOG_STACK_TRACE:
 901                 case OR2_LOG_MF_TRACE:
 902                 case OR2_LOG_CAS_TRACE:
 903                 case OR2_LOG_DEBUG:
 904                 case OR2_LOG_EX_DEBUG:
 905                         ftdm_log(file, function, line, FTDM_LOG_LEVEL_DEBUG, "%s", message);
 906                         break;
 907                 default:
 908                         ftdm_log(FTDM_LOG_WARNING, "We should handle logging level %d here.\n", level);
 909                         ftdm_log(file, function, line, FTDM_LOG_LEVEL_DEBUG, "%s", message);
 910                         break;
 911         }
 912 }
 913 
 914 static void ftdm_r2_on_context_log(openr2_context_t *r2context, const char *file, const char *function, unsigned int line, 
 915         openr2_log_level_t level, const char *fmt, va_list ap)
 916 {
 917 #define CONTEXT_TAG "Context -"
 918         char logmsg[256];
 919         char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
 920         vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
 921         snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
 922         ftdm_r2_write_log(level, file, function, line, completemsg);
 923 #undef CONTEXT_TAG
 924 }
 925 
 926 static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, const char *file, const char *function, unsigned int line, 
 927         openr2_log_level_t level, const char *fmt, va_list ap)
 928 {
 929         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 930         char logmsg[1024];
 931         char completemsg[sizeof(logmsg)];
 932         vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
 933         snprintf(completemsg, sizeof(completemsg), "[s%dc%d] [%d:%d] [%s] %s", 
 934                         ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->physical_span_id, ftdmchan->physical_chan_id,
 935                         ftdm_channel_state2str(ftdmchan->state), logmsg);
 936         ftdm_r2_write_log(level, file, function, line, completemsg);
 937 }
 938 
 939 static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
 940 {
 941         ftdm_sigmsg_t sigev;
 942         ftdm_r2_data_t *r2data;
 943         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 944         ftdm_size_t collected_len = R2CALL(ftdmchan)->dnis_index;
 945 
 946         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "DNIS digit %c received\n", digit);
 947 
 948         /* save the digit we just received */ 
 949         ftdmchan->caller_data.dnis.digits[collected_len] = digit;
 950         collected_len++;
 951         ftdmchan->caller_data.dnis.digits[collected_len] = '\0';
 952         R2CALL(ftdmchan)->dnis_index = collected_len;
 953 
 954         /* notify the user about the new digit and check if we should stop requesting more DNIS */
 955         memset(&sigev, 0, sizeof(sigev));
 956         sigev.chan_id = ftdmchan->chan_id;
 957         sigev.span_id = ftdmchan->span_id;
 958         sigev.channel = ftdmchan;
 959         sigev.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
 960         r2data = ftdmchan->span->signal_data;
 961         if (ftdm_span_send_signal(ftdmchan->span, &sigev) == FTDM_BREAK) {
 962                 ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits);
 963                 return OR2_STOP_DNIS_REQUEST; 
 964         }
 965 
 966         /* the only other reason to stop requesting DNIS is that there is no more room to save it */
 967         if (collected_len == (sizeof(ftdmchan->caller_data.dnis.digits) - 1)) {
 968                 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "No more room for DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits);
 969                 return OR2_STOP_DNIS_REQUEST;
 970         }
 971 
 972         return OR2_CONTINUE_DNIS_REQUEST; 
 973 }
 974 
 975 static void ftdm_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
 976 {
 977         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 978         ftdm_size_t collected_len = R2CALL(ftdmchan)->ani_index;
 979 
 980         /* check if we should drop ANI */
 981         if (collected_len == (sizeof(ftdmchan->caller_data.ani.digits) - 1)) {
 982                 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "No more room for ANI, digit dropped: %c\n", digit);
 983                 return;
 984         }
 985         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ANI digit %c received\n", digit);
 986 
 987         /* save the digit we just received */ 
 988         ftdmchan->caller_data.ani.digits[collected_len] = digit;
 989         collected_len++;
 990         ftdmchan->caller_data.ani.digits[collected_len] = '\0';
 991         R2CALL(ftdmchan)->ani_index = collected_len;
 992 }
 993 
 994 static void ftdm_r2_on_billing_pulse(openr2_chan_t *r2chan) {}
 995 
 996 static void ftdm_r2_on_call_log_created(openr2_chan_t *r2chan, const char *logname)
 997 {
 998         ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
 999         ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
1000         /* this is used when dumping I/O for debugging */
1001         snprintf(r2call->logname, sizeof(r2call->logname), "%s", logname);
1002 }
1003 
1004 static void ftdm_r2_on_call_proceed(openr2_chan_t *r2chan)
1005 {
1006         ftdm_sigmsg_t sigev;
1007         ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan);
1008         memset(&sigev, 0, sizeof(sigev));
1009         sigev.event_id = FTDM_SIGEVENT_PROCEED;
1010         sigev.channel = fchan;
1011         ftdm_span_send_signal(fchan->span, &sigev);
1012 }
1013 
1014 static openr2_event_interface_t ftdm_r2_event_iface = {
1015         /* .on_call_init */ ftdm_r2_on_call_init,
1016         /* .on_call_proceed */ ftdm_r2_on_call_proceed,
1017         /* .on_call_offered */ ftdm_r2_on_call_offered,
1018         /* .on_call_accepted */ ftdm_r2_on_call_accepted,
1019         /* .on_call_answered */ ftdm_r2_on_call_answered,
1020         /* .on_call_disconnect */ ftdm_r2_on_call_disconnect,
1021         /* .on_call_end */ ftdm_r2_on_call_end,
1022         /* .on_call_read */ ftdm_r2_on_call_read,
1023         /* .on_hardware_alarm */ ftdm_r2_on_hardware_alarm,
1024         /* .on_os_error */ ftdm_r2_on_os_error,
1025         /* .on_protocol_error */ ftdm_r2_on_protocol_error,
1026         /* .on_line_blocked */ ftdm_r2_on_line_blocked,
1027         /* .on_line_idle */ ftdm_r2_on_line_idle,
1028 
1029         /* cast seems to be needed to get rid of the annoying warning regarding format attribute  */
1030         /* .on_context_log */ (openr2_handle_context_logging_func)ftdm_r2_on_context_log,
1031         /* .on_dnis_digit_received */ ftdm_r2_on_dnis_digit_received,
1032         /* .on_ani_digit_received */ ftdm_r2_on_ani_digit_received,
1033 
1034         /* so far we do nothing with billing pulses */
1035         /* .on_billing_pulse_received */ ftdm_r2_on_billing_pulse,
1036         /* .on_call_log_created */ ftdm_r2_on_call_log_created,
1037 };
1038 
1039 static int ftdm_r2_io_set_cas(openr2_chan_t *r2chan, int cas)
1040 {
1041         ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
1042         ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_SET_CAS_BITS, &cas);
1043         if (FTDM_FAIL == status) {
1044                 return -1;
1045         }
1046         return 0;
1047 }
1048 
1049 static int ftdm_r2_io_get_cas(openr2_chan_t *r2chan, int *cas)
1050 {
1051         ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
1052         ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_GET_CAS_BITS, cas);
1053         if (FTDM_FAIL == status) {
1054                 return -1;
1055         }
1056         return 0;
1057 }
1058 
1059 static int ftdm_r2_io_flush_write_buffers(openr2_chan_t *r2chan)
1060 {
1061         ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
1062         ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
1063         if (FTDM_FAIL == status) {
1064                 return -1;
1065         }
1066         return 0;
1067 }
1068 
1069 static int ftdm_r2_io_write(openr2_chan_t *r2chan, const void *buf, int size)
1070 {
1071         ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
1072         ftdm_size_t outsize = size;
1073         ftdm_status_t status = ftdm_channel_write(ftdm_chan, (void *)buf, size, &outsize);
1074         if (FTDM_FAIL == status) {
1075                 return -1;
1076         }
1077         return (int)outsize;
1078 }
1079 
1080 static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size)
1081 {
1082         ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
1083         ftdm_size_t outsize = size;
1084         ftdm_status_t status = ftdm_channel_read(ftdm_chan, (void *)buf, &outsize);
1085         if (FTDM_FAIL == status) {
1086                 return -1;
1087         }
1088         return (int)outsize;
1089 }
1090 
1091 static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
1092 {
1093         ftdm_status_t status;
1094         int32_t timeout;
1095         ftdm_wait_flag_t ftdmflags = 0;
1096 
1097         ftdm_channel_t *fchan = openr2_chan_get_fd(r2chan);
1098         timeout = block ? -1 : 0;
1099 
1100         if (*flags & OR2_IO_READ) {
1101                 ftdmflags |= FTDM_READ;
1102         }
1103         if (*flags & OR2_IO_WRITE) {
1104                 ftdmflags |= FTDM_WRITE;
1105         }
1106         if (*flags & OR2_IO_OOB_EVENT) {
1107                 ftdmflags |= FTDM_EVENTS;
1108         }
1109         
1110         status = ftdm_channel_wait(fchan, &ftdmflags, timeout);
1111 
1112         if (FTDM_SUCCESS != status && FTDM_TIMEOUT != status) {
1113                 ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to wait for events on channel\n");
1114                 return -1;
1115         }
1116 
1117         *flags = 0;
1118         if (ftdmflags & FTDM_READ) {
1119                 *flags |= OR2_IO_READ;
1120         }
1121         if (ftdmflags & FTDM_WRITE) {
1122                 *flags |= OR2_IO_WRITE;
1123         }
1124         if (ftdmflags & FTDM_EVENTS) {
1125                 *flags |= OR2_IO_OOB_EVENT;
1126         }
1127 
1128         return 0;
1129 }
1130 
1131 /* The following openr2 hooks never get called, read on for reasoning ... */
1132 /* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
1133 static openr2_io_fd_t ftdm_r2_io_open(openr2_context_t *r2context, int channo)
1134 {
1135         ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O open)!!\n");
1136         return NULL;
1137 }
1138 
1139 /* since freetdm takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */
1140 static int ftdm_r2_io_close(openr2_chan_t *r2chan)
1141 {
1142         ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan);
1143         ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n");
1144         return 0;
1145 }
1146 
1147 /* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
1148 static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
1149 {
1150         ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan);
1151         ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
1152         return 0;
1153 }
1154 
1155 static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
1156 {
1157         ftdm_status_t status;
1158         ftdm_event_t *fevent = NULL;
1159         ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
1160 
1161         *event = OR2_OOB_EVENT_NONE;
1162 
1163         status = ftdm_channel_read_event(ftdmchan, &fevent);
1164 
1165         if (status != FTDM_SUCCESS) {
1166                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n");
1167                 return -1;
1168         }
1169 
1170         if (fevent->e_type != FTDM_EVENT_OOB) {
1171                 return 0;
1172         }
1173 
1174         switch (fevent->enum_id) {
1175         case FTDM_OOB_CAS_BITS_CHANGE:
1176                 {
1177                         *event = OR2_OOB_EVENT_CAS_CHANGE;
1178                 }
1179                 break;
1180         case FTDM_OOB_ALARM_TRAP:
1181                 {
1182                         *event = OR2_OOB_EVENT_ALARM_ON;
1183                 }
1184                 break;
1185         case FTDM_OOB_ALARM_CLEAR:
1186                 {
1187                         *event = OR2_OOB_EVENT_ALARM_OFF;
1188                 }
1189                 break;
1190         }
1191         return 0;
1192 }
1193 
1194 static openr2_io_interface_t ftdm_r2_io_iface = {
1195         /* .open */ ftdm_r2_io_open, /* never called */
1196         /* .close */ ftdm_r2_io_close, /* never called */
1197         /* .set_cas */ ftdm_r2_io_set_cas,
1198         /* .get_cas */ ftdm_r2_io_get_cas,
1199         /* .flush_write_buffers */ ftdm_r2_io_flush_write_buffers,
1200         /* .write */ ftdm_r2_io_write,
1201         /* .read */ ftdm_r2_io_read,
1202         /* .setup */ ftdm_r2_io_setup, /* never called */
1203         /* .wait */ ftdm_r2_io_wait,
1204         /* .get_oob_event */ ftdm_r2_io_get_oob_event /* never called */
1205 };
1206 
1207 /* resolve a loglevel string, such as "debug,notice,warning",  to an openr2 log level integer */
1208 static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level)
1209 {
1210         openr2_log_level_t tmplevel;
1211         openr2_log_level_t newlevel = 0;
1212         char *clevel = NULL;
1213         char *logval = NULL;
1214 
1215         logval = ftdm_malloc(strlen(level)+1); /* alloca man page scared me, so better to use good ol' malloc  */
1216         if (!logval) {
1217                 ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", level);
1218                 return newlevel;
1219         }
1220         strcpy(logval, level);
1221         while (logval) {
1222                 clevel = strsep(&logval, ",");
1223                 if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
1224                         ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
1225                         continue;
1226                 }
1227                 newlevel |= tmplevel;
1228         }
1229         ftdm_safe_free(logval);
1230         return newlevel;
1231 }
1232 
1233 static ftdm_state_map_t r2_state_map = {
1234         {
1235                 {
1236                         ZSD_INBOUND,
1237                         ZSM_UNACCEPTABLE,
1238                         {FTDM_ANY_STATE, FTDM_END},
1239                         {FTDM_CHANNEL_STATE_RESET, FTDM_END}
1240                 },
1241                 {
1242                         ZSD_INBOUND,
1243                         ZSM_UNACCEPTABLE,
1244                         {FTDM_CHANNEL_STATE_RESET, FTDM_END},
1245                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
1246                 },
1247                 {
1248                         ZSD_INBOUND,
1249                         ZSM_UNACCEPTABLE,
1250                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
1251                         {FTDM_CHANNEL_STATE_COLLECT, FTDM_END}
1252                 },
1253                 {
1254                         ZSD_INBOUND,
1255                         ZSM_UNACCEPTABLE,
1256                         {FTDM_CHANNEL_STATE_COLLECT, FTDM_END},
1257                         {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
1258                 },
1259                 {
1260                         ZSD_INBOUND,
1261                         ZSM_UNACCEPTABLE,
1262                         {FTDM_CHANNEL_STATE_RING, FTDM_END},
1263                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
1264                 },
1265                 {
1266                         ZSD_INBOUND,
1267                         ZSM_UNACCEPTABLE,
1268                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
1269                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
1270                 },
1271                 {
1272                         ZSD_INBOUND,
1273                         ZSM_UNACCEPTABLE,
1274                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
1275                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
1276                 },
1277                 {
1278                         ZSD_INBOUND,
1279                         ZSM_UNACCEPTABLE,
1280                         {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
1281                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
1282                 },
1283                 {
1284                         ZSD_INBOUND,
1285                         ZSM_UNACCEPTABLE,
1286                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
1287                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END},
1288                 },
1289                 {
1290                         ZSD_INBOUND,
1291                         ZSM_UNACCEPTABLE,
1292                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
1293                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
1294                 },
1295                 
1296                 /* Outbound states */
1297                 
1298                 {
1299                         ZSD_OUTBOUND,
1300                         ZSM_UNACCEPTABLE,
1301                         {FTDM_ANY_STATE, FTDM_END},
1302                         {FTDM_CHANNEL_STATE_RESET, FTDM_END}
1303                 },
1304 
1305                 {
1306                         ZSD_OUTBOUND,
1307                         ZSM_UNACCEPTABLE,
1308                         {FTDM_CHANNEL_STATE_RESET, FTDM_END},
1309                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
1310                 },
1311 
1312                 {
1313                         ZSD_OUTBOUND,
1314                         ZSM_UNACCEPTABLE,
1315                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
1316                         {FTDM_CHANNEL_STATE_DIALING, FTDM_END}
1317                 },
1318 
1319                 {
1320                         ZSD_OUTBOUND,
1321                         ZSM_UNACCEPTABLE,
1322                         {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
1323                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}
1324                 },
1325 
1326                 {
1327                         ZSD_OUTBOUND,
1328                         ZSM_UNACCEPTABLE,
1329                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
1330                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
1331                 },
1332 
1333                 {
1334                         ZSD_OUTBOUND,
1335                         ZSM_UNACCEPTABLE,
1336                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
1337                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
1338                 },
1339 
1340                 {
1341                         ZSD_OUTBOUND,
1342                         ZSM_UNACCEPTABLE,
1343                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
1344                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
1345                 },
1346 
1347                 {
1348                         ZSD_OUTBOUND,
1349                         ZSM_UNACCEPTABLE,
1350                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
1351                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
1352                 },
1353         }
1354 };
1355 
1356 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
1357 {
1358         unsigned int i = 0;
1359         int conf_failure = 0;
1360         int intval = 0;
1361         char schedname[255];
1362         const char *var = NULL, *val = NULL;
1363         const char *log_level = "notice,warning,error"; /* default loglevel, if none is read from conf */
1364         ftdm_r2_data_t *r2data = NULL;
1365         ftdm_r2_span_pvt_t *spanpvt = NULL;
1366         ftdm_r2_call_t *r2call = NULL;
1367         openr2_chan_t *r2chan = NULL;
1368         unsigned paramindex = 0;
1369 
1370         ft_r2_conf_t r2conf = 
1371         {
1372                 /* .variant */ OR2_VAR_ITU,
1373                 /* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
1374                 /* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING,
1375 #ifdef WIN32
1376                 /* .logdir */ (char *)"c:\\", 
1377 #else
1378                 /* .logdir */ (char *)"/tmp", 
1379 #endif
1380                 /* .advanced_protocol_file */ NULL,
1381                 /* .max_ani */ 10,
1382                 /* .max_dnis */ 4,
1383                 /* .mfback_timeout */ -1,
1384                 /* .metering_pulse_timeout */ -1,
1385                 /* .mf_dump_size */ 0,
1386                 /* .immediate_accept */ -1,
1387                 /* .skip_category */ -1,
1388                 /* .get_ani_first */ -1,
1389                 /* .call_files */ 0,
1390                 /* .double_answer */ -1,
1391                 /* .charge_calls */ -1,
1392                 /* .forced_release */ -1,
1393                 /* .allow_collect_calls */ -1
1394         };
1395 
1396         ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling cb provided\n");
1397 
1398         if (span->signal_type) {
1399                 snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
1400                 return FTDM_FAIL;
1401         }
1402 
1403         for (; ftdm_parameters[paramindex].var; paramindex++) {
1404                 var = ftdm_parameters[paramindex].var;
1405                 val = ftdm_parameters[paramindex].val;
1406                 ftdm_log(FTDM_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id);
1407                 if (!strcasecmp(var, "variant")) {
1408                         if (!val) {
1409                                 break;
1410                         }
1411                         if (ftdm_strlen_zero_buf(val)) {
1412                                 ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 variant parameter\n");
1413                                 continue;
1414                         }
1415                         r2conf.variant = openr2_proto_get_variant(val);
1416                         if (r2conf.variant == OR2_VAR_UNKNOWN) {
1417                                 ftdm_log(FTDM_LOG_ERROR, "Unknown R2 variant %s\n", val);
1418                                 conf_failure = 1;
1419                                 break;
1420                         }
1421                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val);
1422                 } else if (!strcasecmp(var, "category")) {
1423                         if (!val) {
1424                                 break;
1425                         }
1426                         if (ftdm_strlen_zero_buf(val)) {
1427                                 ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 category parameter\n");
1428                                 continue;
1429                         }
1430                         r2conf.category = openr2_proto_get_category(val);
1431                         if (r2conf.category == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
1432                                 ftdm_log(FTDM_LOG_ERROR, "Unknown R2 caller category %s\n", val);
1433                                 conf_failure = 1;
1434                                 break;
1435                         }
1436                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val);
1437                 } else if (!strcasecmp(var, "logdir")) {
1438                         if (!val) {
1439                                 break;
1440                         }
1441                         if (ftdm_strlen_zero_buf(val)) {
1442                                 ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n");
1443                                 continue;
1444                         }
1445                         r2conf.logdir = (char *)val;
1446                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val);
1447                 } else if (!strcasecmp(var, "logging")) {
1448                         if (!val) {
1449                                 break;
1450                         }
1451                         if (ftdm_strlen_zero_buf(val)) {
1452                                 ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
1453                                 continue;
1454                         }
1455                         log_level = val;
1456                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with loglevel %s\n", span->name, val);
1457                 } else if (!strcasecmp(var, "advanced_protocol_file")) {
1458                         if (!val) {
1459                                 break;
1460                         }
1461                         if (ftdm_strlen_zero_buf(val)) {
1462                                 ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n");
1463                                 continue;
1464                         }
1465                         r2conf.advanced_protocol_file = (char *)val;
1466                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with advanced protocol file %s\n", span->name, val);
1467                 } else if (!strcasecmp(var, "mf_dump_size")) {
1468                         intval = atoi(val);
1469                         if (intval < 0) {
1470                                 r2conf.mf_dump_size = FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
1471                                 ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with default mf_dump_size = %d bytes\n", span->name, r2conf.mf_dump_size);
1472                         } else {
1473                                 r2conf.mf_dump_size = intval;
1474                                 ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with mf_dump_size = %d bytes\n", span->name, r2conf.mf_dump_size);
1475                         }
1476                 } else if (!strcasecmp(var, "allow_collect_calls")) {
1477                         r2conf.allow_collect_calls = ftdm_true(val);
1478                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with allow collect calls max ani = %d\n", span->name, r2conf.allow_collect_calls);
1479                 } else if (!strcasecmp(var, "double_answer")) {
1480                         r2conf.double_answer = ftdm_true(val);
1481                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with double answer = %d\n", span->name, r2conf.double_answer);
1482                 } else if (!strcasecmp(var, "immediate_accept")) {
1483                         r2conf.immediate_accept = ftdm_true(val);
1484                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with immediate accept = %d\n", span->name, r2conf.immediate_accept);
1485                 } else if (!strcasecmp(var, "skip_category")) {
1486                         r2conf.skip_category = ftdm_true(val);
1487                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with skip category = %d\n", span->name, r2conf.skip_category);
1488                 } else if (!strcasecmp(var, "forced_release")) {
1489                         r2conf.forced_release = ftdm_true(val);
1490                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with forced release = %d\n", span->name, r2conf.forced_release);
1491                 } else if (!strcasecmp(var, "charge_calls")) {
1492                         r2conf.charge_calls = ftdm_true(val);
1493                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with charge calls = %d\n", span->name, r2conf.charge_calls);
1494                 } else if (!strcasecmp(var, "get_ani_first")) {
1495                         r2conf.get_ani_first = ftdm_true(val);
1496                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with get ani first = %d\n", span->name, r2conf.get_ani_first);
1497                 } else if (!strcasecmp(var, "call_files")) {
1498                         r2conf.call_files = ftdm_true(val);
1499                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with call files = %d\n", span->name, r2conf.call_files);
1500                 } else if (!strcasecmp(var, "mfback_timeout")) {
1501                         r2conf.mfback_timeout = atoi(val);
1502                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with MF backward timeout = %dms\n", span->name, r2conf.mfback_timeout);
1503                 } else if (!strcasecmp(var, "metering_pulse_timeout")) {
1504                         r2conf.metering_pulse_timeout = atoi(val);
1505                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with metering pulse timeout = %dms\n", span->name, r2conf.metering_pulse_timeout);
1506                 } else if (!strcasecmp(var, "max_ani")) {
1507                         r2conf.max_ani = atoi(val);
1508                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max ani = %d\n", span->name, r2conf.max_ani);
1509                 } else if (!strcasecmp(var, "max_dnis")) {
1510                         r2conf.max_dnis = atoi(val);
1511                         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max dnis = %d\n", span->name, r2conf.max_dnis);
1512                 } else {
1513                         snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
1514                         return FTDM_FAIL;
1515                 }
1516         }
1517 
1518         if (conf_failure) {
1519                 snprintf(span->last_error, sizeof(span->last_error), "R2 configuration error");
1520                 return FTDM_FAIL;
1521         }
1522 
1523         /* set span log level */
1524         r2conf.loglevel = ftdm_r2_loglevel_from_string(log_level);
1525         ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, log_level);
1526 
1527         r2data = ftdm_malloc(sizeof(*r2data));
1528         if (!r2data) {
1529                 snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data.");
1530                 return FTDM_FAIL;
1531         }
1532         memset(r2data, 0, sizeof(*r2data));
1533 
1534         spanpvt = ftdm_malloc(sizeof(*spanpvt));
1535         if (!spanpvt) {
1536                 snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate private span data container.");
1537                 goto fail;
1538         }
1539         memset(spanpvt, 0, sizeof(*spanpvt));
1540 
1541         r2data->r2context = openr2_context_new(r2conf.variant, &ftdm_r2_event_iface, r2conf.max_ani, r2conf.max_dnis);
1542         if (!r2data->r2context) {
1543                 snprintf(span->last_error, sizeof(span->last_error), "Cannot create openr2 context for span.");
1544                 goto fail;
1545         }
1546         openr2_context_set_io_type(r2data->r2context, OR2_IO_CUSTOM, &ftdm_r2_io_iface);
1547         openr2_context_set_log_level(r2data->r2context, r2conf.loglevel);
1548         openr2_context_set_ani_first(r2data->r2context, r2conf.get_ani_first);
1549         openr2_context_set_skip_category_request(r2data->r2context, r2conf.skip_category);
1550         openr2_context_set_mf_back_timeout(r2data->r2context, r2conf.mfback_timeout);
1551         openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout);
1552         openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
1553         openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
1554 
1555         ftdm_log(FTDM_LOG_DEBUG, "Setting span %s logdir to %s\n", span->name, r2conf.logdir);
1556         openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
1557         snprintf(r2data->logdir, sizeof(r2data->logdir), "%s", r2conf.logdir);
1558 
1559         if (r2conf.advanced_protocol_file) {
1560                 openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
1561         }
1562 
1563         spanpvt->r2calls = create_hashtable(FTDM_MAX_CHANNELS_SPAN, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
1564         if (!spanpvt->r2calls) {
1565                 snprintf(span->last_error, sizeof(span->last_error), "Cannot create channel calls hash for span.");
1566                 goto fail;
1567         }
1568 
1569         for (i = 1; (i <= span->chan_count) && (i <= FTDM_MAX_CHANNELS_SPAN); i++) {
1570                 r2chan = openr2_chan_new_from_fd(r2data->r2context, span->channels[i], span->channels[i]->chan_id);
1571                 if (!r2chan) {
1572                         snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span.");
1573                         goto fail;
1574                 }
1575                 openr2_chan_set_log_level(r2chan, r2conf.loglevel);
1576                 if (r2conf.call_files) {
1577                         openr2_chan_enable_call_files(r2chan);
1578                 }
1579 
1580                 r2call = ftdm_malloc(sizeof(*r2call));
1581                 if (!r2call) {
1582                         snprintf(span->last_error, sizeof(span->last_error), "Cannot create all R2 call data structures for the span.");
1583                         ftdm_safe_free(r2chan);
1584                         goto fail;
1585                 }
1586                 memset(r2call, 0, sizeof(*r2call));
1587                 openr2_chan_set_logging_func(r2chan, ftdm_r2_on_chan_log);
1588                 openr2_chan_set_client_data(r2chan, span->channels[i]);
1589                 r2call->r2chan = r2chan;
1590                 span->channels[i]->call_data = r2call;
1591                 /* value and key are the same so just free one of them */
1592                 snprintf(r2call->name, sizeof(r2call->name), "chancall%d", i);
1593                 hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
1594         }
1595         r2data->mf_dump_size = r2conf.mf_dump_size;
1596         r2data->category = r2conf.category;
1597         r2data->flags = 0;
1598         spanpvt->r2context = r2data->r2context;
1599 
1600         /* just the value must be freed by the hash */
1601         hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE);
1602 
1603         span->start = ftdm_r2_start;
1604         span->stop = ftdm_r2_stop;
1605         span->sig_read = NULL;
1606         span->sig_write = NULL;
1607 
1608         span->signal_cb = sig_cb;
1609         span->signal_type = FTDM_SIGTYPE_R2;
1610         span->signal_data = r2data;
1611         span->outgoing_call = r2_outgoing_call;
1612         span->get_span_sig_status = ftdm_r2_get_span_sig_status;
1613         span->set_span_sig_status = ftdm_r2_set_span_sig_status;
1614         span->get_channel_sig_status = ftdm_r2_get_channel_sig_status;
1615         span->set_channel_sig_status = ftdm_r2_set_channel_sig_status;
1616 
1617         span->state_map = &r2_state_map;
1618         span->state_processor = ftdm_r2_state_advance;
1619 
1620         /* use signals queue */
1621         ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
1622 
1623         /* we can skip states (going straight from RING to UP) */
1624         ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
1625 
1626         /* setup the scheduler */
1627         snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
1628         ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
1629         spanpvt->sched = r2data->sched;
1630 
1631         return FTDM_SUCCESS;
1632 
1633 fail:
1634 
1635         if (r2data && r2data->r2context) {
1636                 openr2_context_delete(r2data->r2context);
1637         }
1638         if (spanpvt && spanpvt->r2calls) {
1639                 hashtable_destroy(spanpvt->r2calls);
1640         }
1641         ftdm_safe_free(r2data);
1642         ftdm_safe_free(spanpvt);
1643         return FTDM_FAIL;
1644 
1645 }
1646 
1647 /* the channel must be locked when calling this function */
1648 static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
1649 {
1650         ftdm_sigmsg_t sigev;
1651         ftdm_status_t ret;
1652         ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
1653         openr2_chan_t *r2chan = r2call->r2chan;
1654         ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
1655 
1656         memset(&sigev, 0, sizeof(sigev));
1657         sigev.chan_id = ftdmchan->chan_id;
1658         sigev.span_id = ftdmchan->span_id;
1659         sigev.channel = ftdmchan;
1660 
1661         ret = FTDM_SUCCESS;
1662 
1663         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
1664 
1665         if (IS_ACCEPTING_PENDING(ftdmchan)) {
1666                 /* 
1667                    Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
1668                    the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
1669                    since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
1670                    which means during that time the user should not try to perform any operations like answer, hangup or anything
1671                    else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
1672                    the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
1673                    otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first, 
1674                    if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
1675                 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
1676         } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
1677                 ftdm_channel_complete_state(ftdmchan);
1678         }
1679 
1680         switch (ftdmchan->state) {
1681 
1682                 /* starting an incoming call */
1683                 case FTDM_CHANNEL_STATE_COLLECT: 
1684                         {
1685                                 uint32_t interval = 0;
1686                                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
1687                                 ftdm_assert(interval != 0, "Invalid interval!");
1688                                 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
1689                                 openr2_chan_enable_read(r2chan);
1690                         }
1691                         break;
1692 
1693                         /* starting an outgoing call */
1694                 case FTDM_CHANNEL_STATE_DIALING:
1695                         {
1696                                 uint32_t interval = 0;
1697                                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
1698                                 ftdm_assert(interval != 0, "Invalid interval!");
1699                                 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting outgoing call with interval %d\n", interval);
1700                                 openr2_chan_enable_read(r2chan);
1701                         }
1702                         break;
1703 
1704                         /* incoming call was offered */
1705                 case FTDM_CHANNEL_STATE_RING:
1706 
1707                         /* notify the user about the new call */
1708                         sigev.event_id = FTDM_SIGEVENT_START;
1709                         ftdm_span_send_signal(ftdmchan->span, &sigev);
1710                         break;
1711 
1712                         /* the call is making progress */
1713                 case FTDM_CHANNEL_STATE_PROGRESS:
1714                 case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
1715                         {
1716                                 if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1717                                         if (!r2call->accepted) {
1718                                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
1719                                                 ft_r2_accept_call(ftdmchan);
1720                                         } 
1721                                 } else {
1722                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
1723                                         sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
1724                                         ftdm_span_send_signal(ftdmchan->span, &sigev);
1725                                 }
1726                         }
1727                         break;
1728 
1729                         /* the call was answered */
1730                 case FTDM_CHANNEL_STATE_UP:
1731                         {
1732                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
1733                                 if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1734                                         if (!r2call->accepted) {
1735                                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
1736                                                 // the answering will be done in the on_call_accepted handler
1737                                                 ft_r2_accept_call(ftdmchan);
1738                                                 r2call->answer_pending = 1;
1739                                         } else {
1740                                                 ft_r2_answer_call(ftdmchan);
1741                                         }
1742                                 } else {
1743                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
1744                                         sigev.event_id = FTDM_SIGEVENT_UP;
1745                                         ftdm_span_send_signal(ftdmchan->span, &sigev);
1746                                 }
1747                         }
1748                         break;
1749 
1750                         /* just got hangup */
1751                 case FTDM_CHANNEL_STATE_HANGUP:
1752                         {
1753                                 if (!r2call->disconnect_rcvd) {
1754                                         openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
1755                                         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
1756                                         /* this will disconnect the call, but need to wait for the call end before moving to DOWN */
1757                                         openr2_chan_disconnect_call(r2chan, disconnect_cause);
1758                                 } else if (!r2call->protocol_error) {
1759                                         /* just ack the hangup, on_call_end will be called by openr2 right after */
1760                                         openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
1761                                 } else {
1762                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
1763                                         /* do not set to down yet, give some time for recovery */
1764                                         ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100, 
1765                                                         ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
1766                                 }
1767                         }
1768                         break;
1769 
1770                 case FTDM_CHANNEL_STATE_TERMINATING:
1771                         {
1772                                 /* if the call has not been started yet we must go to HANGUP right here */ 
1773                                 if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED)) {
1774                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1775                                 } else {
1776                                         openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
1777                                         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
1778                                         /* notify the user of the call terminating and we wait for the user to move us to hangup */
1779                                         sigev.event_id = FTDM_SIGEVENT_STOP;
1780                                         ftdm_span_send_signal(ftdmchan->span, &sigev);
1781                                 }
1782                         }
1783                         break;
1784 
1785                         /* finished call for good */
1786                 case FTDM_CHANNEL_STATE_DOWN: 
1787                         {
1788                                 if (ftdmchan->last_state != FTDM_CHANNEL_STATE_RESET) {
1789                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
1790                                 } else {
1791                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Reset Complete\n");
1792                                 }
1793                                 ret = FTDM_BREAK;
1794                         }
1795                         break;
1796 
1797                         /* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
1798                 case FTDM_CHANNEL_STATE_RINGING: 
1799                         {
1800                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
1801                         }
1802                         break;
1803 
1804                         /* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
1805                 case FTDM_CHANNEL_STATE_RESET:
1806                         {
1807                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
1808                                 openr2_chan_set_idle(r2chan);
1809                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
1810                         }
1811                         break;
1812 
1813                 default:
1814                         {
1815                                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
1816                         }
1817                         break;
1818         }
1819 
1820         if (ret == FTDM_BREAK) {
1821                 ftdm_channel_t *closed_chan;
1822                 closed_chan = ftdmchan;
1823                 ftdm_channel_close(&closed_chan);
1824                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n");
1825         }
1826         return ret;
1827 }
1828 
1829 static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
1830 {
1831         openr2_chan_t *r2chan = NULL;
1832         ftdm_channel_t *ftdmchan = NULL;
1833         ftdm_r2_call_t *call = NULL;
1834         ftdm_status_t status;
1835         ftdm_span_t *span = (ftdm_span_t *) obj;
1836         ftdm_r2_data_t *r2data = span->signal_data;
1837         int waitms = 20;
1838         unsigned int i;
1839         int res, ms;
1840         int index = 0;
1841         struct timeval start, end;
1842         ftdm_iterator_t *chaniter = NULL;
1843         ftdm_iterator_t *citer = NULL;
1844         uint32_t txqueue_size = 4;
1845         short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
1846 
1847         /* as long as this thread is running, this flag is set */
1848         ftdm_set_flag(r2data, FTDM_R2_RUNNING);
1849 
1850 #ifdef __linux__
1851         r2data->monitor_thread_id = syscall(SYS_gettid);        
1852 #endif
1853         
1854         ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread %lu started.\n", r2data->monitor_thread_id);
1855         r2chan = NULL;
1856         chaniter = ftdm_span_get_chan_iterator(span, NULL);
1857         if (!chaniter) {
1858                 ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
1859                 goto done;
1860         }
1861         for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) {
1862                 ftdmchan = ftdm_iterator_current(citer);
1863                 ftdm_channel_lock(ftdmchan);
1864                 r2chan = R2CALL(ftdmchan)->r2chan;
1865                 openr2_chan_set_span_id(r2chan, span->span_id);
1866                 openr2_chan_set_idle(r2chan);
1867                 openr2_chan_process_cas_signaling(r2chan);
1868                 ftdm_channel_unlock(ftdmchan);
1869                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txqueue_size);
1870         }
1871 
1872         memset(&start, 0, sizeof(start));
1873         memset(&end, 0, sizeof(end));
1874         while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_SPAN_STARTED)) {
1875                 res = gettimeofday(&end, NULL);
1876                 if (res) {
1877                         ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno));
1878                 }
1879                 if (start.tv_sec) {
1880                         ms = ((end.tv_sec - start.tv_sec) * 1000) 
1881                             + ((( 1000000 + end.tv_usec - start.tv_usec) / 1000) - 1000);
1882                         if (ms < 0) {
1883                                 ms = 0;
1884                         }
1885                         if (ms > r2data->jobmax) {
1886                                 r2data->jobmax = ms;
1887                         }
1888                         index = (ms / 10);
1889                         index = (index > 10) ? 10 : index;
1890                         r2data->loops[index]++;
1891                         r2data->total_loops++;
1892                 }
1893 
1894                 /* run any span timers */
1895                 ftdm_sched_run(r2data->sched);
1896 
1897                 /* deliver the actual channel events to the user now without any channel locking */
1898                 ftdm_span_trigger_signals(span);
1899 
1900                  /* figure out what event to poll each channel for. POLLPRI when the channel is down,
1901                   * POLLPRI|POLLIN|POLLOUT otherwise */
1902                 memset(poll_events, 0, sizeof(short)*span->chan_count);
1903                 citer = ftdm_span_get_chan_iterator(span, chaniter);
1904                 if (!citer) {
1905                         ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
1906                         goto done;
1907                 }
1908                 for (i = 0; citer; citer = ftdm_iterator_next(citer), i++) {
1909                         ftdmchan = ftdm_iterator_current(citer);
1910                         r2chan = R2CALL(ftdmchan)->r2chan;
1911                         poll_events[i] = FTDM_EVENTS;
1912                         if (openr2_chan_get_read_enabled(r2chan)) {
1913                                 poll_events[i] |= FTDM_READ;
1914                         }
1915                 }
1916                 status = ftdm_span_poll_event(span, waitms, poll_events);
1917 
1918                 /* run any span timers */
1919                 ftdm_sched_run(r2data->sched);
1920 
1921                 res = gettimeofday(&start, NULL);
1922                 if (res) {
1923                         ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno));
1924                 }
1925 
1926                 if (FTDM_FAIL == status) {
1927                         ftdm_log(FTDM_LOG_CRIT, "Failure waiting I/O! [%s]\n", span->channels[1]->last_error);
1928                         continue;
1929                 }
1930 
1931                 ms = ((start.tv_sec - end.tv_sec) * 1000) 
1932                     + ((( 1000000 + start.tv_usec - end.tv_usec) / 1000) - 1000);
1933                 if (ms < 0) {
1934                         ms = 0;
1935                 }
1936                 if (ms > r2data->sleepmax) {
1937                         r2data->sleepmax = ms;
1938                 }
1939                 index = (ms / 15);
1940                 index = (index > 10) ? 10 : index;
1941                 r2data->sleeps[index]++;
1942                 r2data->total_sleeps++;
1943 
1944                 /* this main loop takes care of MF and CAS signaling during call setup and tear down
1945                  * for every single channel in the span, do not perform blocking operations here! */
1946                 citer = ftdm_span_get_chan_iterator(span, chaniter);
1947                 for ( ; citer; citer = ftdm_iterator_next(citer)) {
1948                         ftdmchan = ftdm_iterator_current(citer);
1949 
1950                         ftdm_channel_lock(ftdmchan);
1951 
1952                         call = R2CALL(ftdmchan);
1953 
1954                         /* This let knows the core and io signaling hooks know that 
1955                          * read/writes come from us and should be allowed */
1956                         ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
1957                         ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
1958 
1959                         ftdm_channel_advance_states(ftdmchan);
1960 
1961                         r2chan = call->r2chan;
1962                         openr2_chan_process_signaling(r2chan);
1963 
1964                         ftdm_channel_advance_states(ftdmchan);
1965 
1966                         if (!call->accepted) {
1967                                 /* if the call is not accepted we do not want users reading */
1968                                 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
1969                                 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
1970                         }
1971 
1972                         ftdm_channel_unlock(ftdmchan);
1973                 }
1974         }
1975 
1976 done:   
1977         citer = ftdm_span_get_chan_iterator(span, chaniter);
1978         for ( ; citer; citer = ftdm_iterator_next(citer)) {
1979                 ftdmchan = ftdm_iterator_current(citer);
1980                 ftdm_channel_lock(ftdmchan);
1981                 r2chan = R2CALL(ftdmchan)->r2chan;
1982                 openr2_chan_set_blocked(r2chan);
1983                 ftdm_channel_unlock(ftdmchan);
1984         }
1985 
1986         ftdm_iterator_free(chaniter);
1987         ftdm_safe_free(poll_events);
1988 
1989         ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
1990         ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n");
1991 
1992         return NULL;
1993 }
1994 
1995 static void __inline__ block_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t *stream)
1996 {
1997         openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
1998         ftdm_mutex_lock(fchan->mutex);
1999         if (fchan->state != FTDM_CHANNEL_STATE_DOWN) {
2000                 stream->write_function(stream, "cannot block channel %d:%d because has a call in progress\n", 
2001                                 fchan->span_id, fchan->chan_id);
2002         } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
2003                 stream->write_function(stream, "cannot block channel %d:%d because is already blocked\n", 
2004                                 fchan->span_id, fchan->chan_id);
2005         } else {
2006                 if (!openr2_chan_set_blocked(r2chan)) {
2007                         ftdm_set_flag(fchan, FTDM_CHANNEL_SUSPENDED);
2008                         stream->write_function(stream, "blocked channel %d:%d\n", 
2009                                         fchan->span_id, fchan->chan_id);
2010                 } else {
2011                         stream->write_function(stream, "failed to block channel %d:%d\n", 
2012                                         fchan->span_id, fchan->chan_id);
2013                 }
2014         }
2015         ftdm_mutex_unlock(fchan->mutex);
2016 }
2017 
2018 static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t *stream)
2019 {
2020         openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
2021         ftdm_mutex_lock(fchan->mutex);
2022         if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) {
2023                 if (!openr2_chan_set_idle(r2chan)) {
2024                         ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED);
2025                         stream->write_function(stream, "unblocked channel %d:%d\n", 
2026                                         fchan->span_id, fchan->chan_id);
2027                 } else {
2028                         stream->write_function(stream, "failed to unblock channel %d:%d\n", 
2029                                         fchan->span_id, fchan->chan_id);
2030                 }
2031         } else {
2032                 stream->write_function(stream, "cannot unblock channel %d:%d because is not blocked\n", 
2033                                 fchan->span_id, fchan->chan_id);
2034         }
2035         ftdm_mutex_unlock(fchan->mutex);
2036 }
2037 
2038 #define FT_SYNTAX "USAGE:\n" \
2039 "--------------------------------------------------------------------------------\n" \
2040 "ftdm r2 status <span_id|span_name>\n" \
2041 "ftdm r2 loopstats <span_id|span_name>\n" \
2042 "ftdm r2 block|unblock <span_id|span_name> [<chan_id>]\n" \
2043 "ftdm r2 version\n" \
2044 "ftdm r2 variants\n" \
2045 "--------------------------------------------------------------------------------\n"
2046 static FIO_API_FUNCTION(ftdm_r2_api)
2047 {
2048         ftdm_span_t *span = NULL;
2049         char *mycmd = NULL, *argv[10] = { 0 };
2050         int argc = 0;
2051         int span_id = 0;
2052         unsigned int chan_id = 0;
2053         unsigned int i = 0;
2054         ftdm_r2_data_t *r2data = NULL;
2055         openr2_chan_t *r2chan = NULL;
2056         openr2_context_t *r2context = NULL;
2057         openr2_variant_t r2variant;
2058 
2059         if (data) {
2060                 mycmd = ftdm_strdup(data);
2061                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
2062         }
2063 
2064         if (argc >= 2) {
2065                 if (!strcasecmp(argv[0], "block")) {
2066                         int span_id = atoi(argv[1]);
2067 
2068                         if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
2069 
2070                                 if (span->start != ftdm_r2_start) {
2071                                         stream->write_function(stream, "-ERR invalid span.\n");
2072                                         goto done;
2073                                 }
2074 
2075                                 if (argc > 2) {
2076                                         chan_id = atoi(argv[2]);
2077                                         if (chan_id && chan_id <= span->chan_count) {
2078                                                 block_channel(span->channels[chan_id], stream);
2079                                         } else {
2080                                                 stream->write_function(stream, "-ERR invalid chan %d.\n", chan_id);
2081                                         }
2082                                 } else {
2083                                         for (i = 1; i <= span->chan_count; i++) {
2084                                                 block_channel(span->channels[i], stream);
2085                                         }
2086                                 }
2087                                 stream->write_function(stream, "+OK blocked.\n");
2088                                 goto done;
2089                         } else {
2090                                 stream->write_function(stream, "-ERR invalid span.\n");
2091                                 goto done;
2092                         }
2093                 }
2094 
2095                 if (!strcasecmp(argv[0], "unblock")) {
2096                         span_id = atoi(argv[1]);
2097                         if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
2098 
2099                                 if (span->start != ftdm_r2_start) {
2100                                         stream->write_function(stream, "-ERR invalid span.\n");
2101                                         goto done;
2102                                 }
2103 
2104                                 if (argc > 2) {
2105                                         chan_id = atoi(argv[2]);
2106                                         if (chan_id && chan_id <= span->chan_count) {
2107                                                 unblock_channel(span->channels[chan_id], stream);
2108                                         } else {
2109                                                 stream->write_function(stream, "-ERR invalid chan %d.\n", chan_id);
2110                                         }
2111                                 } else {
2112                                         for (i = 1; i <= span->chan_count; i++) {
2113                                                 unblock_channel(span->channels[i], stream);
2114                                         }
2115                                 }
2116                                 
2117                                 stream->write_function(stream, "+OK.\n");
2118                                 goto done;
2119                         } else {
2120                                 stream->write_function(stream, "-ERR invalid span.\n");
2121                                 goto done;
2122                         }
2123 
2124                 }
2125 
2126                 if (!strcasecmp(argv[0], "status")) {
2127                         //openr2_chan_stats_t stats;
2128                         span_id = atoi(argv[1]);
2129 
2130                         if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
2131                                 if (span->start != ftdm_r2_start) {
2132                                         stream->write_function(stream, "-ERR not an R2 span.\n");
2133                                         goto done;
2134                                 }
2135                                 if (!(r2data =  span->signal_data)) {
2136                                         stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n");
2137                                         goto done;
2138                                 }
2139                                 r2context = r2data->r2context;
2140                                 r2variant = openr2_context_get_variant(r2context);
2141                                 stream->write_function(stream, 
2142                                                 "Variant: %s\n"
2143                                                 "Max ANI: %d\n"
2144                                                 "Max DNIS: %d\n"
2145                                                 "ANI First: %s\n"
2146                                                 "Immediate Accept: %s\n"
2147                                                 "Job Thread: %u\n"
2148                                                 "Job Max ms: %d\n"
2149                                                 "Job Loops: %lu\n",
2150                                                 openr2_proto_get_variant_string(r2variant),
2151                                                 openr2_context_get_max_ani(r2context),
2152                                                 openr2_context_get_max_dnis(r2context),
2153                                                 openr2_context_get_ani_first(r2context) ? "Yes" : "No",
2154                                                 openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
2155                                                 r2data->monitor_thread_id,
2156                                                 r2data->jobmax, 
2157                                                 r2data->total_loops);
2158                                 stream->write_function(stream, "\n");
2159                                 stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
2160                                 for (i = 1; i <= span->chan_count; i++) {
2161                                         r2chan = R2CALL(span->channels[i])->r2chan;
2162                                         stream->write_function(stream, "%4d    %-12.12s %-12.12s\n", 
2163                                                         span->channels[i]->chan_id,
2164                                                         openr2_chan_get_tx_cas_string(r2chan),
2165                                                         openr2_chan_get_rx_cas_string(r2chan));
2166                                 }
2167                                 stream->write_function(stream, "\n");
2168                                 stream->write_function(stream, "+OK.\n");
2169                                 goto done;
2170                         } else {
2171                                 stream->write_function(stream, "-ERR invalid span.\n");
2172                                 goto done;
2173                         }
2174                 }
2175 
2176                 if (!strcasecmp(argv[0], "loopstats")) {
2177                         int range;
2178                         float pct;
2179                         span_id = atoi(argv[1]);
2180 
2181                         if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
2182                                 if (span->start != ftdm_r2_start) {
2183                                         stream->write_function(stream, "-ERR not an R2 span.\n");
2184                                         goto done;
2185                                 }
2186                                 if (!(r2data =  span->signal_data)) {
2187                                         stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n");
2188                                         goto done;
2189                                 }
2190                                 stream->write_function(stream, "-- Working --\n");
2191                                 stream->write_function(stream, "Total loops: %llu\n", r2data->total_loops);
2192                                 range = 0;
2193                                 for (i = 0; i < ftdm_array_len(r2data->loops); i++) {
2194                                         pct = 100*(float)r2data->loops[i]/r2data->total_loops;
2195                                         if ((i + 1) == ftdm_array_len(r2data->loops)) {
2196                                                 stream->write_function(stream, ">= %dms: %llu - %.03lf%%\n", range, r2data->loops[i], pct);
2197                                         } else {
2198                                                 stream->write_function(stream, "%d-%dms: %llu - %.03lf%%\n", range, range + 9, r2data->loops[i], pct);
2199                                         }
2200                                         range += 10;
2201                                 }
2202                                 stream->write_function(stream, "\n");
2203 
2204                                 stream->write_function(stream, "-- Sleeping --\n");
2205                                 stream->write_function(stream, "Total sleeps: %llu\n", r2data->total_sleeps);
2206                                 range = 0;
2207                                 for (i = 0; i < ftdm_array_len(r2data->sleeps); i++) {
2208                                         pct = 100*(float)r2data->sleeps[i]/r2data->total_sleeps;
2209                                         if ((i + 1) == ftdm_array_len(r2data->sleeps)) {
2210                                                 stream->write_function(stream, ">= %dms: %llu - %.03lf%%\n", range, r2data->sleeps[i], pct);
2211                                         } else {
2212                                                 stream->write_function(stream, "%d-%dms: %llu - %.03lf%%\n", range, range + 14, r2data->sleeps[i], pct);
2213                                         }
2214                                         range += 15;
2215                                 }
2216                                 stream->write_function(stream, "\n");
2217                                 
2218                                 stream->write_function(stream, "+OK.\n");
2219                                 goto done;
2220                         } else {
2221                                 stream->write_function(stream, "-ERR invalid span.\n");
2222                                 goto done;
2223                         }
2224                 }
2225 
2226         }
2227 
2228         if (argc == 1) {
2229                 if (!strcasecmp(argv[0], "version")) {
2230                         stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
2231                         stream->write_function(stream, "+OK.\n");
2232                         goto done;
2233                 }
2234 
2235                 if (!strcasecmp(argv[0], "variants")) {
2236                         int32_t numvariants = 0;
2237                         const openr2_variant_entry_t *variants = openr2_proto_get_variant_list(&numvariants);
2238                         if (!variants) {
2239                                 stream->write_function(stream, "-ERR failed to retrieve openr2 variant list.\n");
2240                                 goto done;
2241                         }
2242 #define VARIANT_FORMAT "%4s %40s\n"
2243                         stream->write_function(stream, VARIANT_FORMAT, "Variant Code", "Country");
2244                         numvariants--;
2245                         for (; numvariants; numvariants--) {
2246                                 stream->write_function(stream, VARIANT_FORMAT, variants[numvariants].name, variants[numvariants].country);
2247                         }
2248                         stream->write_function(stream, "+OK.\n");
2249 #undef VARIANT_FORMAT
2250                         goto done;
2251                 }
2252         }
2253 
2254         stream->write_function(stream, "%s", FT_SYNTAX);
2255 
2256 done:
2257 
2258         ftdm_safe_free(mycmd);
2259 
2260         return FTDM_SUCCESS;
2261 
2262 }
2263 
2264 static FIO_IO_LOAD_FUNCTION(ftdm_r2_io_init)
2265 {
2266         assert(fio != NULL);
2267         memset(&g_ftdm_r2_interface, 0, sizeof(g_ftdm_r2_interface));
2268 
2269         g_ftdm_r2_interface.name = "r2";
2270         g_ftdm_r2_interface.api = ftdm_r2_api;
2271 
2272         *fio = &g_ftdm_r2_interface;
2273 
2274         return FTDM_SUCCESS;
2275 }
2276 
2277 static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
2278 {
2279         g_mod_data_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
2280         if (!g_mod_data_hash) {
2281                 return FTDM_FAIL;
2282         }
2283         return FTDM_SUCCESS;
2284 }
2285 
2286 static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
2287 {
2288         ftdm_hash_iterator_t *i = NULL;
2289         ftdm_r2_span_pvt_t *spanpvt = NULL;
2290         const void *key = NULL;
2291         void *val = NULL;
2292         for (i = hashtable_first(g_mod_data_hash); i; i = hashtable_next(i)) {
2293                 hashtable_this(i, &key, NULL, &val);
2294                 if (key && val) {
2295                         spanpvt = val;
2296                         openr2_context_delete(spanpvt->r2context);
2297                         hashtable_destroy(spanpvt->r2calls);
2298                         ftdm_sched_destroy(&spanpvt->sched);
2299                 }
2300         }
2301         hashtable_destroy(g_mod_data_hash);
2302         return FTDM_SUCCESS;
2303 }
2304 
2305 EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
2306         /* .name */ "r2",
2307         /* .io_load */ ftdm_r2_io_init,
2308         /* .io_unload */ NULL,
2309         /* .sig_load */ ftdm_r2_init,
2310         /* .sig_configure */ NULL,
2311         /* .sig_unload */ ftdm_r2_destroy,
2312         /* .configure_span_signaling */ ftdm_r2_configure_span_signaling
2313 };
2314         
2315 
2316 /* For Emacs:
2317  * Local Variables:
2318  * mode:c
2319  * indent-tabs-mode:t
2320  * tab-width:4
2321  * c-basic-offset:4
2322  * End:
2323  * For VIM:
2324  * vim:set softtabstop=4 shiftwidth=4 tabstop=4
2325  */

/* [<][>][^][v][top][bottom][index][help] */