root/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c

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

DEFINITIONS

This source file includes following definitions.
  1. __release_request_id_span_chan
  2. __release_request_id
  3. __next_request_id
  4. print_request_ids
  5. find_ftdmchan
  6. check_congestion
  7. FIO_CHANNEL_REQUEST_FUNCTION
  8. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  9. handle_call_progress
  10. handle_call_start_ack
  11. handle_call_done
  12. handle_call_start_nack
  13. handle_call_released
  14. handle_call_stop
  15. handle_call_answer
  16. handle_call_start
  17. handle_call_loop_start
  18. stop_loop
  19. handle_call_loop_stop
  20. handle_heartbeat
  21. handle_restart_ack
  22. handle_restart
  23. handle_incoming_digit
  24. event_process_states
  25. parse_sangoma_event
  26. state_advance
  27. init_outgoing_array
  28. check_state
  29. check_events
  30. ftdm_sangoma_events_run
  31. ftdm_boost_connection_open
  32. ftdm_boost_wait_event
  33. ftdm_boost_read_event
  34. ftdm_sangoma_boost_run
  35. sigmod_ss7box_isup_exec_cmd
  36. ftdm_cli_span_state_cmd
  37. FIO_API_FUNCTION
  38. FIO_IO_LOAD_FUNCTION
  39. FIO_SIG_LOAD_FUNCTION
  40. FIO_SIG_UNLOAD_FUNCTION
  41. ftdm_sangoma_boost_start
  42. ftdm_sangoma_boost_stop
  43. BOOST_WRITE_MSG_FUNCTION
  44. BOOST_SIG_STATUS_CB_FUNCTION
  45. FIO_CHANNEL_SET_SIG_STATUS_FUNCTION
  46. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  47. FIO_SPAN_SET_SIG_STATUS_FUNCTION
  48. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  49. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
  50. ftdm_sangoma_boost_list_sigmods

   1 /*
   2  * Copyright (c) 2007, Anthony Minessale II
   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  * Moises Silva <moy@sangoma.com>
  36  * David Yat Sin <dyatsin@sangoma.com>
  37  * Nenad Corbic <ncorbic@sangoma.com>
  38  *
  39  */
  40 
  41 /* NOTE:
  42 On __WINDOWS__ platform this code works with sigmod ONLY, don't try to make sense of any socket code for win
  43 I basically ifdef out everything that the compiler complained about
  44 */
  45 
  46 #include "private/ftdm_core.h"
  47 #include "sangoma_boost_client.h"
  48 #include "ftdm_sangoma_boost.h"
  49 #ifdef HAVE_SYS_SELECT_H
  50 #include <sys/select.h>
  51 #endif
  52 
  53 /* Boost signaling modules global hash and its mutex */
  54 ftdm_mutex_t *g_boost_modules_mutex = NULL;
  55 ftdm_hash_t *g_boost_modules_hash = NULL;
  56 
  57 #define MAX_TRUNK_GROUPS 64
  58 //TODO need to merge congestion_timeouts with ftdm_sangoma_boost_trunkgroups
  59 static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
  60 
  61 static ftdm_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS];
  62 
  63 static ftdm_io_interface_t ftdm_sangoma_boost_interface;
  64 static ftdm_status_t ftdm_sangoma_boost_list_sigmods(ftdm_stream_handle_t *stream);
  65 
  66 #define BOOST_QUEUE_SIZE 500
  67 
  68 /* get freetdm span and chan depending on the span mode */
  69 #define BOOST_SPAN(ftdmchan) ((ftdm_sangoma_boost_data_t*)(ftdmchan)->span->signal_data)->sigmod ? ftdmchan->physical_span_id : ftdmchan->physical_span_id-1
  70 #define BOOST_CHAN(ftdmchan) ((ftdm_sangoma_boost_data_t*)(ftdmchan)->span->signal_data)->sigmod ? ftdmchan->physical_chan_id : ftdmchan->physical_chan_id-1
  71 
  72 /**
  73  * \brief SANGOMA boost notification flag
  74  */
  75 typedef enum {
  76         SFLAG_SENT_FINAL_MSG = (1 << 0),
  77         SFLAG_SENT_ACK = (1 << 1),
  78         SFLAG_RECVD_ACK = (1 << 2),
  79         SFLAG_HANGUP = (1 << 3),
  80         SFLAG_TERMINATING = (1 << 4)
  81 } sflag_t;
  82 
  83 typedef uint16_t sangoma_boost_request_id_t;
  84 
  85 /**
  86  * \brief SANGOMA boost request status
  87  */
  88 typedef enum {
  89         BST_FREE,
  90         BST_WAITING,
  91         BST_READY,
  92         BST_FAIL
  93 } sangoma_boost_request_status_t;
  94 
  95 /**
  96  * \brief SANGOMA boost request structure
  97  */
  98 typedef struct {
  99         sangoma_boost_request_status_t status;
 100         sangomabc_short_event_t event;
 101         ftdm_span_t *span;
 102         ftdm_channel_t *ftdmchan;
 103         int hangup_cause;
 104         int flags;
 105 } sangoma_boost_request_t;
 106 
 107 typedef struct {
 108         int call_setup_id;
 109         int last_event_id;
 110 } sangoma_boost_call_t;
 111 
 112 #define CALL_DATA(ftdmchan) ((sangoma_boost_call_t*)((ftdmchan)->call_data))
 113 
 114 //#define MAX_REQ_ID FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * FTDM_MAX_CHANNELS_PHYSICAL_SPAN
 115 #define MAX_REQ_ID 6000
 116 
 117 static uint16_t SETUP_GRID[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN+1][FTDM_MAX_CHANNELS_PHYSICAL_SPAN+1] = {{ 0 }};
 118 
 119 static sangoma_boost_request_t OUTBOUND_REQUESTS[MAX_REQ_ID+1] = {{ 0 }};
 120 
 121 static ftdm_mutex_t *request_mutex = NULL;
 122 
 123 static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
 124 static uint8_t nack_map[MAX_REQ_ID+1] = { 0 };
 125 
 126 /**
 127  * \brief Releases span and channel from setup grid
 128  *
 129  * \note This is ALWAYS based on freetdm span/chan numbers! not boost event numbers
 130  *       is totally brain damaged to use event->span or event->chan to release the request
 131  *       use BOOST_SPAN_EVENT and BOOST_SPAN_CHAN to get the right index!!
 132  *
 133  * \param span Span number
 134  * \param chan Channel number
 135  * \param func Calling function
 136  * \param line Line number on request
 137  * \return NULL if not found, channel otherwise
 138  */
 139 static void __release_request_id_span_chan(int span, int chan, const char *func, int line)
 140 {
 141         int id;
 142 
 143         ftdm_mutex_lock(request_mutex);
 144         if ((id = SETUP_GRID[span][chan])) {
 145                 ftdm_assert(id <= MAX_REQ_ID, "Invalid request id\n");
 146                 req_map[id] = 0;
 147                 SETUP_GRID[span][chan] = 0;
 148         }
 149         ftdm_mutex_unlock(request_mutex);
 150 }
 151 #define release_request_id_span_chan(s, c) __release_request_id_span_chan(s, c, __FUNCTION__, __LINE__)
 152 
 153 /**
 154  * \brief Releases request ID
 155  * \param func Calling function
 156  * \param line Line number on request
 157  * \return NULL if not found, channel otherwise
 158  */
 159 static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line)
 160 {
 161         ftdm_assert(r <= MAX_REQ_ID, "Invalid request id\n");
 162         ftdm_mutex_lock(request_mutex);
 163         req_map[r] = 0;
 164         ftdm_mutex_unlock(request_mutex);
 165 }
 166 #define release_request_id(r) __release_request_id(r, __FUNCTION__, __LINE__)
 167 
 168 static sangoma_boost_request_id_t last_req = 0;
 169 
 170 /**
 171  * \brief Gets the first available tank request ID
 172  * \param func Calling function
 173  * \param line Line number on request
 174  * \return 0 on failure, request ID on success
 175  */
 176 static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
 177 {
 178         sangoma_boost_request_id_t r = 0, i = 0;
 179         int found=0;
 180         
 181         ftdm_mutex_lock(request_mutex);
 182         //r = ++last_req;
 183         //while(!r || req_map[r]) {
 184 
 185         for (i=1; i<= MAX_REQ_ID; i++){
 186                 r = ++last_req;
 187 
 188                 if (r >= MAX_REQ_ID) {
 189                         r = last_req = 1;
 190                 }
 191 
 192                 if (req_map[r]) {
 193                         /* Busy find another */
 194                         continue;
 195 
 196                 }
 197 
 198                 req_map[r] = 1;
 199                 found=1;
 200                 break;
 201 
 202         }
 203 
 204         ftdm_mutex_unlock(request_mutex);
 205 
 206         if (!found) {
 207                 return 0;
 208         }
 209 
 210         return r;
 211 }
 212 #define next_request_id() __next_request_id(__FUNCTION__, __LINE__)
 213 
 214 
 215 static void print_request_ids(void)
 216 {
 217         sangoma_boost_request_id_t i = 0;
 218         int cnt=0;
 219 
 220         ftdm_mutex_lock(request_mutex);
 221 
 222         for (i=1; i<= MAX_REQ_ID; i++){
 223                 if (req_map[i]) {
 224                         ftdm_log(FTDM_LOG_CRIT, "Used Request ID=%i\n",i);
 225                         cnt++;
 226                 }
 227         }
 228 
 229         ftdm_mutex_unlock(request_mutex);
 230         ftdm_log(FTDM_LOG_CRIT, "Total Request IDs=%i\n",cnt);
 231         
 232         return;
 233 }
 234 
 235 
 236 /**
 237  * \brief Finds the channel that triggered an event
 238  * \param span Span where to search the channel
 239  * \param event SANGOMA event
 240  * \param force Do not wait for the channel to be available if in use
 241  * \return NULL if not found, channel otherwise
 242  */
 243 static ftdm_channel_t *find_ftdmchan(ftdm_span_t *span, sangomabc_short_event_t *event, int force)
 244 {
 245         uint32_t i;
 246         ftdm_channel_t *ftdmchan = NULL;
 247 
 248         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
 249         uint32_t targetspan = BOOST_EVENT_SPAN(sangoma_boost_data->sigmod, event);
 250         uint32_t targetchan = BOOST_EVENT_CHAN(sangoma_boost_data->sigmod, event);
 251 
 252         /* NC: Sanity check in case the call setup id does not relate
 253                to span.  This can happen if RESTART is received on a
 254                    full load. Where stray ACK messages can arrive after
 255                    a RESTART has taken place.
 256         */
 257         if (!span) {
 258                 ftdm_log(FTDM_LOG_CRIT, "No Span for Event=%s s%dc%d cid=%d\n",
 259                                                 BOOST_DECODE_EVENT_ID(event->event_id),
 260                                                 targetspan,
 261                                                 targetchan,
 262                                                 event->call_setup_id);
 263                 return NULL;
 264         }
 265 
 266 
 267         for(i = 1; i <= span->chan_count; i++) {
 268                 if (span->channels[i]->physical_span_id == targetspan && span->channels[i]->physical_chan_id == targetchan) {
 269                         ftdmchan = span->channels[i];
 270                         if (force || (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE))) {
 271                                 break;
 272                         } else {
 273                                 ftdmchan = NULL;
 274                                 ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d ~ %d:%d is already in use in state %s\n",
 275                                                 span->channels[i]->span_id,
 276                                                 span->channels[i]->chan_id,
 277                                                 span->channels[i]->physical_span_id,
 278                                                 span->channels[i]->physical_chan_id,
 279                                                 ftdm_channel_state2str(span->channels[i]->state));
 280                                 break;
 281                         }
 282                 }
 283         }
 284 
 285         return ftdmchan;
 286 }
 287 
 288 static int check_congestion(int trunk_group)
 289 {
 290         if (congestion_timeouts[trunk_group]) {
 291                 time_t now = time(NULL);
 292 
 293                 if (now >= congestion_timeouts[trunk_group]) {
 294                         congestion_timeouts[trunk_group] = 0;
 295                 } else {
 296                         return 1;
 297                 }
 298         }
 299 
 300         return 0;
 301 }
 302 
 303 
 304 /**
 305  * \brief Requests an sangoma boost channel on a span (outgoing call)
 306  * \param span Span where to get a channel
 307  * \param chan_id Specific channel to get (0 for any)
 308  * \param direction Call direction
 309  * \param caller_data Caller information
 310  * \param ftdmchan Channel to initialise
 311  * \return Success or failure
 312  */
 313 static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
 314 {
 315         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
 316         ftdm_status_t status = FTDM_FAIL;
 317         sangoma_boost_request_id_t r;
 318         sangomabc_event_t event = {0};
 319         /* sanity has to be more than 8 seconds.
 320          * In PRI specs, timeout is 4 seconds for remote switch to respond to a SETUP,
 321          * and PRI stack will retransmit a second SETUP after the first timeout, so
 322          * we should allow for at least 8 seconds.
 323          */
 324 
 325         int boost_request_timeout = 10000;
 326         sangoma_boost_request_status_t st;
 327         char dnis[128] = "";
 328         char *gr = NULL;
 329         uint32_t count = 0;
 330         int tg=0;
 331 
 332         /* NC: On large number of calls 10 seconds is not enough.
 333                 Resetting to 30 seconds. Especially on ss7 when
 334                 links are reset during large call volume */
 335         if (!sangoma_boost_data->sigmod) {
 336                 boost_request_timeout = 30000;
 337         }
 338         
 339         if (sangoma_boost_data->sigmod) {
 340                 ftdm_log(FTDM_LOG_CRIT, "This function should not be called when sigmod was configured in boost\n");
 341                 *ftdmchan = NULL;
 342                 return FTDM_FAIL;
 343         }
 344 
 345         if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED)) {
 346                 ftdm_log(FTDM_LOG_CRIT, "SPAN is Suspended.\n");
 347                 *ftdmchan = NULL;
 348                 return FTDM_FAIL;
 349         }
 350 
 351         if (check_congestion(tg)) {
 352                 ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (CONGESTION)\n",tg+1);
 353                 *ftdmchan = NULL;
 354                 return FTDM_FAIL;
 355         }
 356 
 357         if (count >= span->chan_count) {
 358                 ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
 359                 *ftdmchan = NULL;
 360                 return FTDM_FAIL;
 361         }
 362 
 363         r = next_request_id();
 364         if (r == 0) {
 365                 ftdm_log(FTDM_LOG_CRIT, "All tanks ids are busy.\n");
 366                 *ftdmchan = NULL;
 367                 return FTDM_FAIL;
 368         }
 369 
 370         /* After this point we must release request id before we leave the function
 371            in case of an error. */
 372 
 373         ftdm_set_string(dnis, caller_data->dnis.digits);
 374 
 375         if ((gr = strchr(dnis, '@'))) {
 376                 *gr++ = '\0';
 377         }
 378 
 379         if (gr && *(gr+1)) {
 380                 tg = atoi(gr+1);
 381                 if (tg > 0) {
 382                         tg--;
 383                 }
 384         }
 385         
 386         sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r);
 387 
 388         event.trunk_group = tg;
 389 
 390 
 391         ftdm_span_channel_use_count(span, &count);
 392 
 393         if (gr && *(gr+1)) {
 394                 switch(*gr) {
 395                                 case 'g':
 396                                                 event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
 397                                                 break;
 398                                 case 'G':
 399                                                 event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC;
 400                                                 break;
 401                                 case 'r':
 402                                                 event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC;
 403                                                 break;
 404                                 case 'R':
 405                                                 event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC;
 406                                                 break;
 407                                 default:
 408                                                 ftdm_log(FTDM_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr);
 409                                                                         event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
 410                 }
 411         }
 412 
 413         ftdm_set_string(event.calling_name, caller_data->cid_name);
 414         ftdm_set_string(event.rdnis.digits, caller_data->rdnis.digits);
 415         if (strlen(caller_data->rdnis.digits)) {
 416                         event.rdnis.digits_count = (uint8_t)strlen(caller_data->rdnis.digits)+1;
 417                         event.rdnis.ton = caller_data->rdnis.type;
 418                         event.rdnis.npi = caller_data->rdnis.plan;
 419         }
 420     
 421         event.calling.screening_ind = caller_data->screen;
 422         event.calling.presentation_ind = caller_data->pres;
 423 
 424         event.calling.ton = caller_data->cid_num.type;
 425         event.calling.npi = caller_data->cid_num.plan;
 426 
 427         event.called.ton = caller_data->dnis.type;
 428         event.called.npi = caller_data->dnis.plan;
 429 
 430         /* we're making a contract now that FreeTDM values for capability, layer 1 and such will be the same as for boost */
 431         event.bearer.capability = caller_data->bearer_capability;
 432         event.bearer.uil1p = caller_data->bearer_layer1;
 433 
 434         if (caller_data->raw_data_len) {
 435                 ftdm_set_string(event.custom_data, caller_data->raw_data);
 436                 event.custom_data_size = (uint16_t)caller_data->raw_data_len;
 437         }
 438 
 439         OUTBOUND_REQUESTS[r].status = BST_WAITING;
 440         OUTBOUND_REQUESTS[r].span = span;
 441 
 442         if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
 443                 ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
 444                 status = OUTBOUND_REQUESTS[r].status = FTDM_FAIL;
 445                 if (!sangoma_boost_data->sigmod) {
 446                         *ftdmchan = NULL;
 447                 }
 448                 goto done;
 449         }
 450 
 451         while(ftdm_running() && OUTBOUND_REQUESTS[r].status == BST_WAITING) {
 452                 ftdm_sleep(1);
 453                 if (--boost_request_timeout <= 0) {
 454                         status = FTDM_FAIL;
 455                         if (!sangoma_boost_data->sigmod) {
 456                                 *ftdmchan = NULL;
 457                         }
 458                         ftdm_log(FTDM_LOG_CRIT, "Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", r);
 459                         goto done;
 460                 }
 461         }
 462 
 463         if (OUTBOUND_REQUESTS[r].status == BST_READY && OUTBOUND_REQUESTS[r].ftdmchan) {
 464                 *ftdmchan = OUTBOUND_REQUESTS[r].ftdmchan;
 465                 status = FTDM_SUCCESS;
 466         } else {
 467                 status = FTDM_FAIL;
 468                 if (!sangoma_boost_data->sigmod) {
 469                         *ftdmchan = NULL;
 470                 }
 471         }
 472 
 473  done:
 474         
 475         st = OUTBOUND_REQUESTS[r].status;
 476         OUTBOUND_REQUESTS[r].status = BST_FREE; 
 477 
 478         if (status == FTDM_FAIL) {
 479                 if (st == BST_FAIL) {
 480                         caller_data->hangup_cause = OUTBOUND_REQUESTS[r].hangup_cause;
 481                 } else {
 482                         caller_data->hangup_cause = FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
 483                 }
 484         }
 485         
 486         if (st == BST_FAIL) {
 487                 release_request_id(r);
 488         } else if (st != BST_READY) {
 489                 ftdm_assert_return(r <= MAX_REQ_ID, FTDM_FAIL, "Invalid index\n");
 490                 nack_map[r] = 1;
 491                 if (sangoma_boost_data->sigmod) {
 492                         sangomabc_exec_command(&sangoma_boost_data->mcon,
 493                                                                 BOOST_SPAN((*ftdmchan)),
 494                                                                 BOOST_CHAN((*ftdmchan)),
 495                                                                 r,
 496                                                                 SIGBOOST_EVENT_CALL_START_NACK,
 497                                                                 0, 0);
 498                 } else {
 499                         sangomabc_exec_command(&sangoma_boost_data->mcon,
 500                                                                 0,
 501                                                                 0,
 502                                                                 r,
 503                                                                 SIGBOOST_EVENT_CALL_START_NACK,
 504                                                                 0, 0);
 505                 }
 506         }
 507 
 508         return status;
 509 }
 510 
 511 /**
 512  * \brief Starts an sangoma boost channel (outgoing call)
 513  * \param ftdmchan Channel to initiate call on
 514  * \return Success
 515  */
 516 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call)
 517 {
 518         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
 519 
 520         if (!sangoma_boost_data->sigmod) {
 521                 return FTDM_SUCCESS;
 522         }
 523 
 524         ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
 525 
 526         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
 527 
 528         return FTDM_SUCCESS;
 529 }
 530 
 531 /**
 532  * \brief Handler for call start ack no media event
 533  * \param mcon sangoma boost connection
 534  * \param event Event to handle
 535  */
 536 static void handle_call_progress(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 537 {
 538         ftdm_channel_t *ftdmchan;
 539 
 540 
 541         if ((ftdmchan = find_ftdmchan(span, event, 1))) {
 542                 ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
 543                 ftdm_mutex_lock(ftdmchan->mutex);
 544                 if (!sangoma_boost_data->sigmod && ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
 545                         if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
 546                                 ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
 547                                 ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
 548                         } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
 549                                 ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
 550                                 ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to PROGRESS [Csid:%d]\n", event->call_setup_id);
 551                         } else {
 552                                 ftdmchan->init_state = FTDM_CHANNEL_STATE_IDLE;
 553                                 ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to IDLE [Csid:%d]\n", event->call_setup_id);
 554                         }                       
 555                 } else {
 556                         if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
 557                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
 558                         } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
 559                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
 560                         } else {
 561                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
 562                         }
 563                 }
 564                 ftdm_mutex_unlock(ftdmchan->mutex);
 565         }
 566 }
 567 
 568 /**
 569  * \brief Handler for call start ack event
 570  * \param mcon sangoma boost connection
 571  * \param event Event to handle
 572  */
 573 static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 574 {
 575         
 576         ftdm_channel_t *ftdmchan = NULL;
 577         uint32_t event_span = BOOST_EVENT_SPAN(mcon->sigmod, event);
 578         uint32_t event_chan = BOOST_EVENT_CHAN(mcon->sigmod, event);
 579 
 580         
 581         if (nack_map[event->call_setup_id]) {
 582                 /* In this scenario outgoing call was alrady stopped
 583                    via NACK and now we are expecting an NACK_ACK.
 584                If we receive an ACK its a race condition thus
 585                    ignor it */
 586                 return;
 587         }
 588 
 589         if (mcon->sigmod) {
 590                 ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
 591         } else {
 592                 ftdmchan = find_ftdmchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0);
 593         }
 594 
 595 
 596         if (ftdmchan) {
 597                 ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
 598                 if (!mcon->sigmod && ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
 599                         ftdm_log(FTDM_LOG_ERROR, "Failed to open FTDM channel [%s]\n", ftdmchan->last_error);
 600                 } else {
 601 
 602                         /* Only bind the setup id to GRID when we are sure that channel is ready
 603                            otherwise we could overwite the original call */
 604                         OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
 605                         SETUP_GRID[event_span][event_chan] = event->call_setup_id;
 606 
 607                         ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
 608                         ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE);
 609                         ftdmchan->sflags = SFLAG_RECVD_ACK;
 610 
 611                         if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
 612                                 if (sangoma_boost_data->sigmod) {
 613                                         ftdm_log(FTDM_LOG_DEBUG, "Channel state changing to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
 614                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
 615                                 } else {
 616                                         ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
 617                                         ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
 618                                 }
 619                         } else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
 620                                 if (sangoma_boost_data->sigmod) {
 621                                         ftdm_log(FTDM_LOG_DEBUG, "Channel state changing to PROGRESS [Csid:%d]\n", event->call_setup_id);
 622                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
 623                                 } else {
 624                                         ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
 625                                         ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to PROGRESS [Csid:%d]\n", event->call_setup_id);
 626                                 }
 627                         } else {
 628                                 if (sangoma_boost_data->sigmod) {
 629                                         /* should we set a state here? */
 630                                 } else {
 631                                         ftdmchan->init_state = FTDM_CHANNEL_STATE_IDLE;
 632                                         ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to IDLE [Csid:%d]\n", event->call_setup_id);
 633                                 }
 634                         }
 635                         if (!sangoma_boost_data->sigmod) {
 636                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HOLD);
 637                                 ftdm_log(FTDM_LOG_DEBUG, "Assigned chan %d:%d (%d:%d) to CSid=%d\n", 
 638                                                 ftdmchan->span_id, ftdmchan->chan_id, event_span, event_chan, event->call_setup_id);
 639                                 OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan = ftdmchan;
 640                         }
 641                         OUTBOUND_REQUESTS[event->call_setup_id].flags = event->flags;
 642                         OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
 643                         return;
 644                 }
 645 
 646         } else {
 647 
 648                 ftdm_assert(!mcon->sigmod, "CALL STOP ACK: Invalid Sigmod Path");
 649  
 650                 if ((ftdmchan = find_ftdmchan(OUTBOUND_REQUESTS[event->call_setup_id].span, (sangomabc_short_event_t*)event, 1))) {
 651                                 int r;
 652                                 /* NC: If we get CALL START ACK and channel is in active state
 653                                                 then we are completely out of sync with the other end.
 654                                                 Treat CALL START ACK as CALL STOP and hangup the current call.
 655                                 */
 656 
 657                                 if (ftdmchan->state == FTDM_CHANNEL_STATE_UP ||
 658                                         ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
 659                                         ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) {
 660                                         ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN CALL ACK STATE UP -> Changed to TERMINATING %d:%d\n", event_span, event_chan);
 661                                         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
 662                                 } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP ||  ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
 663                                         ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN CALL ACK STATE HANGUP  -> Changed to HANGUP COMPLETE %d:%d\n", event_span, event_chan);
 664                                         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
 665                                 } else {
 666                                         ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN STATE INVALID State %s on IN CALL ACK %d:%d\n",
 667                                                  ftdm_channel_state2str(ftdmchan->state), event_span, event_chan);
 668                                 }
 669                                 ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
 670                                 ftdmchan=NULL;
 671                 }
 672         }
 673 
 674 
 675         if (!ftdmchan) {
 676                 ftdm_log(FTDM_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event_span, event_chan);
 677         } else {
 678                 /* only reason to be here is failed to open channel when we we're in sigmod  */
 679                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
 680                 ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
 681         }
 682         
 683         sangomabc_exec_command(mcon,
 684                                            event->span,
 685                                            event->chan,
 686                                            event->call_setup_id,
 687                                            SIGBOOST_EVENT_CALL_STOPPED,
 688                                            FTDM_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
 689         OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
 690         OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
 691 }
 692 
 693 /**
 694  * \brief Handler for call done event
 695  * \param span Span where event was fired
 696  * \param mcon sangoma boost connection
 697  * \param event Event to handle
 698  */
 699 static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 700 {
 701         ftdm_channel_t *ftdmchan;
 702         int r = 0;
 703 
 704         if ((ftdmchan = find_ftdmchan(span, event, 1))) {
 705                 ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
 706                 ftdm_mutex_lock(ftdmchan->mutex);
 707 
 708                 if (sangoma_boost_data->sigmod) {
 709                         /* not really completely done, but if we ever get an incoming call before moving to HANGUP_COMPLETE
 710                          * handle_incoming_call() will take care of moving the state machine to release the channel */
 711                         sangomabc_exec_command(&sangoma_boost_data->mcon,
 712                                                                 BOOST_SPAN(ftdmchan),
 713                                                                 BOOST_CHAN(ftdmchan),
 714                                                                 0,
 715                                                                 SIGBOOST_EVENT_CALL_RELEASED,
 716                                                                 0, 0);
 717                 }
 718 
 719                 if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP_COMPLETE || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
 720                         goto done;
 721                 }
 722 
 723                 ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
 724                 if (r) {
 725                         ftdm_mutex_unlock(ftdmchan->mutex);
 726                         return;
 727                 }
 728         } 
 729 
 730  done:
 731         
 732         if (ftdmchan) {
 733                 ftdm_mutex_unlock(ftdmchan->mutex);
 734         }
 735 
 736         if (event->call_setup_id) {
 737                 release_request_id(event->call_setup_id);
 738         } else {
 739                 release_request_id_span_chan(BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 740         }
 741 }
 742 
 743 
 744 /**
 745  * \brief Handler for call start nack event
 746  * \param span Span where event was fired
 747  * \param mcon sangoma boost connection
 748  * \param event Event to handle
 749  */
 750 static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 751 {
 752         ftdm_channel_t *ftdmchan;
 753         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
 754 
 755         if (event->release_cause == SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY) {
 756                 uint32_t count = 0;
 757                 int delay = 0;
 758                 int tg=event->trunk_group;
 759 
 760                 ftdm_span_channel_use_count(span, &count);
 761 
 762                 delay = (int) (count / 100) * 2;
 763                 
 764                 if (delay > 10) {
 765                         delay = 10;
 766                 } else if (delay < 1) {
 767                         delay = 1;
 768                 }
 769 
 770                 if (tg < 0 || tg >= MAX_TRUNK_GROUPS) {
 771                         ftdm_log(FTDM_LOG_CRIT, "Invalid All Ckt Busy trunk group number %i\n", tg);
 772                         tg=0;
 773                 }
 774                 
 775                 congestion_timeouts[tg] = time(NULL) + delay;
 776                 event->release_cause = 17;
 777 
 778         } else if (event->release_cause == SIGBOOST_CALL_SETUP_CSUPID_DBL_USE) {
 779                 event->release_cause = 17;
 780         }
 781 
 782         if (event->call_setup_id) {
 783                 if (sangoma_boost_data->sigmod) {
 784                         ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
 785                         CALL_DATA(ftdmchan)->last_event_id = event->event_id;
 786                         CALL_DATA(ftdmchan)->call_setup_id = event->call_setup_id;
 787                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
 788                         ftdm_clear_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
 789                 } else {
 790                         sangomabc_exec_command(mcon,
 791                                                    0,
 792                                                    0,
 793                                                    event->call_setup_id,
 794                                                    SIGBOOST_EVENT_CALL_START_NACK_ACK,
 795                                                    0, 0);
 796                         OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
 797                         OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
 798                         OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
 799                         ftdm_log(FTDM_LOG_DEBUG, "setting outbound request status %d to BST_FAIL\n", event->call_setup_id);
 800                 }
 801                 return;
 802         } else {
 803                 if ((ftdmchan = find_ftdmchan(span, event, 1))) {
 804                         int r = 0;
 805 
 806                         /* if there is no call setup id this should not be an outbound channel for sure */
 807                         ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), "Yay, outbound flag should not be set here!\n");
 808 
 809                         CALL_DATA(ftdmchan)->last_event_id = event->event_id;
 810                         ftdm_mutex_lock(ftdmchan->mutex);
 811                         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
 812                         if (r == FTDM_SUCCESS) {
 813                                 ftdmchan->caller_data.hangup_cause = event->release_cause;
 814                         }
 815                         ftdm_mutex_unlock(ftdmchan->mutex);
 816                         if (r) {
 817                                 return;
 818                         }
 819                 } 
 820         }
 821 
 822         if (ftdmchan) {
 823                 ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
 824         }
 825 
 826         /* nobody else will do it so we have to do it ourselves */
 827         sangomabc_exec_command(mcon,
 828                                            event->span,
 829                                            event->chan,
 830                                            event->call_setup_id,
 831                                            SIGBOOST_EVENT_CALL_START_NACK_ACK,
 832                                            0, 0);
 833 }
 834 
 835 static void handle_call_released(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 836 {
 837         ftdm_channel_t *ftdmchan;
 838         
 839         if ((ftdmchan = find_ftdmchan(span, event, 1))) {
 840                 ftdm_log(FTDM_LOG_DEBUG, "Releasing completely chan s%dc%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), 
 841                                 BOOST_EVENT_CHAN(mcon->sigmod, event));
 842                 ftdm_channel_close(&ftdmchan);
 843         } else {
 844                 ftdm_log(FTDM_LOG_CRIT, "Odd, We could not find chan: s%dc%d to release the call completely!!\n", 
 845                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 846         }
 847 }
 848 
 849 /**
 850  * \brief Handler for call stop event
 851  * \param span Span where event was fired
 852  * \param mcon sangoma boost connection
 853  * \param event Event to handle
 854  */
 855 static void handle_call_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 856 {
 857         ftdm_channel_t *ftdmchan;
 858         
 859         if ((ftdmchan = find_ftdmchan(span, event, 1))) {
 860                 int r = 0;
 861 
 862                 ftdm_mutex_lock(ftdmchan->mutex);
 863                 
 864                 if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP) ||
 865                         ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ||
 866                         ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
 867 
 868                         /* NC: Checking for state DOWN because ss7box can
 869                                 send CALL_STOP twice in a row.  If we do not check for
 870                                 STATE_DOWN we will set the state back to termnating
 871                                 and block the channel forever
 872                         */
 873 
 874                         /* racing condition where both sides initiated a hangup 
 875                          * Do not change current state as channel is already clearing
 876                          * itself through local initiated hangup */
 877                         
 878                         sangomabc_exec_command(mcon,
 879                                                 BOOST_SPAN(ftdmchan),
 880                                                 BOOST_CHAN(ftdmchan),
 881                                                 0,
 882                                                 SIGBOOST_EVENT_CALL_STOPPED_ACK,
 883                                                 0, 0);
 884                         ftdm_mutex_unlock(ftdmchan->mutex);
 885                         return;
 886                 } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
 887                         ftdmchan->init_state = FTDM_CHANNEL_STATE_TERMINATING;
 888                         ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to TERMINATING [Csid:%d]\n", event->call_setup_id);
 889                         OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
 890                         ftdmchan->caller_data.hangup_cause = event->release_cause;
 891                         ftdm_mutex_unlock(ftdmchan->mutex);
 892                         return;
 893                 } else {
 894                         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
 895                 }
 896 
 897                 if (r == FTDM_SUCCESS) {
 898                         ftdmchan->caller_data.hangup_cause = event->release_cause;
 899                 }
 900 
 901                 ftdm_mutex_unlock(ftdmchan->mutex);
 902 
 903                 if (r) {
 904                         return;
 905                 }
 906         } else { /* we have to do it ourselves.... */
 907                 ftdm_log(FTDM_LOG_CRIT, "Odd, We could not find chan: s%dc%d\n", 
 908                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 909                 release_request_id_span_chan(BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 910         }
 911 }
 912 
 913 /**
 914  * \brief Handler for call answer event
 915  * \param span Span where event was fired
 916  * \param mcon sangoma boost connection
 917  * \param event Event to handle
 918  */
 919 static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
 920 {
 921         ftdm_channel_t *ftdmchan;
 922         
 923         if ((ftdmchan = find_ftdmchan(span, event, 1))) {
 924                 ftdm_mutex_lock(ftdmchan->mutex);
 925 
 926                 if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP) ||
 927                         ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ||
 928                         ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
 929 
 930                         /* NC: Do nothing here because we are in process
 931                                 of stopping the call. So ignore the ANSWER. */
 932                         ftdm_log(FTDM_LOG_DEBUG, "Got answer but call is already hangup %d:%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), 
 933                                         BOOST_EVENT_CHAN(mcon->sigmod, event));
 934 
 935                 } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
 936                         ftdmchan->init_state = FTDM_CHANNEL_STATE_UP;
 937 
 938                 } else {
 939                         int r = 0;
 940                         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, r);
 941                 }
 942                 ftdm_mutex_unlock(ftdmchan->mutex);
 943         } else {
 944                 ftdm_log(FTDM_LOG_CRIT, "Could not find channel %d:%d on answer message!\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 945                 sangomabc_exec_command(mcon,
 946                                    event->span,
 947                                    event->chan,
 948                                    event->call_setup_id,
 949                                    SIGBOOST_EVENT_CALL_STOPPED,
 950                                    FTDM_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
 951         }
 952 }
 953 
 954 static __inline__ void stop_loop(ftdm_channel_t *ftdmchan);
 955 
 956 /**
 957  * \brief Handler for call start event
 958  * \param span Span where event was fired
 959  * \param mcon sangoma boost connection
 960  * \param event Event to handle
 961  */
 962 static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
 963 {
 964         ftdm_channel_t *ftdmchan = NULL;
 965         int hangup_cause = FTDM_CAUSE_CALL_REJECTED;
 966         int retry = 1;
 967 
 968 tryagain:
 969 
 970         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
 971                 if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
 972                         int r;
 973 
 974                          /* NC: If we get CALL START and channel is in active state
 975                                 then we are completely out of sync with the other end.
 976                                     Treat CALL START as CALL STOP and hangup the current call.
 977                                         The incoming call will also be NACKed.
 978                           */
 979 
 980                         if (ftdmchan->state == FTDM_CHANNEL_STATE_UP ||
 981                                 ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
 982                                 ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) {
 983                                 ftdm_log(FTDM_LOG_CRIT, "s%dc%d: FTDMCHAN STATE UP -> Changed to TERMINATING\n", 
 984                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 985                                 ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
 986                         } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP ||  ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
 987                                 ftdm_log(FTDM_LOG_CRIT, "s%dc%d: FTDMCHAN STATE HANGUP -> Changed to HANGUP COMPLETE\n", 
 988                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 989                                 ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
 990                         } else if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 991                                 ftdm_log(FTDM_LOG_WARNING, "s%dc%d: Collision, hanging up incoming call\n", 
 992                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 993                                 /* dont hangup the outgoing call, the other side will send a call start nack too
 994                                  * and there we will move to terminating. If we move to terminating here. We used to move
 995                                  * to terminating here, but that introduces a problem in handle_call_start_nack where
 996                                  * when receiving call start nack we move the channel from DOWN to TERMINATING ( cuz we already
 997                                  * hangup here ) and the channel gets stuck in terminating forever. So at this point we're trusting
 998                                  * the other side to send the call start nack ( or proceed with the call )
 999                                  * ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
1000                                  */
1001                         } else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) {
1002                                 retry = 0;
1003                                 stop_loop(ftdmchan);
1004                                 ftdm_channel_advance_states(ftdmchan);
1005                                 goto tryagain;
1006                         } else {
1007                                 ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n", 
1008                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event), 
1009                                                 ftdm_channel_state2str(ftdmchan->state));
1010                         }
1011                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
1012                         ftdmchan = NULL;
1013                 } else {
1014                         ftdm_log(FTDM_LOG_CRIT, "s%dc%d: incoming call in invalid channel (channel not found)!\n", 
1015                                         BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1016                 }
1017                 goto error;
1018         }
1019 
1020         if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
1021                 ftdm_log(FTDM_LOG_ERROR, "s%dc%d: failed to open channel on incoming call, rejecting!\n", 
1022                         BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1023                 goto error;
1024         }
1025         
1026         ftdm_log(FTDM_LOG_DEBUG, "Got call start from s%dc%d mapped to freetdm logical s%dc%d, physical s%dc%d\n", 
1027                         event->span, event->chan, 
1028                         ftdmchan->span_id, ftdmchan->chan_id,
1029                         ftdmchan->physical_span_id, ftdmchan->physical_chan_id);
1030 
1031         ftdmchan->sflags = 0;
1032         ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)event->calling.digits);
1033         ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling.digits);
1034         ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)event->calling.digits);
1035         ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)event->called.digits);
1036         ftdm_set_string(ftdmchan->caller_data.rdnis.digits, (char *)event->rdnis.digits);
1037         if (event->custom_data_size) {
1038                 ftdm_set_string(ftdmchan->caller_data.raw_data, event->custom_data);
1039                 ftdmchan->caller_data.raw_data_len = event->custom_data_size;
1040         }
1041 
1042         if (strlen(event->calling_name)) {
1043                 ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling_name);
1044         }
1045 
1046         ftdmchan->caller_data.cid_num.plan = event->calling.npi;
1047         ftdmchan->caller_data.cid_num.type = event->calling.ton;
1048 
1049         ftdmchan->caller_data.ani.plan = event->calling.npi;
1050         ftdmchan->caller_data.ani.type = event->calling.ton;
1051 
1052         ftdmchan->caller_data.dnis.plan = event->called.npi;
1053         ftdmchan->caller_data.dnis.type = event->called.ton;
1054 
1055         ftdmchan->caller_data.rdnis.plan = event->rdnis.npi;
1056         ftdmchan->caller_data.rdnis.type = event->rdnis.ton;
1057 
1058         ftdmchan->caller_data.screen = event->calling.screening_ind;
1059         ftdmchan->caller_data.pres = event->calling.presentation_ind;
1060 
1061         ftdmchan->caller_data.bearer_capability = event->bearer.capability;
1062         ftdmchan->caller_data.bearer_layer1 = event->bearer.uil1p;
1063 
1064         /* more info about custom data: http://www.ss7box.com/smg_manual.html#ISUP-IN-RDNIS-NEW */
1065         if (event->custom_data_size) {
1066                 char* p = NULL;
1067 
1068                 p = strstr((char*)event->custom_data,"PRI001-ANI2-");
1069                 if (p!=NULL) {
1070                         int ani2 = 0;
1071                         sscanf(p, "PRI001-ANI2-%d", &ani2);
1072                         snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", ani2);
1073                 }       
1074         }
1075 
1076         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
1077         return;
1078 
1079  error:
1080         hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
1081         sangomabc_exec_command(mcon,
1082                                                    event->span,
1083                                                    event->chan,
1084                                                    event->call_setup_id,
1085                                                    SIGBOOST_EVENT_CALL_START_NACK,
1086                                                    hangup_cause, 0);
1087                 
1088 }
1089 
1090 static void handle_call_loop_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
1091 {
1092         ftdm_status_t res = FTDM_FAIL;
1093         ftdm_channel_t *ftdmchan;
1094 
1095         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
1096                 ftdm_log(FTDM_LOG_CRIT, "CANNOT START LOOP, CHAN NOT AVAILABLE %d:%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1097                 return;
1098         }
1099 
1100         if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
1101                 ftdm_log(FTDM_LOG_CRIT, "CANNOT START LOOP, CANT OPEN CHAN %d:%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1102                 return;
1103         }
1104 
1105         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, res);
1106         if (res != FTDM_SUCCESS) {
1107                 ftdm_channel_t *toclose = ftdmchan;
1108                 ftdm_log(FTDM_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
1109                 ftdm_channel_close(&toclose);
1110                 return;
1111         }
1112         ftdm_log(FTDM_LOG_DEBUG, "%d:%d starting loop\n", ftdmchan->span_id, ftdmchan->chan_id);
1113         ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_LOOP, NULL);
1114 }
1115 
1116 static __inline__ void stop_loop(ftdm_channel_t *ftdmchan)
1117 {
1118         ftdm_status_t res = FTDM_FAIL;
1119         ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL);
1120         /* even when we did not sent a msg we set this flag to avoid sending call stop in the DOWN state handler */
1121         ftdm_set_flag(ftdmchan, SFLAG_SENT_FINAL_MSG);
1122         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_DOWN, res);
1123         if (res != FTDM_SUCCESS) {
1124                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "yay, could not set the state of the channel from IN_LOOP to DOWN\n");
1125         }
1126 }
1127 
1128 static void handle_call_loop_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
1129 {
1130         ftdm_channel_t *ftdmchan;
1131         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
1132                 ftdm_log(FTDM_LOG_CRIT, "CANNOT STOP LOOP, INVALID CHAN REQUESTED %d:%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1133                 return;
1134         }
1135         if (ftdmchan->state != FTDM_CHANNEL_STATE_IN_LOOP) {
1136                 ftdm_log(FTDM_LOG_WARNING, "Got stop loop request in a channel that is not in loop, ignoring ...\n");
1137                 return;
1138         }
1139         stop_loop(ftdmchan);
1140 }
1141 
1142 /**
1143  * \brief Handler for heartbeat event
1144  * \param mcon sangoma boost connection
1145  * \param event Event to handle
1146  */
1147 static void handle_heartbeat(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
1148 {
1149         int err;
1150         
1151         err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event);
1152         
1153         if (err <= 0) {
1154                 ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost connection [%s]: %s\n", strerror(errno));
1155         }
1156     return;
1157 }
1158 
1159 /**
1160  * \brief Handler for restart ack event
1161  * \param mcon sangoma boost connection
1162  * \param span Span where event was fired
1163  * \param event Event to handle
1164  */
1165 static void handle_restart_ack(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_short_event_t *event)
1166 {
1167         ftdm_log(FTDM_LOG_DEBUG, "RECV RESTART ACK\n");
1168 }
1169 
1170 /**
1171  * \brief Handler for restart event
1172  * \param mcon sangoma boost connection
1173  * \param span Span where event was fired
1174  * \param event Event to handle
1175  */
1176 static void handle_restart(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_short_event_t *event)
1177 {
1178         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1179 
1180     mcon->rxseq_reset = 0;
1181         ftdm_set_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
1182         ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
1183         ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
1184         
1185 }
1186 
1187 /**
1188  * \brief Handler for incoming digit event
1189  * \param mcon sangoma boost connection
1190  * \param span Span where event was fired
1191  * \param event Event to handle
1192  */
1193 static void handle_incoming_digit(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_event_t *event)
1194 {
1195         ftdm_channel_t *ftdmchan = NULL;
1196         char digits[MAX_DIALED_DIGITS + 2] = "";
1197         
1198         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t *)event, 1))) {
1199                 ftdm_log(FTDM_LOG_ERROR, "Invalid channel\n");
1200                 return;
1201         }
1202         
1203         if (event->called_number_digits_count == 0) {
1204                 ftdm_log(FTDM_LOG_WARNING, "Error Incoming digit with len %s %d [w%dg%d]\n",
1205                                 event->called_number_digits,
1206                                 event->called_number_digits_count,
1207                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1208                 return;
1209         }
1210 
1211         ftdm_log(FTDM_LOG_WARNING, "Incoming digit with len %s %d [w%dg%d]\n",
1212                                         event->called_number_digits,
1213                                         event->called_number_digits_count,
1214                                         BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1215 
1216         memcpy(digits, event->called_number_digits, event->called_number_digits_count);
1217         ftdm_channel_queue_dtmf(ftdmchan, digits);
1218 
1219         return;
1220 }
1221 
1222 
1223 /**
1224  * \brief Checks if span has state changes pending and processes 
1225  * \param span Span where event was fired
1226  * \param event Event to handle
1227  * \return The locked FTDM channel associated to the event if any, NULL otherwise
1228  */
1229 static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_event_t *event) 
1230 {
1231     ftdm_channel_t *ftdmchan = NULL;
1232                 ftdm_sangoma_boost_data_t *signal_data = span->signal_data;
1233     
1234     switch (event->event_id) {
1235         case SIGBOOST_EVENT_CALL_START_NACK:
1236         case SIGBOOST_EVENT_CALL_START_NACK_ACK:
1237             if (event->call_setup_id && !signal_data->sigmod) {
1238                 return NULL;
1239             } 
1240             //if event->span and event->chan is valid, fall-through
1241         case SIGBOOST_EVENT_CALL_START:
1242         case SIGBOOST_EVENT_CALL_START_ACK:
1243         case SIGBOOST_EVENT_CALL_STOPPED:
1244         case SIGBOOST_EVENT_CALL_PROGRESS:
1245         case SIGBOOST_EVENT_CALL_ANSWERED:
1246         case SIGBOOST_EVENT_CALL_STOPPED_ACK:
1247         case SIGBOOST_EVENT_DIGIT_IN:
1248         case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
1249         case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
1250         case SIGBOOST_EVENT_CALL_RELEASED:
1251             if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
1252                 ftdm_log(FTDM_LOG_CRIT, "could not find channel %d:%d to process pending state changes!\n",
1253                                                                         BOOST_EVENT_SPAN(signal_data->sigmod, event),
1254                                                                         BOOST_EVENT_CHAN(signal_data->sigmod, event));
1255                 return NULL;
1256             }
1257             break;
1258         case SIGBOOST_EVENT_HEARTBEAT:
1259         case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
1260         case SIGBOOST_EVENT_SYSTEM_RESTART:
1261         case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
1262             return NULL;
1263         default:
1264             ftdm_log(FTDM_LOG_CRIT, "Unhandled event id: %d\n", event->event_id);
1265             return NULL;
1266     }
1267 
1268     ftdm_mutex_lock(ftdmchan->mutex);
1269     ftdm_channel_advance_states(ftdmchan);
1270     return ftdmchan;
1271 }
1272 
1273 /**
1274  * \brief Handler for sangoma boost event
1275  * \param span Span where event was fired
1276  * \param mcon sangoma boost connection
1277  * \param event Event to handle
1278  */
1279 static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
1280 {
1281     ftdm_channel_t* ftdmchan = NULL;
1282         
1283         if (!ftdm_running()) {
1284                 ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
1285                 return -1;
1286         }
1287 
1288     ftdm_assert_return(event->call_setup_id <= MAX_REQ_ID, -1, "Unexpected call setup id\n");
1289 
1290         /* process all pending state changes for that channel before
1291          * processing the new boost event */
1292     ftdmchan = event_process_states(span, event);
1293 
1294     switch(event->event_id) {
1295     case SIGBOOST_EVENT_CALL_START:
1296                 handle_call_start(span, mcon, (sangomabc_event_t*)event);
1297                 break;
1298     case SIGBOOST_EVENT_CALL_STOPPED:
1299                 handle_call_stop(span, mcon, event);
1300                 break;
1301     case SIGBOOST_EVENT_CALL_RELEASED:
1302                 handle_call_released(span, mcon, event);
1303                 break;
1304     case SIGBOOST_EVENT_CALL_START_ACK:
1305                 handle_call_start_ack(mcon, event);
1306                 break;
1307     case SIGBOOST_EVENT_CALL_PROGRESS:
1308                 handle_call_progress(span, mcon, event);
1309                 break;
1310     case SIGBOOST_EVENT_CALL_START_NACK:
1311                 handle_call_start_nack(span, mcon, event);
1312                 break;
1313     case SIGBOOST_EVENT_CALL_ANSWERED:
1314                 handle_call_answer(span, mcon, event);
1315                 break;
1316     case SIGBOOST_EVENT_HEARTBEAT:
1317                 handle_heartbeat(mcon, event);
1318                 break;
1319     case SIGBOOST_EVENT_CALL_STOPPED_ACK:
1320                 handle_call_done(span, mcon, event);
1321                 break;
1322     case SIGBOOST_EVENT_CALL_START_NACK_ACK:
1323                 /* On NACK ack span chan are always invalid
1324                    All there is to do is to clear the id */
1325                 if (event->call_setup_id) {
1326                         nack_map[event->call_setup_id] = 0;
1327                         release_request_id(event->call_setup_id);
1328                 } else {
1329                         handle_call_done(span, mcon, event);
1330                 }
1331                 break;
1332     case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
1333                 handle_call_loop_start(span, mcon, event);
1334                 break;
1335     case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
1336                 handle_call_loop_stop(span, mcon, event);
1337                 break;
1338     case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
1339                 handle_restart_ack(mcon, span, event);
1340                 break;
1341         case SIGBOOST_EVENT_SYSTEM_RESTART:
1342                 handle_restart(mcon, span, event);
1343                 break;
1344     case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
1345                 //handle_gap_abate(event);
1346                 break;
1347         case SIGBOOST_EVENT_DIGIT_IN:
1348                 handle_incoming_digit(mcon, span, (sangomabc_event_t*)event);
1349                 break;
1350     default:
1351                 ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", sangomabc_event_id_name(event->event_id));
1352                 break;
1353     }
1354 
1355     if(ftdmchan != NULL) {
1356         ftdm_channel_advance_states(ftdmchan);
1357         ftdm_mutex_unlock(ftdmchan->mutex);
1358     }
1359 
1360     return 0;
1361 
1362 }
1363 
1364 /**
1365  * \brief Handler for channel state change
1366  * \param ftdmchan Channel to handle
1367  */
1368 static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
1369 {
1370         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
1371         sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
1372         ftdm_sigmsg_t sig;
1373         ftdm_status_t status;
1374 
1375 
1376         ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n");
1377 
1378         ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
1379         
1380         memset(&sig, 0, sizeof(sig));
1381         sig.chan_id = ftdmchan->chan_id;
1382         sig.span_id = ftdmchan->span_id;
1383         sig.channel = ftdmchan;
1384 
1385         ftdm_channel_complete_state(ftdmchan);
1386 
1387         switch (ftdmchan->state) {
1388         case FTDM_CHANNEL_STATE_DOWN:
1389                 {
1390                         int call_stopped_ack_sent = 0;
1391                         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
1392 
1393                         if (ftdmchan->last_state == FTDM_CHANNEL_STATE_IN_LOOP) {
1394                                 ftdm_log(FTDM_LOG_DEBUG, "%d:%d terminating loop\n", ftdmchan->span_id, ftdmchan->chan_id);
1395                         } else {
1396                                 release_request_id_span_chan(ftdmchan->physical_span_id, ftdmchan->physical_chan_id);
1397 
1398                                 if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG)) {
1399                                         ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
1400 
1401                                         if (ftdmchan->call_data && CALL_DATA(ftdmchan)->last_event_id == SIGBOOST_EVENT_CALL_START_NACK) {
1402                                                 sangomabc_exec_command(mcon,
1403                                                                                 BOOST_SPAN(ftdmchan),
1404                                                                                 BOOST_CHAN(ftdmchan),
1405                                                                                 CALL_DATA(ftdmchan)->call_setup_id,
1406                                                                                 SIGBOOST_EVENT_CALL_START_NACK_ACK,
1407                                                                                 0, 0);
1408                                                 
1409                                         } else {
1410                                                 /* we got a call stop msg, time to reply with call stopped ack  */
1411                                                 sangomabc_exec_command(mcon,
1412                                                                                 BOOST_SPAN(ftdmchan),
1413                                                                                 BOOST_CHAN(ftdmchan),
1414                                                                                 0,
1415                                                                                 SIGBOOST_EVENT_CALL_STOPPED_ACK,
1416                                                                                 0, 0);
1417                                                 call_stopped_ack_sent = 1;
1418                                         }
1419                                 }
1420                         }
1421 
1422                         ftdmchan->sflags = 0;
1423                         memset(ftdmchan->call_data, 0, sizeof(sangoma_boost_call_t));
1424                         if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
1425                                 /* we dont want to call ftdm_channel_close just yet until call released is received */
1426                                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n", 
1427                                                 ftdmchan->span_id, ftdmchan->chan_id);
1428                         } else {
1429                                 ftdm_channel_t *toclose = ftdmchan;
1430                                 ftdm_channel_close(&toclose);
1431                         }
1432                 }
1433                 break;
1434         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
1435                 {
1436                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1437                                 sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
1438                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1439                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1440                                 }
1441                         } else {
1442                                 if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
1443                                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
1444                                         sangomabc_exec_command(mcon,
1445                                                                 BOOST_SPAN(ftdmchan),
1446                                                                 BOOST_CHAN(ftdmchan),
1447                                                                 0,
1448                                                                 SIGBOOST_EVENT_CALL_START_ACK,
1449                                                                 0, 0);
1450                                 }
1451                                 sangomabc_exec_command(mcon,
1452                                                         BOOST_SPAN(ftdmchan),
1453                                                         BOOST_CHAN(ftdmchan),
1454                                                         0,
1455                                                         SIGBOOST_EVENT_CALL_PROGRESS,
1456                                                         0, SIGBOOST_PROGRESS_MEDIA);
1457                         }
1458                 }
1459                 break;
1460         case FTDM_CHANNEL_STATE_PROGRESS:
1461                 {
1462                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1463                                 sig.event_id = FTDM_SIGEVENT_PROGRESS;
1464                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1465                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1466                                 }
1467                         } else {
1468                                 if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
1469                                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
1470                                         sangomabc_exec_command(mcon,
1471                                                                 BOOST_SPAN(ftdmchan),
1472                                                                 BOOST_CHAN(ftdmchan),
1473                                                                 0,
1474                                                                 SIGBOOST_EVENT_CALL_START_ACK,
1475                                                                 0, SIGBOOST_PROGRESS_RING);
1476                                 }
1477                         }
1478                 }
1479                 break;
1480         case FTDM_CHANNEL_STATE_IDLE:
1481         case FTDM_CHANNEL_STATE_HOLD:
1482                 {
1483                         /* twiddle */
1484                 }
1485                 break;
1486         case FTDM_CHANNEL_STATE_RING:
1487                 {
1488                         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1489                                 sig.event_id = FTDM_SIGEVENT_START;
1490                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1491                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1492                                 }
1493                         }
1494                 }
1495                 break;
1496         case FTDM_CHANNEL_STATE_RESTART:
1497                 {
1498                         sig.event_id = FTDM_SIGEVENT_RESTART;
1499                         status = ftdm_span_send_signal(ftdmchan->span, &sig);
1500                         ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
1501                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
1502                 }
1503                 break;
1504         case FTDM_CHANNEL_STATE_UP:
1505                 {
1506                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1507                                 sig.event_id = FTDM_SIGEVENT_UP;
1508                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1509                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1510                                 }
1511                         } else {
1512                                 if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
1513                                         sangomabc_exec_command(mcon,
1514                                                                            BOOST_SPAN(ftdmchan),
1515                                                                            BOOST_CHAN(ftdmchan),                                                                   
1516                                                                            0,
1517                                                                            SIGBOOST_EVENT_CALL_START_ACK,
1518                                                                            0, 0);
1519                                 }
1520                                 
1521                                 sangomabc_exec_command(mcon,
1522                                                                    BOOST_SPAN(ftdmchan),
1523                                                                    BOOST_CHAN(ftdmchan),                                                                   
1524                                                                    0,
1525                                                                    SIGBOOST_EVENT_CALL_ANSWERED,
1526                                                                    0, 0);
1527                         }
1528                 }
1529                 break;
1530         case FTDM_CHANNEL_STATE_DIALING:
1531                 {
1532                         char dnis[128] = "";
1533                         sangoma_boost_request_id_t r;
1534                         sangomabc_event_t event = {0};
1535 
1536                         ftdm_assert(sangoma_boost_data->sigmod != NULL, "We should be in sigmod here!\n");
1537                         
1538                         ftdm_set_string(dnis, ftdmchan->caller_data.dnis.digits);
1539 
1540                         r = next_request_id();
1541                         if (r == 0) {
1542                                 ftdm_log(FTDM_LOG_CRIT, "All boost request ids are busy.\n");
1543                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
1544                                 break;
1545                         }
1546                         
1547                         sangomabc_call_init(&event, ftdmchan->caller_data.cid_num.digits, dnis, r);
1548 
1549                         event.span = (uint8_t)ftdmchan->physical_span_id;
1550                         event.chan = (uint8_t)ftdmchan->physical_chan_id;
1551                         /* because we already have a span/chan here we bind to the SETUP_GRID now and not on call start ack */
1552                         SETUP_GRID[event.span][event.chan] = event.call_setup_id;
1553 
1554                         ftdm_set_string(event.calling_name, ftdmchan->caller_data.cid_name);
1555                         ftdm_set_string(event.rdnis.digits, ftdmchan->caller_data.rdnis.digits);
1556                         if (strlen(ftdmchan->caller_data.rdnis.digits)) {
1557                                 event.rdnis.digits_count = (uint8_t)strlen(ftdmchan->caller_data.rdnis.digits)+1;
1558                                 event.rdnis.ton = ftdmchan->caller_data.rdnis.type;
1559                                 event.rdnis.npi = ftdmchan->caller_data.rdnis.plan;
1560                         }
1561 
1562                         event.calling.screening_ind = ftdmchan->caller_data.screen;
1563                         event.calling.presentation_ind = ftdmchan->caller_data.pres;
1564 
1565                         event.calling.ton = ftdmchan->caller_data.cid_num.type;
1566                         event.calling.npi = ftdmchan->caller_data.cid_num.plan;
1567 
1568                         event.called.ton = ftdmchan->caller_data.dnis.type;
1569                         event.called.npi = ftdmchan->caller_data.dnis.plan;
1570 
1571                         if (ftdmchan->caller_data.raw_data_len) {
1572                                 ftdm_set_string(event.custom_data, ftdmchan->caller_data.raw_data);
1573                                 event.custom_data_size = (uint16_t)ftdmchan->caller_data.raw_data_len;
1574                         }
1575 
1576                         OUTBOUND_REQUESTS[r].status = BST_WAITING;
1577                         OUTBOUND_REQUESTS[r].span = ftdmchan->span;
1578                         OUTBOUND_REQUESTS[r].ftdmchan = ftdmchan;
1579 
1580                         ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s over boost channel with request id %d\n", event.called_number_digits, r);
1581                         if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
1582                                 release_request_id(r);
1583                                 ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
1584                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
1585                         }
1586                         
1587                 }
1588                 break;
1589         case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
1590                 {
1591                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
1592                 }
1593                 break;
1594         case FTDM_CHANNEL_STATE_HANGUP:
1595                 {
1596                         ftdm_set_sflag_locked(ftdmchan, SFLAG_HANGUP);
1597 
1598                         if (ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG) || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
1599                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
1600                         } else {
1601                                 ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
1602                                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || 
1603                                                 ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || 
1604                                                 ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA) ||
1605                                                 ftdm_test_sflag(ftdmchan, SFLAG_RECVD_ACK)) {
1606                                         sangomabc_exec_command(mcon,
1607                                                                            BOOST_SPAN(ftdmchan),
1608                                                                            BOOST_CHAN(ftdmchan),
1609                                                                            0,
1610                                                                            SIGBOOST_EVENT_CALL_STOPPED,
1611                                                                            ftdmchan->caller_data.hangup_cause, 0);
1612                                 } else {
1613                                         sangomabc_exec_command(mcon,
1614                                                                            BOOST_SPAN(ftdmchan),
1615                                                                            BOOST_CHAN(ftdmchan),                                                                   
1616                                                                            0,
1617                                                                            SIGBOOST_EVENT_CALL_START_NACK,
1618                                                                            ftdmchan->caller_data.hangup_cause, 0);
1619                                 }
1620                         }
1621                 }
1622                 break;
1623         case FTDM_CHANNEL_STATE_TERMINATING:
1624                 {
1625                         ftdm_set_sflag_locked(ftdmchan, SFLAG_TERMINATING);
1626                         sig.event_id = FTDM_SIGEVENT_STOP;
1627                         status = ftdm_span_send_signal(ftdmchan->span, &sig);
1628                 }
1629                 break;
1630         case FTDM_CHANNEL_STATE_IN_LOOP:
1631                 {
1632                         /* nothing to do, we sent the FTDM_COMMAND_ENABLE_LOOP command in handle_call_loop_start() right away */
1633                 }
1634                 break;
1635         default:
1636                 break;
1637         }
1638         return FTDM_SUCCESS;
1639 }
1640 
1641 /**
1642  * \brief Initialises outgoing requests array
1643  */
1644 static __inline__ void init_outgoing_array(void)
1645 {
1646         memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
1647 }
1648 
1649 /**
1650  * \brief Checks current state on a span
1651  * \param span Span to check status on
1652  */
1653 static __inline__ void check_state(ftdm_span_t *span)
1654 {
1655         ftdm_channel_t *ftdmchan = NULL;
1656         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1657         int susp = ftdm_test_flag(span, FTDM_SPAN_SUSPENDED);
1658         
1659         if (susp && ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
1660                 susp = 0;
1661         }
1662 
1663         if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE) || susp) {
1664                 uint32_t j;
1665                 ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
1666                 if (susp) {
1667                         for(j = 1; j <= span->chan_count; j++) {
1668                                 if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE) || susp) {
1669                                         ftdm_mutex_lock(span->channels[j]->mutex);
1670                                         ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
1671                                         if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
1672                                                 ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
1673                                         }
1674                                         ftdm_channel_advance_states(span->channels[j]);
1675                                         ftdm_mutex_unlock(span->channels[j]->mutex);
1676                                 }
1677                         }
1678                 } else {
1679                         while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
1680                                 /* it can happen that someone else processed the chan states
1681                                  * but without taking the chan out of the queue, so check th
1682                                  * flag before advancing the state */
1683                                 ftdm_mutex_lock(ftdmchan->mutex);
1684                                 ftdm_channel_advance_states(ftdmchan);
1685                                 ftdm_mutex_unlock(ftdmchan->mutex);
1686                         }
1687                 }
1688         }
1689 
1690         if (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING)) {
1691                 if (ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
1692                         sangomabc_exec_command(&sangoma_boost_data->mcon,
1693                                                                    0,
1694                                                                    0,
1695                                                                    -1,
1696                                                                    SIGBOOST_EVENT_SYSTEM_RESTART_ACK,
1697                                                                    0, 0);       
1698                         ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
1699                         ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
1700                         ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
1701                         init_outgoing_array();
1702                 }
1703         }
1704 }
1705 
1706 
1707 /**
1708  * \brief Checks for events on a span
1709  * \param span Span to check for events
1710  */
1711 static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout)
1712 {
1713         ftdm_status_t status;
1714         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1715 
1716         status = ftdm_span_poll_event(span, ms_timeout, NULL);
1717 
1718         switch(status) {
1719         case FTDM_SUCCESS:
1720                 {
1721                         ftdm_event_t *event;
1722                         while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
1723                                 switch (event->enum_id) {
1724                                 case FTDM_OOB_ALARM_TRAP:
1725                                         if (sangoma_boost_data->sigmod) {
1726                                                 sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_DISCONNECTED);
1727                                         }
1728                                         break;
1729                                 case FTDM_OOB_ALARM_CLEAR:
1730                                         if (sangoma_boost_data->sigmod) {
1731                                                 sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_CONNECTED);
1732                                         }
1733                                         break;
1734                                 }
1735                         }
1736                 }
1737                 break;
1738         case FTDM_FAIL:
1739                 {
1740                         if (!ftdm_running()) {
1741                                 break;
1742                         }
1743                         ftdm_log(FTDM_LOG_ERROR, "Boost Check Event Failure Failure: %s\n", span->last_error);
1744                         return FTDM_FAIL;
1745                 }
1746                 break;
1747         default:
1748                 break;
1749         }
1750 
1751         return FTDM_SUCCESS;
1752 }
1753 
1754 /**
1755  * \brief Main thread function for sangoma boost span (monitor)
1756  * \param me Current thread
1757  * \param obj Span to run in this thread
1758  */
1759 static void *ftdm_sangoma_events_run(ftdm_thread_t *me, void *obj)
1760 {
1761         ftdm_span_t *span = (ftdm_span_t *) obj;
1762         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1763         unsigned errs = 0;
1764 
1765         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && ftdm_running()) {
1766                 if (check_events(span, 100) != FTDM_SUCCESS) {
1767                         if (errs++ > 50) {
1768                                 ftdm_log(FTDM_LOG_ERROR, "Too many event errors, quitting sangoma events thread\n");
1769                                 return NULL;
1770                         }
1771                 }
1772         }
1773         
1774         ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost Events thread ended.\n");
1775 
1776         ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
1777 
1778         return NULL;
1779 }
1780 
1781 static ftdm_status_t ftdm_boost_connection_open(ftdm_span_t *span)
1782 {
1783         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1784         if (sangoma_boost_data->sigmod) {
1785                 if (sangoma_boost_data->sigmod->start_span(span) != FTDM_SUCCESS) {
1786                         return FTDM_FAIL;
1787                 }
1788                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
1789                 ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
1790                 ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
1791         } 
1792 
1793         sangoma_boost_data->pcon = sangoma_boost_data->mcon;
1794 
1795         /* when sigmod is present, all arguments: local_ip etc, are ignored by sangomabc_connection_open */
1796         if (sangomabc_connection_open(&sangoma_boost_data->mcon,
1797                                                                   sangoma_boost_data->mcon.cfg.local_ip,
1798                                                                   sangoma_boost_data->mcon.cfg.local_port,
1799                                                                   sangoma_boost_data->mcon.cfg.remote_ip,
1800                                                                   sangoma_boost_data->mcon.cfg.remote_port) < 0) {
1801                 ftdm_log(FTDM_LOG_ERROR, "Error: Opening MCON Socket [%d] %s\n", sangoma_boost_data->mcon.socket, strerror(errno));
1802                 return FTDM_FAIL;
1803         }
1804 
1805         if (sangomabc_connection_open(&sangoma_boost_data->pcon,
1806                                                           sangoma_boost_data->pcon.cfg.local_ip,
1807                                                           ++sangoma_boost_data->pcon.cfg.local_port,
1808                                                           sangoma_boost_data->pcon.cfg.remote_ip,
1809                                                           ++sangoma_boost_data->pcon.cfg.remote_port) < 0) {
1810                 ftdm_log(FTDM_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
1811                 return FTDM_FAIL;
1812         }
1813 
1814         /* try to create the boost sockets interrupt objects */
1815         if (ftdm_interrupt_create(&sangoma_boost_data->pcon.sock_interrupt, sangoma_boost_data->pcon.socket) != FTDM_SUCCESS) {
1816                 ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost msock interrupt!\n", span->name);
1817                 return FTDM_FAIL;
1818         }
1819 
1820         if (ftdm_interrupt_create(&sangoma_boost_data->mcon.sock_interrupt, sangoma_boost_data->mcon.socket) != FTDM_SUCCESS) {
1821                 ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost psock interrupt!\n", span->name);
1822                 return FTDM_FAIL;
1823         }
1824 
1825         return FTDM_SUCCESS;
1826 }
1827 
1828 /*! 
1829   \brief wait for a boost event 
1830   \return -1 on error, 0 on timeout, 1 when there are events
1831  */
1832 static int ftdm_boost_wait_event(ftdm_span_t *span)
1833 {
1834                 ftdm_status_t res;
1835                 ftdm_interrupt_t *ints[3];
1836                 int numints;
1837                 ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1838 
1839                 ftdm_queue_get_interrupt(span->pendingchans, &ints[0]);
1840                 numints = 1;
1841                 /* if in queue mode wait for both the pendingchans queue and the boost msg queue */
1842                 if (sangoma_boost_data->sigmod) {
1843                         ftdm_queue_get_interrupt(sangoma_boost_data->boost_queue, &ints[1]);
1844                         numints = 2;
1845                 } 
1846 #ifndef __WINDOWS__
1847                 else {
1848                         /* socket mode ... */
1849                         ints[1] = sangoma_boost_data->mcon.sock_interrupt;
1850                         ints[2] = sangoma_boost_data->pcon.sock_interrupt;
1851                         numints = 3;
1852                         sangoma_boost_data->iteration = 0;
1853                 }
1854 #endif
1855                 res = ftdm_interrupt_multiple_wait(ints, numints, 100);
1856                 if (FTDM_SUCCESS != res && FTDM_TIMEOUT != res) {
1857                         ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res);
1858                         return -1;
1859                 }
1860                 return 0;
1861 }
1862 
1863 
1864 static sangomabc_event_t *ftdm_boost_read_event(ftdm_span_t *span)
1865 {
1866         sangomabc_event_t *event = NULL;
1867         sangomabc_connection_t *mcon, *pcon;
1868         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1869 
1870         mcon = &sangoma_boost_data->mcon;
1871         pcon = &sangoma_boost_data->pcon;
1872 
1873         event = sangomabc_connection_readp(pcon, sangoma_boost_data->iteration);
1874 
1875         /* if there is no event and this is not a sigmod-driven span it's time to try the other connection for events */
1876         if (!event && !sangoma_boost_data->sigmod) {
1877                 event = sangomabc_connection_read(mcon, sangoma_boost_data->iteration);
1878         }
1879 
1880         return event;
1881 }
1882 
1883 /**
1884  * \brief Main thread function for sangoma boost span (monitor)
1885  * \param me Current thread
1886  * \param obj Span to run in this thread
1887  */
1888 static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
1889 {
1890         ftdm_span_t *span = (ftdm_span_t *) obj;
1891         sangomabc_connection_t *mcon, *pcon;
1892         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1893 
1894         mcon = &sangoma_boost_data->mcon;
1895         pcon = &sangoma_boost_data->pcon;       
1896 
1897         /* sigmod overrides socket functionality if not null */
1898         if (sangoma_boost_data->sigmod) {
1899                 mcon->span = span;
1900                 pcon->span = span;
1901                 /* everything could be retrieved through span, but let's use shortcuts */
1902                 mcon->sigmod = sangoma_boost_data->sigmod;
1903                 pcon->sigmod = sangoma_boost_data->sigmod;
1904                 mcon->boost_queue = sangoma_boost_data->boost_queue;
1905                 pcon->boost_queue = sangoma_boost_data->boost_queue;
1906         }
1907 
1908         if (ftdm_boost_connection_open(span) != FTDM_SUCCESS) {
1909                 ftdm_log(FTDM_LOG_CRIT, "ftdm_boost_connection_open failed\n");
1910                 goto end;
1911         }
1912 
1913         init_outgoing_array();
1914         if (!sangoma_boost_data->sigmod) {
1915                 sangomabc_exec_commandp(pcon,
1916                                                    0,
1917                                                    0,
1918                                                    -1,
1919                                                    SIGBOOST_EVENT_SYSTEM_RESTART,
1920                                                    0);
1921                 ftdm_set_flag(mcon, MSU_FLAG_DOWN);
1922         }
1923 
1924         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) {
1925                 sangomabc_event_t *event = NULL;
1926                 
1927                 if (!ftdm_running()) {
1928                         if (!sangoma_boost_data->sigmod) {
1929                                 sangomabc_exec_commandp(pcon,
1930                                                                    0,
1931                                                                    0,
1932                                                                    -1,
1933                                                                    SIGBOOST_EVENT_SYSTEM_RESTART,
1934                                                                    0);
1935                                 ftdm_set_flag(mcon, MSU_FLAG_DOWN);
1936                         }
1937                         ftdm_log(FTDM_LOG_DEBUG, "ftdm is no longer running\n");
1938                         break;
1939                 }
1940 
1941                 if (ftdm_boost_wait_event(span) < 0) {
1942                         ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n");
1943                 }
1944                 
1945                 while ((event = ftdm_boost_read_event(span))) {
1946                         parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
1947                         sangoma_boost_data->iteration++;
1948                 }
1949                 
1950                 check_state(span);
1951         }
1952 
1953 end:
1954         if (!sangoma_boost_data->sigmod) {
1955                 sangomabc_connection_close(&sangoma_boost_data->mcon);
1956                 sangomabc_connection_close(&sangoma_boost_data->pcon);
1957         }
1958 
1959         ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
1960 
1961         ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost thread ended.\n");
1962         return NULL;
1963 }
1964 
1965 #if 0
1966 static int sigmod_ss7box_isup_exec_cmd(ftdm_stream_handle_t *stream, char *cmd)
1967 {
1968         FILE *fp;
1969         int status=0;
1970         char path[1024];
1971         
1972         fp = popen(cmd, "r");
1973         if (fp == NULL) {
1974                 stream->write_function(stream, "%s: -ERR failed to execute cmd: %s\n",
1975                                 __FILE__,cmd);
1976                 return -1;
1977         }
1978         
1979         while (fgets(path, sizeof(path)-1, fp) != NULL) {
1980                 path[sizeof(path)-1]='\0';
1981                 stream->write_function(stream,"%s", path);
1982         }
1983         
1984         
1985         status = pclose(fp);
1986         if (status == -1) {
1987                 /* Error reported by pclose() */
1988         } else {
1989                 /* Use macros described under wait() to inspect `status' in order
1990                 to determine success/failure of command executed by popen() */
1991         }
1992 
1993         return status;
1994 }
1995 #endif
1996 
1997 static void ftdm_cli_span_state_cmd(ftdm_span_t *span, char *state)
1998 {
1999         unsigned int j;
2000         int cnt=0;
2001         ftdm_channel_state_t state_e = ftdm_str2ftdm_channel_state(state);
2002         if (state_e == FTDM_CHANNEL_STATE_INVALID) {
2003                 ftdm_log(FTDM_LOG_CRIT, "Checking for channels not in the INVALID state is probably not what you want\n");
2004         }
2005         for(j = 1; j <= span->chan_count; j++) {
2006                 if (span->channels[j]->state != state_e) {
2007                         ftdm_channel_t *ftdmchan = span->channels[j];
2008                         ftdm_log(FTDM_LOG_CRIT, "Channel %i s%dc%d State=%s\n",
2009                                 j, ftdmchan->physical_span_id-1, ftdmchan->physical_chan_id-1, ftdm_channel_state2str(ftdmchan->state));
2010                         cnt++;
2011                 }
2012         }
2013         ftdm_log(FTDM_LOG_CRIT, "Total Channel Cnt %i\n",cnt);
2014 }
2015 
2016 #define FTDM_BOOST_SYNTAX "list sigmods | <sigmod_name> <command> | tracelevel <span> <level>"
2017 /**
2018  * \brief API function to kill or debug a sangoma_boost span
2019  * \param stream API stream handler
2020  * \param data String containing argurments
2021  * \return Flags
2022  */
2023 static FIO_API_FUNCTION(ftdm_sangoma_boost_api)
2024 {
2025         char *mycmd = NULL, *argv[10] = { 0 };
2026         int argc = 0;
2027 
2028         if (data) {
2029                 mycmd = ftdm_strdup(data);
2030                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
2031         }
2032 
2033         if (argc > 1) {
2034                 if (!strcasecmp(argv[0], "list")) {
2035                         if (!strcasecmp(argv[1], "sigmods")) {
2036                                 if (ftdm_sangoma_boost_list_sigmods(stream) != FTDM_SUCCESS) {
2037                                         stream->write_function(stream, "-ERR failed to list sigmods\n");
2038                                         goto done;
2039                                 }
2040                                 goto done;
2041                         }
2042 
2043                         if (!strcasecmp(argv[1], "ids")) {
2044                                 print_request_ids();
2045                                 goto done;
2046                         }
2047                 } else if (!strcasecmp(argv[0], "tracelevel")) {
2048                         ftdm_status_t status;
2049                         const char *levelname = NULL;
2050                         int dbglevel;
2051                         ftdm_sangoma_boost_data_t *sangoma_boost_data;
2052                         ftdm_span_t *span;
2053 
2054                         if (argc <= 2) {
2055                                 stream->write_function(stream, "-ERR usage: tracelevel <span> <level>\n");
2056                                 goto done;
2057                         }
2058 
2059                         status = ftdm_span_find_by_name(argv[1], &span);
2060                         if (FTDM_SUCCESS != status) {
2061                                 stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[1]);
2062                                 goto done;
2063                         }
2064 
2065                         if (span->signal_type != FTDM_SIGTYPE_SANGOMABOOST) {
2066                                 stream->write_function(stream, "-ERR span %s is not of boost type\n", argv[1]);
2067                                 goto done;
2068                         }
2069 
2070                         for (dbglevel = 0; (levelname = FTDM_LEVEL_NAMES[dbglevel]); dbglevel++) {
2071                                 if (!strcasecmp(levelname, argv[2])) {
2072                                         break;
2073                                 }
2074                         }
2075 
2076                         if (!levelname) {
2077                                 stream->write_function(stream, "-ERR invalid log level %s\n", argv[2]);
2078                                 goto done;
2079                         }
2080 
2081                         sangoma_boost_data = span->signal_data;
2082                         sangoma_boost_data->pcon.debuglevel = dbglevel;
2083                         sangoma_boost_data->mcon.debuglevel = dbglevel;
2084                         stream->write_function(stream, "+OK span %s has now trace level %s\n", argv[1], FTDM_LEVEL_NAMES[dbglevel]);
2085                         goto done;
2086 #ifndef __WINDOWS__
2087 #if 0
2088 /* NC: This code crashes the kernel due to fork on heavy fs load */
2089                 } else if (!strcasecmp(argv[0], "ss7box_isupd_ckt")) {
2090                 
2091                         if (!strcasecmp(argv[1], "used")) {
2092                                 stream->write_function(stream, "ss7box_isupd: in use\n", FTDM_BOOST_SYNTAX);
2093                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh inuse");
2094                         } else if (!strcasecmp(argv[1], "reset")) {
2095                                 stream->write_function(stream, "ss7box_isupd: in reset\n", FTDM_BOOST_SYNTAX);
2096                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh reset");
2097                         } else if (!strcasecmp(argv[1], "ready")) {
2098                                 stream->write_function(stream, "ss7box_isupd: ready \n", FTDM_BOOST_SYNTAX);
2099                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh free");
2100                         } else {
2101                                 stream->write_function(stream, "ss7box_isupd: list\n", FTDM_BOOST_SYNTAX);
2102                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh");
2103                         }
2104 
2105                         goto done;
2106 #endif
2107 #endif
2108 
2109                 } else if (!strcasecmp(argv[0], "span")) {
2110                         int err;
2111                         sangomabc_connection_t *pcon;
2112                         ftdm_sangoma_boost_data_t *sangoma_boost_data;
2113                         ftdm_span_t *span;
2114 
2115                         if (argc <= 2) {
2116                                 stream->write_function(stream, "-ERR invalid span usage: span <name> <cmd>\n");
2117                                 goto done;
2118                         }
2119 
2120                         err = ftdm_span_find_by_name(argv[1], &span);
2121                         if (FTDM_SUCCESS != err) {
2122                                 stream->write_function(stream, "-ERR failed to find span by name %s\n",argv[1]);
2123                                 goto done;
2124                         }
2125 
2126                         if (!strcasecmp(argv[2], "restart")) {
2127                                 sangoma_boost_data = span->signal_data;
2128                                 pcon = &sangoma_boost_data->pcon;
2129 
2130                                 /* No need to set any span flags because
2131                            our RESTART will generate a RESTART from the sig daemon */
2132                                 sangomabc_exec_commandp(pcon,
2133                                                    0,
2134                                                    0,
2135                                                    -1,
2136                                                    SIGBOOST_EVENT_SYSTEM_RESTART,
2137                                                    0);          
2138                         } else if (!strcasecmp(argv[2], "state")) {
2139                                 if (argc <= 3) {
2140                                         stream->write_function(stream, "-ERR invalid span state: span <name> state <state name>\n");
2141                                         goto done;
2142                                 }
2143                                 ftdm_cli_span_state_cmd(span,argv[3]);
2144                         }
2145 
2146                         goto done;
2147 
2148                 } else {
2149                         boost_sigmod_interface_t *sigmod_iface = NULL;
2150                         sigmod_iface = hashtable_search(g_boost_modules_hash, argv[0]);
2151                         if (sigmod_iface) {
2152                                 char *p = strchr(data, ' ');
2153                                 if (++p) {
2154                                         char* mydup = strdup(p);
2155                                         if(sigmod_iface->exec_api == NULL) {
2156                                                 stream->write_function(stream, "%s does not support api functions\n", sigmod_iface->name);
2157                                                 goto done;
2158                                         }
2159                                         //stream->write_function(stream, "sigmod:%s command:%s\n", sigmod_iface->name, mydup);
2160                                         if (sigmod_iface->exec_api(stream, mydup) != FTDM_SUCCESS) {
2161                                                 stream->write_function(stream, "-ERR:failed to execute command:%s\n", mydup);
2162                                         }
2163                                         free(mydup);
2164                                 }
2165                                 
2166                                 goto done;
2167                         } else {
2168                                 stream->write_function(stream, "-ERR: Could not find sigmod %s\n", argv[0]);
2169                         }
2170                 }
2171         }
2172         stream->write_function(stream, "-ERR: Usage: %s\n", FTDM_BOOST_SYNTAX);
2173 done:
2174         ftdm_safe_free(mycmd);
2175         return FTDM_SUCCESS;
2176 }
2177 
2178 /**
2179  * \brief Loads sangoma_boost IO module
2180  * \param fio FreeTDM IO interface
2181  * \return Success
2182  */
2183 static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_boost_io_init)
2184 {
2185         ftdm_assert(fio != NULL, "fio is NULL");
2186         memset(&ftdm_sangoma_boost_interface, 0, sizeof(ftdm_sangoma_boost_interface));
2187 
2188         ftdm_sangoma_boost_interface.name = "boost";
2189         ftdm_sangoma_boost_interface.api = ftdm_sangoma_boost_api;
2190 
2191         *fio = &ftdm_sangoma_boost_interface;
2192 
2193         return FTDM_SUCCESS;
2194 }
2195 
2196 /**
2197  * \brief Loads sangoma boost signaling module
2198  * \param fio FreeTDM IO interface
2199  * \return Success
2200  */
2201 static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_boost_init)
2202 {
2203         g_boost_modules_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
2204         if (!g_boost_modules_hash) {
2205                 return FTDM_FAIL;
2206         }
2207         ftdm_mutex_create(&request_mutex);
2208         ftdm_mutex_create(&g_boost_modules_mutex);
2209         memset(&g_trunkgroups[0], 0, sizeof(g_trunkgroups));
2210         return FTDM_SUCCESS;
2211 }
2212 
2213 static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_boost_destroy)
2214 {
2215         ftdm_hash_iterator_t *i = NULL;
2216         boost_sigmod_interface_t *sigmod = NULL;
2217         const void *key = NULL;
2218         void *val = NULL;
2219         ftdm_dso_lib_t lib;
2220         ftdm_log(FTDM_LOG_DEBUG, "Destroying sangoma boost module\n");
2221         for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
2222                 hashtable_this(i, &key, NULL, &val);
2223                 if (key && val) {
2224                         sigmod = val;
2225                         lib = sigmod->pvt;
2226                         ftdm_log(FTDM_LOG_DEBUG, "destroying sigmod %s\n", sigmod->name);
2227                         sigmod->on_unload();
2228                         ftdm_dso_destroy(&lib);
2229                 }
2230         }
2231 
2232         hashtable_destroy(g_boost_modules_hash);
2233         ftdm_mutex_destroy(&request_mutex);
2234         ftdm_mutex_destroy(&g_boost_modules_mutex);
2235         return FTDM_SUCCESS;
2236 }
2237 
2238 static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span)
2239 {
2240         int err;
2241 
2242         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2243 
2244         ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
2245         err = ftdm_thread_create_detached(ftdm_sangoma_boost_run, span);
2246         if (err) {
2247                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
2248                 return err;
2249         }
2250 
2251         // launch the events thread to handle HW DTMF and possibly
2252         // other events in the future
2253         ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
2254         err = ftdm_thread_create_detached(ftdm_sangoma_events_run, span);
2255         if (err) {
2256                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
2257                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
2258         }
2259 
2260         return err;
2261 }
2262 
2263 static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span)
2264 {
2265         int cnt = 50;
2266         ftdm_status_t status = FTDM_SUCCESS;
2267         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2268 
2269         if (sangoma_boost_data->sigmod) {
2270                 /* I think stopping the span before destroying the queue makes sense
2271                    otherwise may be boost events would still arrive when the queue is already destroyed! */
2272                 status = sangoma_boost_data->sigmod->stop_span(span);
2273                 if (status != FTDM_SUCCESS) {
2274                         ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s boost signaling\n", span->name);
2275                         return FTDM_FAIL;
2276                 }
2277                 ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL);
2278         }
2279 
2280         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) {
2281                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost thread\n");
2282                 ftdm_sleep(100);
2283         }
2284 
2285         if (!cnt) {
2286                 ftdm_log(FTDM_LOG_CRIT, "it seems boost thread in span %s may be stuck, we may segfault :-(\n", span->name);
2287                 return FTDM_FAIL;
2288         }
2289 
2290         cnt = 50;
2291         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && cnt-- > 0) {
2292                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost events thread\n");
2293                 ftdm_sleep(100);
2294         }
2295 
2296         if (!cnt) {
2297                 ftdm_log(FTDM_LOG_CRIT, "it seems boost events thread in span %s may be stuck, we may segfault :-(\n", span->name);
2298                 return FTDM_FAIL;
2299         }
2300 
2301         if (sangoma_boost_data->sigmod) {
2302                 ftdm_queue_destroy(&sangoma_boost_data->boost_queue);
2303         }
2304 
2305         return status;
2306 }
2307 
2308 static ftdm_state_map_t boost_state_map = {
2309         {
2310                 {
2311                         ZSD_OUTBOUND,
2312                         ZSM_UNACCEPTABLE,
2313                         {FTDM_ANY_STATE},
2314                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
2315                 },
2316                 {
2317                         ZSD_OUTBOUND,
2318                         ZSM_UNACCEPTABLE,
2319                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
2320                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
2321                 },
2322                 {
2323                         ZSD_OUTBOUND,
2324                         ZSM_UNACCEPTABLE,
2325                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2326                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_HOLD, FTDM_END}
2327                 },
2328                 {
2329                         ZSD_OUTBOUND,
2330                         ZSM_UNACCEPTABLE,
2331                         {FTDM_CHANNEL_STATE_HOLD, FTDM_END},
2332                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, 
2333                          FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
2334                 },
2335                 {
2336                         ZSD_OUTBOUND,
2337                         ZSM_UNACCEPTABLE,
2338                         {FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
2339                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
2340                 },
2341                 {
2342                         ZSD_OUTBOUND,
2343                         ZSM_UNACCEPTABLE,
2344                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
2345                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
2346                 },
2347                 {
2348                         ZSD_OUTBOUND,
2349                         ZSM_UNACCEPTABLE,
2350                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2351                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
2352                 },
2353                 {
2354                         ZSD_OUTBOUND,
2355                         ZSM_UNACCEPTABLE,
2356                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
2357                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2358                 },
2359                 {
2360                         ZSD_OUTBOUND,
2361                         ZSM_UNACCEPTABLE,
2362                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
2363                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
2364                 },
2365 
2366                 /****************************************/
2367                 {
2368                         ZSD_INBOUND,
2369                         ZSM_UNACCEPTABLE,
2370                         {FTDM_ANY_STATE},
2371                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
2372                 },
2373                 {
2374                         ZSD_INBOUND,
2375                         ZSM_UNACCEPTABLE,
2376                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
2377                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
2378                 },
2379                 {
2380                         ZSD_INBOUND,
2381                         ZSM_UNACCEPTABLE,
2382                         {FTDM_CHANNEL_STATE_DOWN},
2383                         {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
2384                 },
2385                 {
2386                         ZSD_INBOUND,
2387                         ZSM_UNACCEPTABLE,
2388                         {FTDM_CHANNEL_STATE_IN_LOOP},
2389                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
2390                 },
2391                 {
2392                         ZSD_INBOUND,
2393                         ZSM_UNACCEPTABLE,
2394                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2395                         {FTDM_CHANNEL_STATE_RING, FTDM_END}
2396                 },
2397                 {
2398                         ZSD_INBOUND,
2399                         ZSM_UNACCEPTABLE,
2400                         {FTDM_CHANNEL_STATE_RING, FTDM_END},
2401                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,FTDM_END}
2402                 },
2403                 {
2404                         ZSD_INBOUND,
2405                         ZSM_UNACCEPTABLE,
2406                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2407                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
2408                 },
2409                 {
2410                         ZSD_INBOUND,
2411                         ZSM_UNACCEPTABLE,
2412                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2413                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2414                 },
2415                 {
2416                         ZSD_INBOUND,
2417                         ZSM_UNACCEPTABLE,
2418                         {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
2419                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
2420                 },
2421                 {
2422                         ZSD_INBOUND,
2423                         ZSM_UNACCEPTABLE,
2424                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
2425                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2426                 },
2427                 
2428 
2429         }
2430 };
2431 
2432 static BOOST_WRITE_MSG_FUNCTION(ftdm_boost_write_msg)
2433 {
2434         sangomabc_short_event_t *shortmsg = NULL;
2435         ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
2436         sangomabc_queue_element_t *element = NULL;
2437 
2438         ftdm_assert_return(msg != NULL, FTDM_FAIL, "Boost message to write was null");
2439 
2440         if (!span) {
2441                 shortmsg = msg;
2442                 ftdm_log(FTDM_LOG_ERROR, "Unexpected boost message %d\n", shortmsg->event_id);
2443                 return FTDM_FAIL;
2444         }
2445         /* duplicate the event and enqueue it */
2446         element = ftdm_calloc(1, sizeof(*element));
2447         if (!element) {
2448                 return FTDM_FAIL;
2449         }
2450         memcpy(element->boostmsg, msg, msglen);
2451         element->size = msglen;
2452 
2453         sangoma_boost_data = span->signal_data;
2454         return ftdm_queue_enqueue(sangoma_boost_data->boost_queue, element);
2455 }
2456 
2457 static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
2458 {
2459         ftdm_sigmsg_t sig;
2460         ftdm_log(FTDM_LOG_NOTICE, "%d:%d Signaling link status changed to %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_signaling_status2str(status));
2461         
2462         memset(&sig, 0, sizeof(sig));
2463         sig.chan_id = ftdmchan->chan_id;
2464         sig.span_id = ftdmchan->span_id;
2465         sig.channel = ftdmchan;
2466         sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
2467         sig.ev_data.sigstatus.status = status;
2468         ftdm_span_send_signal(ftdmchan->span, &sig);
2469         return;
2470 }
2471 
2472 static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_channel_sig_status)
2473 {
2474         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
2475         if (!sangoma_boost_data->sigmod) {
2476                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel with no signaling module configured\n");
2477                 return FTDM_FAIL;
2478         }
2479         if (!sangoma_boost_data->sigmod->set_channel_sig_status) {
2480                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel: method not implemented\n");
2481                 return FTDM_NOTIMPL;
2482         }
2483         return sangoma_boost_data->sigmod->set_channel_sig_status(ftdmchan, status);
2484 }
2485 
2486 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_channel_sig_status)
2487 {
2488         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
2489         if (!sangoma_boost_data->sigmod) {
2490                 return FTDM_FAIL;
2491         }
2492         if (!sangoma_boost_data->sigmod->get_channel_sig_status) {
2493                 return FTDM_NOTIMPL;
2494         }
2495         return sangoma_boost_data->sigmod->get_channel_sig_status(ftdmchan, status);
2496 }
2497 
2498 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_span_sig_status)
2499 {
2500         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2501         if (!sangoma_boost_data->sigmod) {
2502                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span with no signaling module configured\n");
2503                 return FTDM_FAIL;
2504         }
2505         if (!sangoma_boost_data->sigmod->set_span_sig_status) {
2506                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span: method not implemented\n");
2507                 return FTDM_NOTIMPL;
2508         }
2509         return sangoma_boost_data->sigmod->set_span_sig_status(span, status);
2510 }
2511 
2512 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_span_sig_status)
2513 {
2514         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2515         if (!sangoma_boost_data->sigmod) {
2516                 return FTDM_FAIL;
2517         }
2518         if (!sangoma_boost_data->sigmod->get_span_sig_status) {
2519                 ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost span: method not implemented\n");
2520                 return FTDM_NOTIMPL;
2521         }
2522         return sangoma_boost_data->sigmod->get_span_sig_status(span, status);
2523 }
2524 
2525 /**
2526  * \brief Initialises an sangoma boost span from configuration variables
2527  * \param span Span to configure
2528  * \param sig_cb Callback function for event signals
2529  * \param ap List of configuration variables
2530  * \return Success or failure
2531  */
2532 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
2533 {
2534 #define FAIL_CONFIG_RETURN(retstatus) \
2535                 if (sangoma_boost_data) \
2536                         ftdm_safe_free(sangoma_boost_data); \
2537                 if (err) \
2538                         ftdm_safe_free(err) \
2539                 if (hash_locked) \
2540                         ftdm_mutex_unlock(g_boost_modules_mutex); \
2541                 if (lib) \
2542                         ftdm_dso_destroy(&lib); \
2543                 return retstatus;
2544 
2545         boost_sigmod_interface_t *sigmod_iface = NULL;
2546         ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
2547         const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
2548         const char *sigmod = NULL;
2549         int local_port = 53000, remote_port = 53000;
2550         const char *var = NULL, *val = NULL;
2551         int hash_locked = 0;
2552         ftdm_dso_lib_t lib = NULL;
2553         char path[255] = "";
2554         char *err = NULL;
2555         unsigned int j = 0;
2556         unsigned paramindex = 0;
2557         ftdm_status_t rc = FTDM_SUCCESS;
2558 
2559         for (; ftdm_parameters[paramindex].var; paramindex++) {
2560                 var = ftdm_parameters[paramindex].var;
2561                 val = ftdm_parameters[paramindex].val;
2562                 if (!strcasecmp(var, "sigmod")) {
2563                         sigmod = val;
2564                 } else if (!strcasecmp(var, "local_ip")) {
2565                         local_ip = val;
2566                 } else if (!strcasecmp(var, "remote_ip")) {
2567                         remote_ip = val;
2568                 } else if (!strcasecmp(var, "local_port")) {
2569                         local_port = atoi(val);
2570                 } else if (!strcasecmp(var, "remote_port")) {
2571                         remote_port = atoi(val);
2572                 } else if (!strcasecmp(var, "outbound-called-ton")) {
2573                         ftdm_set_ton(val, &span->default_caller_data.dnis.type);
2574                 } else if (!strcasecmp(var, "outbound-called-npi")) {
2575                         ftdm_set_npi(val, &span->default_caller_data.dnis.plan);
2576                 } else if (!strcasecmp(var, "outbound-calling-ton")) {
2577                         ftdm_set_ton(val, &span->default_caller_data.cid_num.type);
2578                 } else if (!strcasecmp(var, "outbound-calling-npi")) {
2579                         ftdm_set_npi(val, &span->default_caller_data.cid_num.plan);
2580                 } else if (!strcasecmp(var, "outbound-rdnis-ton")) {
2581                         ftdm_set_ton(val, &span->default_caller_data.rdnis.type);
2582                 } else if (!strcasecmp(var, "outbound-rdnis-npi")) {
2583                         ftdm_set_npi(val, &span->default_caller_data.rdnis.plan);
2584                 } else if (!sigmod) {
2585                         snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
2586                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2587                 }
2588         }
2589 
2590         if (!sigmod) {
2591 #ifndef HAVE_NETINET_SCTP_H
2592                 ftdm_log(FTDM_LOG_CRIT, "No sigmod attribute in span %s, you must either specify a sigmod or re-compile with SCTP available to use socket mode boost!\n", span->name);
2593                 ftdm_set_string(span->last_error, "No sigmod configuration was set and there is no SCTP available!");
2594                 FAIL_CONFIG_RETURN(FTDM_FAIL);
2595 #else
2596                 if (!local_ip && local_port && remote_ip && remote_port && sig_cb) {
2597                         ftdm_set_string(span->last_error, "missing Sangoma boost IP parameters");
2598                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2599                 }
2600 #endif
2601         }
2602 
2603         sangoma_boost_data = ftdm_calloc(1, sizeof(*sangoma_boost_data));
2604         if (!sangoma_boost_data) {
2605                 FAIL_CONFIG_RETURN(FTDM_FAIL);
2606         }
2607 
2608         /* WARNING: be sure to release this mutex on errors inside this if() */
2609         ftdm_mutex_lock(g_boost_modules_mutex);
2610         hash_locked = 1;
2611         if (sigmod && !(sigmod_iface = hashtable_search(g_boost_modules_hash, (void *)sigmod))) {
2612                 ftdm_build_dso_path(sigmod, path, sizeof(path));        
2613                 lib = ftdm_dso_open(path, &err);
2614                 if (!lib) {
2615                         ftdm_log(FTDM_LOG_ERROR, "Error loading Sangoma boost signaling module '%s': %s\n", path, err);
2616                         snprintf(span->last_error, sizeof(span->last_error), "Failed to load sangoma boost signaling module %s", path);
2617 
2618                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2619                 }
2620                 if (!(sigmod_iface = (boost_sigmod_interface_t *)ftdm_dso_func_sym(lib, BOOST_INTERFACE_NAME_STR, &err))) {
2621                         ftdm_log(FTDM_LOG_ERROR, "Failed to read Sangoma boost signaling module interface '%s': %s\n", path, err);
2622                         snprintf(span->last_error, sizeof(span->last_error), "Failed to read Sangoma boost signaling module interface '%s': %s", path, err);
2623 
2624                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2625                 }
2626                 rc = sigmod_iface->on_load();
2627                 if (rc != FTDM_SUCCESS) {
2628                         ftdm_log(FTDM_LOG_ERROR, "Failed to load Sangoma boost signaling module interface '%s': on_load method failed (%d)\n", path, rc);
2629                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2630                 }
2631                 sigmod_iface->pvt = lib;
2632                 sigmod_iface->set_write_msg_cb(ftdm_boost_write_msg);
2633                 sigmod_iface->set_sig_status_cb(ftdm_boost_sig_status_change);
2634                 hashtable_insert(g_boost_modules_hash, (void *)sigmod_iface->name, sigmod_iface, HASHTABLE_FLAG_NONE);
2635                 lib = NULL; /* destroying the lib will be done when going down and NOT on FAIL_CONFIG_RETURN */
2636         }
2637         ftdm_mutex_unlock(g_boost_modules_mutex);
2638         hash_locked = 0;
2639 
2640         if (sigmod_iface) {
2641                 /* try to create the boost queue */
2642                 if (ftdm_queue_create(&sangoma_boost_data->boost_queue, BOOST_QUEUE_SIZE) != FTDM_SUCCESS) {
2643                         ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost queue!\n", span->name);
2644                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2645                 }
2646                 ftdm_log(FTDM_LOG_NOTICE, "Span %s will use Sangoma Boost Signaling Module %s\n", span->name, sigmod_iface->name);
2647                 sangoma_boost_data->sigmod = sigmod_iface;
2648                 sigmod_iface->configure_span(span, ftdm_parameters);
2649         } else {
2650                 ftdm_log(FTDM_LOG_NOTICE, "Span %s will use boost socket mode\n", span->name);
2651                 ftdm_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
2652                 sangoma_boost_data->mcon.cfg.local_port = local_port;
2653                 ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
2654                 sangoma_boost_data->mcon.cfg.remote_port = remote_port;
2655         }
2656 
2657         for (j = 1; j <= span->chan_count; j++) {
2658                 span->channels[j]->call_data = ftdm_calloc(1, sizeof(sangoma_boost_call_t));
2659                 if (!span->channels[j]->call_data) {
2660                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2661                 }
2662         }
2663 
2664         span->signal_cb = sig_cb;
2665         span->start = ftdm_sangoma_boost_start;
2666         span->stop = ftdm_sangoma_boost_stop;
2667         span->signal_data = sangoma_boost_data;
2668         span->signal_type = FTDM_SIGTYPE_SANGOMABOOST;
2669         span->outgoing_call = sangoma_boost_outgoing_call;
2670         span->channel_request = sangoma_boost_channel_request;
2671         span->get_channel_sig_status = sangoma_boost_get_channel_sig_status;
2672         span->set_channel_sig_status = sangoma_boost_set_channel_sig_status;
2673         span->get_span_sig_status = sangoma_boost_get_span_sig_status;
2674         span->set_span_sig_status = sangoma_boost_set_span_sig_status;
2675         span->state_map = &boost_state_map;
2676         span->state_processor = state_advance;
2677         sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
2678         sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
2679         ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
2680         ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
2681         if (sigmod_iface) {
2682                 /* the core will do the hunting */
2683                 span->channel_request = NULL;
2684         } 
2685         ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
2686         return FTDM_SUCCESS;
2687 }
2688 
2689 static ftdm_status_t ftdm_sangoma_boost_list_sigmods(ftdm_stream_handle_t *stream)
2690 {
2691         ftdm_hash_iterator_t *i = NULL;
2692         boost_sigmod_interface_t *sigmod_iface = NULL;
2693         const void *key = NULL;
2694         void *val = NULL;
2695 
2696         stream->write_function(stream, "List of loaded sigmod modules:\n");
2697         for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
2698                 hashtable_this(i, &key, NULL, &val);
2699                 if (key && val) {
2700                         sigmod_iface = val;
2701                         stream->write_function(stream, "  %s\n", sigmod_iface->name);
2702                 }
2703         }
2704         stream->write_function(stream, "\n");
2705         return FTDM_SUCCESS;
2706 }
2707 
2708 /**
2709  * \brief FreeTDM sangoma boost signaling module definition
2710  */
2711 EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
2712         /*.name =*/ "sangoma_boost",
2713         /*.io_load =*/ ftdm_sangoma_boost_io_init,
2714         /*.io_unload =*/ NULL,
2715         /*.sig_load = */ ftdm_sangoma_boost_init,
2716         /*.sig_configure =*/ NULL,
2717         /*.sig_unload = */ftdm_sangoma_boost_destroy,
2718         /*.configure_span_signaling = */ ftdm_sangoma_boost_configure_span
2719 };
2720 
2721 /* For Emacs:
2722  * Local Variables:
2723  * mode:c
2724  * indent-tabs-mode:t
2725  * tab-width:4
2726  * c-basic-offset:4
2727  * End:
2728  * For VIM:
2729  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
2730  */

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