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. advance_chan_states
  28. init_outgoing_array
  29. check_state
  30. check_events
  31. ftdm_sangoma_events_run
  32. ftdm_boost_connection_open
  33. ftdm_boost_wait_event
  34. ftdm_boost_read_event
  35. ftdm_sangoma_boost_run
  36. sigmod_ss7box_isup_exec_cmd
  37. ftdm_cli_span_state_cmd
  38. FIO_API_FUNCTION
  39. FIO_IO_LOAD_FUNCTION
  40. FIO_SIG_LOAD_FUNCTION
  41. FIO_SIG_UNLOAD_FUNCTION
  42. ftdm_sangoma_boost_start
  43. ftdm_sangoma_boost_stop
  44. BOOST_WRITE_MSG_FUNCTION
  45. BOOST_SIG_STATUS_CB_FUNCTION
  46. FIO_CHANNEL_SET_SIG_STATUS_FUNCTION
  47. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  48. FIO_SPAN_SET_SIG_STATUS_FUNCTION
  49. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  50. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
  51. 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 //DAVIDY 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_done(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 advance_chan_states(ftdm_channel_t *ftdmchan);
 955 static __inline__ void stop_loop(ftdm_channel_t *ftdmchan);
 956 
 957 /**
 958  * \brief Handler for call start event
 959  * \param span Span where event was fired
 960  * \param mcon sangoma boost connection
 961  * \param event Event to handle
 962  */
 963 static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
 964 {
 965         ftdm_channel_t *ftdmchan = NULL;
 966         int hangup_cause = FTDM_CAUSE_CALL_REJECTED;
 967         int retry = 1;
 968 
 969 tryagain:
 970 
 971         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
 972                 if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
 973                         int r;
 974 
 975                          /* NC: If we get CALL START and channel is in active state
 976                                 then we are completely out of sync with the other end.
 977                                     Treat CALL START as CALL STOP and hangup the current call.
 978                                         The incoming call will also be NACKed.
 979                           */
 980 
 981                         if (ftdmchan->state == FTDM_CHANNEL_STATE_UP ||
 982                                 ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
 983                                 ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) {
 984                                 ftdm_log(FTDM_LOG_CRIT, "s%dc%d: FTDMCHAN STATE UP -> Changed to TERMINATING\n", 
 985                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 986                                 ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
 987                         } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP ||  ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
 988                                 ftdm_log(FTDM_LOG_CRIT, "s%dc%d: FTDMCHAN STATE HANGUP -> Changed to HANGUP COMPLETE\n", 
 989                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 990                                 ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
 991                         } else if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 992                                 ftdm_log(FTDM_LOG_WARNING, "s%dc%d: Collision, hanging up incoming call\n", 
 993                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
 994                                 /* dont hangup the outgoing call, the other side will send a call start nack too
 995                                  * and there we will move to terminating. If we move to terminating here. We used to move
 996                                  * to terminating here, but that introduces a problem in handle_call_start_nack where
 997                                  * when receiving call start nack we move the channel from DOWN to TERMINATING ( cuz we already
 998                                  * hangup here ) and the channel gets stuck in terminating forever. So at this point we're trusting
 999                                  * the other side to send the call start nack ( or proceed with the call )
1000                                  * ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
1001                                  */
1002                         } else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) {
1003                                 retry = 0;
1004                                 stop_loop(ftdmchan);
1005                                 advance_chan_states(ftdmchan);
1006                                 goto tryagain;
1007                         } else {
1008                                 ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n", 
1009                                                 BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event), 
1010                                                 ftdm_channel_state2str(ftdmchan->state));
1011                         }
1012                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
1013                         ftdmchan = NULL;
1014                 } else {
1015                         ftdm_log(FTDM_LOG_CRIT, "s%dc%d: incoming call in invalid channel (channel not found)!\n", 
1016                                         BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1017                 }
1018                 goto error;
1019         }
1020 
1021         if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
1022                 ftdm_log(FTDM_LOG_ERROR, "s%dc%d: failed to open channel on incoming call, rejecting!\n", 
1023                         BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
1024                 goto error;
1025         }
1026         
1027         ftdm_log(FTDM_LOG_DEBUG, "Got call start from s%dc%d mapped to freetdm logical s%dc%d, physical s%dc%d\n", 
1028                         event->span, event->chan, 
1029                         ftdmchan->span_id, ftdmchan->chan_id,
1030                         ftdmchan->physical_span_id, ftdmchan->physical_chan_id);
1031 
1032         ftdmchan->sflags = 0;
1033         ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)event->calling.digits);
1034         ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling.digits);
1035         ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)event->calling.digits);
1036         ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)event->called.digits);
1037         ftdm_set_string(ftdmchan->caller_data.rdnis.digits, (char *)event->rdnis.digits);
1038         if (event->custom_data_size) {
1039                 ftdm_set_string(ftdmchan->caller_data.raw_data, event->custom_data);
1040                 ftdmchan->caller_data.raw_data_len = event->custom_data_size;
1041         }
1042 
1043         if (strlen(event->calling_name)) {
1044                 ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling_name);
1045         }
1046 
1047         ftdmchan->caller_data.cid_num.plan = event->calling.npi;
1048         ftdmchan->caller_data.cid_num.type = event->calling.ton;
1049 
1050         ftdmchan->caller_data.ani.plan = event->calling.npi;
1051         ftdmchan->caller_data.ani.type = event->calling.ton;
1052 
1053         ftdmchan->caller_data.dnis.plan = event->called.npi;
1054         ftdmchan->caller_data.dnis.type = event->called.ton;
1055 
1056         ftdmchan->caller_data.rdnis.plan = event->rdnis.npi;
1057         ftdmchan->caller_data.rdnis.type = event->rdnis.ton;
1058 
1059         ftdmchan->caller_data.screen = event->calling.screening_ind;
1060         ftdmchan->caller_data.pres = event->calling.presentation_ind;
1061 
1062         ftdmchan->caller_data.bearer_capability = event->bearer.capability;
1063         ftdmchan->caller_data.bearer_layer1 = event->bearer.uil1p;
1064 
1065         /* more info about custom data: http://www.ss7box.com/smg_manual.html#ISUP-IN-RDNIS-NEW */
1066         if (event->custom_data_size) {
1067                 char* p = NULL;
1068 
1069                 p = strstr((char*)event->custom_data,"PRI001-ANI2-");
1070                 if (p!=NULL) {
1071                         int ani2 = 0;
1072                         sscanf(p, "PRI001-ANI2-%d", &ani2);
1073                         snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", ani2);
1074                 }       
1075         }
1076 
1077         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
1078         return;
1079 
1080  error:
1081         hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
1082         sangomabc_exec_command(mcon,
1083                                                    event->span,
1084                                                    event->chan,
1085                                                    event->call_setup_id,
1086                                                    SIGBOOST_EVENT_CALL_START_NACK,
1087                                                    hangup_cause, 0);
1088                 
1089 }
1090 
1091 static void handle_call_loop_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
1092 {
1093         ftdm_status_t res = FTDM_FAIL;
1094         ftdm_channel_t *ftdmchan;
1095 
1096         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
1097                 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));
1098                 return;
1099         }
1100 
1101         if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
1102                 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));
1103                 return;
1104         }
1105 
1106         ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, res);
1107         if (res != FTDM_SUCCESS) {
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_done(ftdmchan);
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     advance_chan_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         advance_chan_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 __inline__ 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         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
1377                 ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
1378         } else {
1379                 return FTDM_SUCCESS;
1380         }
1381 
1382         ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n");
1383 
1384         ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
1385         
1386         memset(&sig, 0, sizeof(sig));
1387         sig.chan_id = ftdmchan->chan_id;
1388         sig.span_id = ftdmchan->span_id;
1389         sig.channel = ftdmchan;
1390 
1391         switch (ftdmchan->state) {
1392         case FTDM_CHANNEL_STATE_DOWN:
1393                 {
1394                         int call_stopped_ack_sent = 0;
1395                         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
1396 
1397                         if (ftdmchan->last_state == FTDM_CHANNEL_STATE_IN_LOOP) {
1398                                 ftdm_log(FTDM_LOG_DEBUG, "%d:%d terminating loop\n", ftdmchan->span_id, ftdmchan->chan_id);
1399                         } else {
1400                                 release_request_id_span_chan(ftdmchan->physical_span_id, ftdmchan->physical_chan_id);
1401 
1402                                 if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG)) {
1403                                         ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
1404 
1405                                         if (ftdmchan->call_data && CALL_DATA(ftdmchan)->last_event_id == SIGBOOST_EVENT_CALL_START_NACK) {
1406                                                 sangomabc_exec_command(mcon,
1407                                                                                 BOOST_SPAN(ftdmchan),
1408                                                                                 BOOST_CHAN(ftdmchan),
1409                                                                                 CALL_DATA(ftdmchan)->call_setup_id,
1410                                                                                 SIGBOOST_EVENT_CALL_START_NACK_ACK,
1411                                                                                 0, 0);
1412                                                 
1413                                         } else {
1414                                                 /* we got a call stop msg, time to reply with call stopped ack  */
1415                                                 sangomabc_exec_command(mcon,
1416                                                                                 BOOST_SPAN(ftdmchan),
1417                                                                                 BOOST_CHAN(ftdmchan),
1418                                                                                 0,
1419                                                                                 SIGBOOST_EVENT_CALL_STOPPED_ACK,
1420                                                                                 0, 0);
1421                                                 call_stopped_ack_sent = 1;
1422                                         }
1423                                 }
1424                         }
1425 
1426                         ftdmchan->sflags = 0;
1427                         memset(ftdmchan->call_data, 0, sizeof(sangoma_boost_call_t));
1428                         if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
1429                                 /* we dont want to call ftdm_channel_done just yet until call released is received */
1430                                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n", 
1431                                                 ftdmchan->span_id, ftdmchan->chan_id);
1432                         } else {
1433                                 ftdm_channel_done(ftdmchan);
1434                         }
1435                 }
1436                 break;
1437         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
1438                 {
1439                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1440                                 sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
1441                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1442                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1443                                 }
1444                         } else {
1445                                 if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
1446                                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
1447                                         sangomabc_exec_command(mcon,
1448                                                                 BOOST_SPAN(ftdmchan),
1449                                                                 BOOST_CHAN(ftdmchan),
1450                                                                 0,
1451                                                                 SIGBOOST_EVENT_CALL_START_ACK,
1452                                                                 0, 0);
1453                                 }
1454                                 sangomabc_exec_command(mcon,
1455                                                         BOOST_SPAN(ftdmchan),
1456                                                         BOOST_CHAN(ftdmchan),
1457                                                         0,
1458                                                         SIGBOOST_EVENT_CALL_PROGRESS,
1459                                                         0, SIGBOOST_PROGRESS_MEDIA);
1460                         }
1461                 }
1462                 break;
1463         case FTDM_CHANNEL_STATE_PROGRESS:
1464                 {
1465                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1466                                 sig.event_id = FTDM_SIGEVENT_PROGRESS;
1467                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1468                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1469                                 }
1470                         } else {
1471                                 if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
1472                                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
1473                                         sangomabc_exec_command(mcon,
1474                                                                 BOOST_SPAN(ftdmchan),
1475                                                                 BOOST_CHAN(ftdmchan),
1476                                                                 0,
1477                                                                 SIGBOOST_EVENT_CALL_START_ACK,
1478                                                                 0, SIGBOOST_PROGRESS_RING);
1479                                 }
1480                         }
1481                 }
1482                 break;
1483         case FTDM_CHANNEL_STATE_IDLE:
1484         case FTDM_CHANNEL_STATE_HOLD:
1485                 {
1486                         /* twiddle */
1487                 }
1488                 break;
1489         case FTDM_CHANNEL_STATE_RING:
1490                 {
1491                         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1492                                 sig.event_id = FTDM_SIGEVENT_START;
1493                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1494                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1495                                 }
1496                         }
1497                 }
1498                 break;
1499         case FTDM_CHANNEL_STATE_RESTART:
1500                 {
1501                         sig.event_id = FTDM_SIGEVENT_RESTART;
1502                         status = ftdm_span_send_signal(ftdmchan->span, &sig);
1503                         ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
1504                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
1505                 }
1506                 break;
1507         case FTDM_CHANNEL_STATE_UP:
1508                 {
1509                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
1510                                 sig.event_id = FTDM_SIGEVENT_UP;
1511                                 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
1512                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
1513                                 }
1514                         } else {
1515                                 if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
1516                                         sangomabc_exec_command(mcon,
1517                                                                            BOOST_SPAN(ftdmchan),
1518                                                                            BOOST_CHAN(ftdmchan),                                                                   
1519                                                                            0,
1520                                                                            SIGBOOST_EVENT_CALL_START_ACK,
1521                                                                            0, 0);
1522                                 }
1523                                 
1524                                 sangomabc_exec_command(mcon,
1525                                                                    BOOST_SPAN(ftdmchan),
1526                                                                    BOOST_CHAN(ftdmchan),                                                                   
1527                                                                    0,
1528                                                                    SIGBOOST_EVENT_CALL_ANSWERED,
1529                                                                    0, 0);
1530                         }
1531                 }
1532                 break;
1533         case FTDM_CHANNEL_STATE_DIALING:
1534                 {
1535                         char dnis[128] = "";
1536                         sangoma_boost_request_id_t r;
1537                         sangomabc_event_t event = {0};
1538 
1539                         ftdm_assert(sangoma_boost_data->sigmod != NULL, "We should be in sigmod here!\n");
1540                         
1541                         ftdm_set_string(dnis, ftdmchan->caller_data.dnis.digits);
1542 
1543                         r = next_request_id();
1544                         if (r == 0) {
1545                                 ftdm_log(FTDM_LOG_CRIT, "All boost request ids are busy.\n");
1546                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
1547                                 break;
1548                         }
1549                         
1550                         sangomabc_call_init(&event, ftdmchan->caller_data.cid_num.digits, dnis, r);
1551 
1552                         event.span = (uint8_t)ftdmchan->physical_span_id;
1553                         event.chan = (uint8_t)ftdmchan->physical_chan_id;
1554                         /* because we already have a span/chan here we bind to the SETUP_GRID now and not on call start ack */
1555                         SETUP_GRID[event.span][event.chan] = event.call_setup_id;
1556 
1557                         ftdm_set_string(event.calling_name, ftdmchan->caller_data.cid_name);
1558                         ftdm_set_string(event.rdnis.digits, ftdmchan->caller_data.rdnis.digits);
1559                         if (strlen(ftdmchan->caller_data.rdnis.digits)) {
1560                                         event.rdnis.digits_count = (uint8_t)strlen(ftdmchan->caller_data.rdnis.digits)+1;
1561                                         event.rdnis.ton = ftdmchan->caller_data.rdnis.type;
1562                                         event.rdnis.npi = ftdmchan->caller_data.rdnis.plan;
1563                         }
1564                     
1565                         event.calling.screening_ind = ftdmchan->caller_data.screen;
1566                         event.calling.presentation_ind = ftdmchan->caller_data.pres;
1567 
1568                         event.calling.ton = ftdmchan->caller_data.cid_num.type;
1569                         event.calling.npi = ftdmchan->caller_data.cid_num.plan;
1570 
1571                         event.called.ton = ftdmchan->caller_data.dnis.type;
1572                         event.called.npi = ftdmchan->caller_data.dnis.plan;
1573 
1574                         if (ftdmchan->caller_data.raw_data_len) {
1575                                 ftdm_set_string(event.custom_data, ftdmchan->caller_data.raw_data);
1576                                 event.custom_data_size = (uint16_t)ftdmchan->caller_data.raw_data_len;
1577                         }
1578 
1579                         OUTBOUND_REQUESTS[r].status = BST_WAITING;
1580                         OUTBOUND_REQUESTS[r].span = ftdmchan->span;
1581                         OUTBOUND_REQUESTS[r].ftdmchan = ftdmchan;
1582 
1583                         ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s over boost channel with request id %d\n", event.called_number_digits, r);
1584                         if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
1585                                 release_request_id(r);
1586                                 ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
1587                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
1588                         }
1589                         
1590                 }
1591                 break;
1592         case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
1593                 {
1594                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
1595                 }
1596                 break;
1597         case FTDM_CHANNEL_STATE_HANGUP:
1598                 {
1599                         ftdm_set_sflag_locked(ftdmchan, SFLAG_HANGUP);
1600 
1601                         if (ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG) || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
1602                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
1603                         } else {
1604                                 ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
1605                                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || 
1606                                                 ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || 
1607                                                 ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA) ||
1608                                                 ftdm_test_sflag(ftdmchan, SFLAG_RECVD_ACK)) {
1609                                         sangomabc_exec_command(mcon,
1610                                                                            BOOST_SPAN(ftdmchan),
1611                                                                            BOOST_CHAN(ftdmchan),
1612                                                                            0,
1613                                                                            SIGBOOST_EVENT_CALL_STOPPED,
1614                                                                            ftdmchan->caller_data.hangup_cause, 0);
1615                                 } else {
1616                                         sangomabc_exec_command(mcon,
1617                                                                            BOOST_SPAN(ftdmchan),
1618                                                                            BOOST_CHAN(ftdmchan),                                                                   
1619                                                                            0,
1620                                                                            SIGBOOST_EVENT_CALL_START_NACK,
1621                                                                            ftdmchan->caller_data.hangup_cause, 0);
1622                                 }
1623                         }
1624                 }
1625                 break;
1626         case FTDM_CHANNEL_STATE_TERMINATING:
1627                 {
1628                         ftdm_set_sflag_locked(ftdmchan, SFLAG_TERMINATING);
1629                         sig.event_id = FTDM_SIGEVENT_STOP;
1630                         status = ftdm_span_send_signal(ftdmchan->span, &sig);
1631                 }
1632                 break;
1633         case FTDM_CHANNEL_STATE_IN_LOOP:
1634                 {
1635                         /* nothing to do, we sent the FTDM_COMMAND_ENABLE_LOOP command in handle_call_loop_start() right away */
1636                 }
1637                 break;
1638         default:
1639                 break;
1640         }
1641         ftdm_channel_complete_state(ftdmchan);
1642         return FTDM_SUCCESS;
1643 }
1644 
1645 static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
1646 {
1647         while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
1648                 state_advance(ftdmchan);
1649         }
1650 }
1651 
1652 /**
1653  * \brief Initialises outgoing requests array
1654  */
1655 static __inline__ void init_outgoing_array(void)
1656 {
1657         memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
1658 
1659 }
1660 
1661 /**
1662  * \brief Checks current state on a span
1663  * \param span Span to check status on
1664  */
1665 static __inline__ void check_state(ftdm_span_t *span)
1666 {
1667         ftdm_channel_t *ftdmchan = NULL;
1668         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1669         int susp = ftdm_test_flag(span, FTDM_SPAN_SUSPENDED);
1670         
1671         if (susp && ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
1672                 susp = 0;
1673         }
1674 
1675         if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE) || susp) {
1676                 uint32_t j;
1677                 ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
1678                 if (susp) {
1679                         for(j = 1; j <= span->chan_count; j++) {
1680                                 if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE) || susp) {
1681                                         ftdm_mutex_lock(span->channels[j]->mutex);
1682                                         ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
1683                                         if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
1684                                                 ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
1685                                         }
1686                                         state_advance(span->channels[j]);
1687                                         ftdm_mutex_unlock(span->channels[j]->mutex);
1688                                 }
1689                         }
1690                 } else {
1691                         while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
1692                                 /* it can happen that someone else processed the chan states
1693                                  * but without taking the chan out of the queue, so check th
1694                                  * flag before advancing the state */
1695                                 ftdm_mutex_lock(ftdmchan->mutex);
1696                                 state_advance(ftdmchan);
1697                                 ftdm_mutex_unlock(ftdmchan->mutex);
1698                         }
1699                 }
1700         }
1701 
1702         if (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING)) {
1703                 if (ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
1704                         sangomabc_exec_command(&sangoma_boost_data->mcon,
1705                                                                    0,
1706                                                                    0,
1707                                                                    -1,
1708                                                                    SIGBOOST_EVENT_SYSTEM_RESTART_ACK,
1709                                                                    0, 0);       
1710                         ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
1711                         ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
1712                         ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
1713                         init_outgoing_array();
1714                 }
1715         }
1716 }
1717 
1718 
1719 /**
1720  * \brief Checks for events on a span
1721  * \param span Span to check for events
1722  */
1723 static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout)
1724 {
1725         ftdm_status_t status;
1726         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1727 
1728         status = ftdm_span_poll_event(span, ms_timeout);
1729 
1730         switch(status) {
1731         case FTDM_SUCCESS:
1732                 {
1733                         ftdm_event_t *event;
1734                         while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
1735                                 switch (event->enum_id) {
1736                                 case FTDM_OOB_ALARM_TRAP:
1737                                         if (sangoma_boost_data->sigmod) {
1738                                                 sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_DISCONNECTED);
1739                                         }
1740                                         break;
1741                                 case FTDM_OOB_ALARM_CLEAR:
1742                                         if (sangoma_boost_data->sigmod) {
1743                                                 sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_CONNECTED);
1744                                         }
1745                                         break;
1746                                 }
1747                         }
1748                 }
1749                 break;
1750         case FTDM_FAIL:
1751                 {
1752                         if (!ftdm_running()) {
1753                                 break;
1754                         }
1755                         ftdm_log(FTDM_LOG_ERROR, "Boost Check Event Failure Failure: %s\n", span->last_error);
1756                         return FTDM_FAIL;
1757                 }
1758                 break;
1759         default:
1760                 break;
1761         }
1762 
1763         return FTDM_SUCCESS;
1764 }
1765 
1766 /**
1767  * \brief Main thread function for sangoma boost span (monitor)
1768  * \param me Current thread
1769  * \param obj Span to run in this thread
1770  */
1771 static void *ftdm_sangoma_events_run(ftdm_thread_t *me, void *obj)
1772 {
1773         ftdm_span_t *span = (ftdm_span_t *) obj;
1774         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1775         unsigned errs = 0;
1776 
1777         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && ftdm_running()) {
1778                 if (check_events(span, 100) != FTDM_SUCCESS) {
1779                         if (errs++ > 50) {
1780                                 ftdm_log(FTDM_LOG_ERROR, "Too many event errors, quitting sangoma events thread\n");
1781                                 return NULL;
1782                         }
1783                 }
1784         }
1785         
1786         ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost Events thread ended.\n");
1787 
1788         ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
1789 
1790         return NULL;
1791 }
1792 
1793 static ftdm_status_t ftdm_boost_connection_open(ftdm_span_t *span)
1794 {
1795         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1796         if (sangoma_boost_data->sigmod) {
1797                 if (sangoma_boost_data->sigmod->start_span(span) != FTDM_SUCCESS) {
1798                         return FTDM_FAIL;
1799                 }
1800                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
1801                 ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
1802                 ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
1803         } 
1804 
1805         sangoma_boost_data->pcon = sangoma_boost_data->mcon;
1806 
1807         /* when sigmod is present, all arguments: local_ip etc, are ignored by sangomabc_connection_open */
1808         if (sangomabc_connection_open(&sangoma_boost_data->mcon,
1809                                                                   sangoma_boost_data->mcon.cfg.local_ip,
1810                                                                   sangoma_boost_data->mcon.cfg.local_port,
1811                                                                   sangoma_boost_data->mcon.cfg.remote_ip,
1812                                                                   sangoma_boost_data->mcon.cfg.remote_port) < 0) {
1813                 ftdm_log(FTDM_LOG_ERROR, "Error: Opening MCON Socket [%d] %s\n", sangoma_boost_data->mcon.socket, strerror(errno));
1814                 return FTDM_FAIL;
1815         }
1816 
1817         if (sangomabc_connection_open(&sangoma_boost_data->pcon,
1818                                                           sangoma_boost_data->pcon.cfg.local_ip,
1819                                                           ++sangoma_boost_data->pcon.cfg.local_port,
1820                                                           sangoma_boost_data->pcon.cfg.remote_ip,
1821                                                           ++sangoma_boost_data->pcon.cfg.remote_port) < 0) {
1822                 ftdm_log(FTDM_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
1823                 return FTDM_FAIL;
1824         }
1825 
1826         /* try to create the boost sockets interrupt objects */
1827         if (ftdm_interrupt_create(&sangoma_boost_data->pcon.sock_interrupt, sangoma_boost_data->pcon.socket) != FTDM_SUCCESS) {
1828                 ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost msock interrupt!\n", span->name);
1829                 return FTDM_FAIL;
1830         }
1831 
1832         if (ftdm_interrupt_create(&sangoma_boost_data->mcon.sock_interrupt, sangoma_boost_data->mcon.socket) != FTDM_SUCCESS) {
1833                 ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost psock interrupt!\n", span->name);
1834                 return FTDM_FAIL;
1835         }
1836 
1837         return FTDM_SUCCESS;
1838 }
1839 
1840 /*! 
1841   \brief wait for a boost event 
1842   \return -1 on error, 0 on timeout, 1 when there are events
1843  */
1844 static int ftdm_boost_wait_event(ftdm_span_t *span)
1845 {
1846                 ftdm_status_t res;
1847                 ftdm_interrupt_t *ints[3];
1848                 int numints;
1849                 ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1850 
1851                 ftdm_queue_get_interrupt(span->pendingchans, &ints[0]);
1852                 numints = 1;
1853                 /* if in queue mode wait for both the pendingchans queue and the boost msg queue */
1854                 if (sangoma_boost_data->sigmod) {
1855                         ftdm_queue_get_interrupt(sangoma_boost_data->boost_queue, &ints[1]);
1856                         numints = 2;
1857                 } 
1858 #ifndef __WINDOWS__
1859                 else {
1860                         /* socket mode ... */
1861                         ints[1] = sangoma_boost_data->mcon.sock_interrupt;
1862                         ints[2] = sangoma_boost_data->pcon.sock_interrupt;
1863                         numints = 3;
1864                         sangoma_boost_data->iteration = 0;
1865                 }
1866 #endif
1867                 res = ftdm_interrupt_multiple_wait(ints, numints, 100);
1868                 if (FTDM_SUCCESS != res && FTDM_TIMEOUT != res) {
1869                         ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res);
1870                         return -1;
1871                 }
1872                 return 0;
1873 }
1874 
1875 
1876 static sangomabc_event_t *ftdm_boost_read_event(ftdm_span_t *span)
1877 {
1878         sangomabc_event_t *event = NULL;
1879         sangomabc_connection_t *mcon, *pcon;
1880         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1881 
1882         mcon = &sangoma_boost_data->mcon;
1883         pcon = &sangoma_boost_data->pcon;
1884 
1885         event = sangomabc_connection_readp(pcon, sangoma_boost_data->iteration);
1886 
1887         /* if there is no event and this is not a sigmod-driven span it's time to try the other connection for events */
1888         if (!event && !sangoma_boost_data->sigmod) {
1889                 event = sangomabc_connection_read(mcon, sangoma_boost_data->iteration);
1890         }
1891 
1892         return event;
1893 }
1894 
1895 /**
1896  * \brief Main thread function for sangoma boost span (monitor)
1897  * \param me Current thread
1898  * \param obj Span to run in this thread
1899  */
1900 static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
1901 {
1902         ftdm_span_t *span = (ftdm_span_t *) obj;
1903         sangomabc_connection_t *mcon, *pcon;
1904         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
1905 
1906         mcon = &sangoma_boost_data->mcon;
1907         pcon = &sangoma_boost_data->pcon;       
1908 
1909         /* sigmod overrides socket functionality if not null */
1910         if (sangoma_boost_data->sigmod) {
1911                 mcon->span = span;
1912                 pcon->span = span;
1913                 /* everything could be retrieved through span, but let's use shortcuts */
1914                 mcon->sigmod = sangoma_boost_data->sigmod;
1915                 pcon->sigmod = sangoma_boost_data->sigmod;
1916                 mcon->boost_queue = sangoma_boost_data->boost_queue;
1917                 pcon->boost_queue = sangoma_boost_data->boost_queue;
1918         }
1919 
1920         if (ftdm_boost_connection_open(span) != FTDM_SUCCESS) {
1921                 ftdm_log(FTDM_LOG_CRIT, "ftdm_boost_connection_open failed\n");
1922                 goto end;
1923         }
1924 
1925         init_outgoing_array();
1926         if (!sangoma_boost_data->sigmod) {
1927                 sangomabc_exec_commandp(pcon,
1928                                                    0,
1929                                                    0,
1930                                                    -1,
1931                                                    SIGBOOST_EVENT_SYSTEM_RESTART,
1932                                                    0);
1933                 ftdm_set_flag(mcon, MSU_FLAG_DOWN);
1934         }
1935 
1936         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) {
1937                 sangomabc_event_t *event = NULL;
1938                 
1939                 if (!ftdm_running()) {
1940                         if (!sangoma_boost_data->sigmod) {
1941                                 sangomabc_exec_commandp(pcon,
1942                                                                    0,
1943                                                                    0,
1944                                                                    -1,
1945                                                                    SIGBOOST_EVENT_SYSTEM_RESTART,
1946                                                                    0);
1947                                 ftdm_set_flag(mcon, MSU_FLAG_DOWN);
1948                         }
1949                         ftdm_log(FTDM_LOG_DEBUG, "ftdm is no longer running\n");
1950                         break;
1951                 }
1952 
1953                 if (ftdm_boost_wait_event(span) < 0) {
1954                         ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n");
1955                 }
1956                 
1957                 while ((event = ftdm_boost_read_event(span))) {
1958                         parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
1959                         sangoma_boost_data->iteration++;
1960                 }
1961                 
1962                 check_state(span);
1963         }
1964 
1965 end:
1966         if (!sangoma_boost_data->sigmod) {
1967                 sangomabc_connection_close(&sangoma_boost_data->mcon);
1968                 sangomabc_connection_close(&sangoma_boost_data->pcon);
1969         }
1970 
1971         ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
1972 
1973         ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost thread ended.\n");
1974         return NULL;
1975 }
1976 
1977 #if 0
1978 static int sigmod_ss7box_isup_exec_cmd(ftdm_stream_handle_t *stream, char *cmd)
1979 {
1980         FILE *fp;
1981         int status=0;
1982         char path[1024];
1983         
1984         fp = popen(cmd, "r");
1985         if (fp == NULL) {
1986                 stream->write_function(stream, "%s: -ERR failed to execute cmd: %s\n",
1987                                 __FILE__,cmd);
1988                 return -1;
1989         }
1990         
1991         while (fgets(path, sizeof(path)-1, fp) != NULL) {
1992                 path[sizeof(path)-1]='\0';
1993                 stream->write_function(stream,"%s", path);
1994         }
1995         
1996         
1997         status = pclose(fp);
1998         if (status == -1) {
1999                 /* Error reported by pclose() */
2000         } else {
2001                 /* Use macros described under wait() to inspect `status' in order
2002                 to determine success/failure of command executed by popen() */
2003         }
2004 
2005         return status;
2006 }
2007 #endif
2008 
2009 static void ftdm_cli_span_state_cmd(ftdm_span_t *span, char *state)
2010 {
2011         unsigned int j;
2012         int cnt=0;
2013         ftdm_channel_state_t state_e = ftdm_str2ftdm_channel_state(state);
2014         if (state_e == FTDM_CHANNEL_STATE_INVALID) {
2015                 ftdm_log(FTDM_LOG_CRIT, "Checking for channels not in the INVALID state is probably not what you want\n");
2016         }
2017         for(j = 1; j <= span->chan_count; j++) {
2018                 if (span->channels[j]->state != state_e) {
2019                         ftdm_channel_t *ftdmchan = span->channels[j];
2020                         ftdm_log(FTDM_LOG_CRIT, "Channel %i s%dc%d State=%s\n",
2021                                 j, ftdmchan->physical_span_id-1, ftdmchan->physical_chan_id-1, ftdm_channel_state2str(ftdmchan->state));
2022                         cnt++;
2023                 }
2024         }
2025         ftdm_log(FTDM_LOG_CRIT, "Total Channel Cnt %i\n",cnt);
2026 }
2027 
2028 #define FTDM_BOOST_SYNTAX "list sigmods | <sigmod_name> <command> | tracelevel <span> <level>"
2029 /**
2030  * \brief API function to kill or debug a sangoma_boost span
2031  * \param stream API stream handler
2032  * \param data String containing argurments
2033  * \return Flags
2034  */
2035 static FIO_API_FUNCTION(ftdm_sangoma_boost_api)
2036 {
2037         char *mycmd = NULL, *argv[10] = { 0 };
2038         int argc = 0;
2039 
2040         if (data) {
2041                 mycmd = ftdm_strdup(data);
2042                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
2043         }
2044 
2045         if (argc > 1) {
2046                 if (!strcasecmp(argv[0], "list")) {
2047                         if (!strcasecmp(argv[1], "sigmods")) {
2048                                 if (ftdm_sangoma_boost_list_sigmods(stream) != FTDM_SUCCESS) {
2049                                         stream->write_function(stream, "-ERR failed to list sigmods\n");
2050                                         goto done;
2051                                 }
2052                                 goto done;
2053                         }
2054 
2055                         if (!strcasecmp(argv[1], "ids")) {
2056                                 print_request_ids();
2057                                 goto done;
2058                         }
2059                 } else if (!strcasecmp(argv[0], "tracelevel")) {
2060                         ftdm_status_t status;
2061                         const char *levelname = NULL;
2062                         int dbglevel;
2063                         ftdm_sangoma_boost_data_t *sangoma_boost_data;
2064                         ftdm_span_t *span;
2065 
2066                         if (argc <= 2) {
2067                                 stream->write_function(stream, "-ERR usage: tracelevel <span> <level>\n");
2068                                 goto done;
2069                         }
2070 
2071                         status = ftdm_span_find_by_name(argv[1], &span);
2072                         if (FTDM_SUCCESS != status) {
2073                                 stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[1]);
2074                                 goto done;
2075                         }
2076 
2077                         if (span->signal_type != FTDM_SIGTYPE_SANGOMABOOST) {
2078                                 stream->write_function(stream, "-ERR span %s is not of boost type\n", argv[1]);
2079                                 goto done;
2080                         }
2081 
2082                         for (dbglevel = 0; (levelname = FTDM_LEVEL_NAMES[dbglevel]); dbglevel++) {
2083                                 if (!strcasecmp(levelname, argv[2])) {
2084                                         break;
2085                                 }
2086                         }
2087 
2088                         if (!levelname) {
2089                                 stream->write_function(stream, "-ERR invalid log level %s\n", argv[2]);
2090                                 goto done;
2091                         }
2092 
2093                         sangoma_boost_data = span->signal_data;
2094                         sangoma_boost_data->pcon.debuglevel = dbglevel;
2095                         sangoma_boost_data->mcon.debuglevel = dbglevel;
2096                         stream->write_function(stream, "+OK span %s has now trace level %s\n", argv[1], FTDM_LEVEL_NAMES[dbglevel]);
2097                         goto done;
2098 #ifndef __WINDOWS__
2099 #if 0
2100 /* NC: This code crashes the kernel due to fork on heavy fs load */
2101                 } else if (!strcasecmp(argv[0], "ss7box_isupd_ckt")) {
2102                 
2103                         if (!strcasecmp(argv[1], "used")) {
2104                                 stream->write_function(stream, "ss7box_isupd: in use\n", FTDM_BOOST_SYNTAX);
2105                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh inuse");
2106                         } else if (!strcasecmp(argv[1], "reset")) {
2107                                 stream->write_function(stream, "ss7box_isupd: in reset\n", FTDM_BOOST_SYNTAX);
2108                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh reset");
2109                         } else if (!strcasecmp(argv[1], "ready")) {
2110                                 stream->write_function(stream, "ss7box_isupd: ready \n", FTDM_BOOST_SYNTAX);
2111                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh free");
2112                         } else {
2113                                 stream->write_function(stream, "ss7box_isupd: list\n", FTDM_BOOST_SYNTAX);
2114                                 sigmod_ss7box_isup_exec_cmd(stream, (char*) "ckt_report.sh");
2115                         }
2116 
2117                         goto done;
2118 #endif
2119 #endif
2120 
2121                 } else if (!strcasecmp(argv[0], "span")) {
2122                         int err;
2123                         sangomabc_connection_t *pcon;
2124                         ftdm_sangoma_boost_data_t *sangoma_boost_data;
2125                         ftdm_span_t *span;
2126 
2127                         if (argc <= 2) {
2128                                 stream->write_function(stream, "-ERR invalid span usage: span <name> <cmd>\n");
2129                                 goto done;
2130                         }
2131 
2132                         err = ftdm_span_find_by_name(argv[1], &span);
2133                         if (FTDM_SUCCESS != err) {
2134                                 stream->write_function(stream, "-ERR failed to find span by name %s\n",argv[1]);
2135                                 goto done;
2136                         }
2137 
2138                         if (!strcasecmp(argv[2], "restart")) {
2139                                 sangoma_boost_data = span->signal_data;
2140                                 pcon = &sangoma_boost_data->pcon;
2141 
2142                                 /* No need to set any span flags because
2143                            our RESTART will generate a RESTART from the sig daemon */
2144                                 sangomabc_exec_commandp(pcon,
2145                                                    0,
2146                                                    0,
2147                                                    -1,
2148                                                    SIGBOOST_EVENT_SYSTEM_RESTART,
2149                                                    0);          
2150                         } else if (!strcasecmp(argv[2], "state")) {
2151                                 if (argc <= 3) {
2152                                         stream->write_function(stream, "-ERR invalid span state: span <name> state <state name>\n");
2153                                         goto done;
2154                                 }
2155                                 ftdm_cli_span_state_cmd(span,argv[3]);
2156                         }
2157 
2158                         goto done;
2159 
2160                 } else {
2161                         boost_sigmod_interface_t *sigmod_iface = NULL;
2162                         sigmod_iface = hashtable_search(g_boost_modules_hash, argv[0]);
2163                         if (sigmod_iface) {
2164                                 char *p = strchr(data, ' ');
2165                                 if (++p) {
2166                                         char* mydup = strdup(p);
2167                                         if(sigmod_iface->exec_api == NULL) {
2168                                                 stream->write_function(stream, "%s does not support api functions\n", sigmod_iface->name);
2169                                                 goto done;
2170                                         }
2171                                         //stream->write_function(stream, "sigmod:%s command:%s\n", sigmod_iface->name, mydup);
2172                                         if (sigmod_iface->exec_api(stream, mydup) != FTDM_SUCCESS) {
2173                                                 stream->write_function(stream, "-ERR:failed to execute command:%s\n", mydup);
2174                                         }
2175                                         free(mydup);
2176                                 }
2177                                 
2178                                 goto done;
2179                         } else {
2180                                 stream->write_function(stream, "-ERR: Could not find sigmod %s\n", argv[0]);
2181                         }
2182                 }
2183         }
2184         stream->write_function(stream, "-ERR: Usage: %s\n", FTDM_BOOST_SYNTAX);
2185 done:
2186         ftdm_safe_free(mycmd);
2187         return FTDM_SUCCESS;
2188 }
2189 
2190 /**
2191  * \brief Loads sangoma_boost IO module
2192  * \param fio FreeTDM IO interface
2193  * \return Success
2194  */
2195 static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_boost_io_init)
2196 {
2197         ftdm_assert(fio != NULL, "fio is NULL");
2198         memset(&ftdm_sangoma_boost_interface, 0, sizeof(ftdm_sangoma_boost_interface));
2199 
2200         ftdm_sangoma_boost_interface.name = "boost";
2201         ftdm_sangoma_boost_interface.api = ftdm_sangoma_boost_api;
2202 
2203         *fio = &ftdm_sangoma_boost_interface;
2204 
2205         return FTDM_SUCCESS;
2206 }
2207 
2208 /**
2209  * \brief Loads sangoma boost signaling module
2210  * \param fio FreeTDM IO interface
2211  * \return Success
2212  */
2213 static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_boost_init)
2214 {
2215         g_boost_modules_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
2216         if (!g_boost_modules_hash) {
2217                 return FTDM_FAIL;
2218         }
2219         ftdm_mutex_create(&request_mutex);
2220         ftdm_mutex_create(&g_boost_modules_mutex);
2221         memset(&g_trunkgroups[0], 0, sizeof(g_trunkgroups));
2222         return FTDM_SUCCESS;
2223 }
2224 
2225 static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_boost_destroy)
2226 {
2227         ftdm_hash_iterator_t *i = NULL;
2228         boost_sigmod_interface_t *sigmod = NULL;
2229         const void *key = NULL;
2230         void *val = NULL;
2231         ftdm_dso_lib_t lib;
2232         ftdm_log(FTDM_LOG_DEBUG, "Destroying sangoma boost module\n");
2233         for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
2234                 hashtable_this(i, &key, NULL, &val);
2235                 if (key && val) {
2236                         sigmod = val;
2237                         lib = sigmod->pvt;
2238                         ftdm_log(FTDM_LOG_DEBUG, "destroying sigmod %s\n", sigmod->name);
2239                         sigmod->on_unload();
2240                         ftdm_dso_destroy(&lib);
2241                 }
2242         }
2243 
2244         hashtable_destroy(g_boost_modules_hash);
2245         ftdm_mutex_destroy(&request_mutex);
2246         ftdm_mutex_destroy(&g_boost_modules_mutex);
2247         return FTDM_SUCCESS;
2248 }
2249 
2250 static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span)
2251 {
2252         int err;
2253 
2254         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2255 
2256         ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
2257         err = ftdm_thread_create_detached(ftdm_sangoma_boost_run, span);
2258         if (err) {
2259                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
2260                 return err;
2261         }
2262 
2263         // launch the events thread to handle HW DTMF and possibly
2264         // other events in the future
2265         ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
2266         err = ftdm_thread_create_detached(ftdm_sangoma_events_run, span);
2267         if (err) {
2268                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
2269                 ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
2270         }
2271 
2272         return err;
2273 }
2274 
2275 static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span)
2276 {
2277         int cnt = 50;
2278         ftdm_status_t status = FTDM_SUCCESS;
2279         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2280 
2281         if (sangoma_boost_data->sigmod) {
2282                 /* I think stopping the span before destroying the queue makes sense
2283                    otherwise may be boost events would still arrive when the queue is already destroyed! */
2284                 status = sangoma_boost_data->sigmod->stop_span(span);
2285                 if (status != FTDM_SUCCESS) {
2286                         ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s boost signaling\n", span->name);
2287                         return FTDM_FAIL;
2288                 }
2289                 ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL);
2290         }
2291 
2292         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) {
2293                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost thread\n");
2294                 ftdm_sleep(100);
2295         }
2296 
2297         if (!cnt) {
2298                 ftdm_log(FTDM_LOG_CRIT, "it seems boost thread in span %s may be stuck, we may segfault :-(\n", span->name);
2299                 return FTDM_FAIL;
2300         }
2301 
2302         cnt = 50;
2303         while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && cnt-- > 0) {
2304                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost events thread\n");
2305                 ftdm_sleep(100);
2306         }
2307 
2308         if (!cnt) {
2309                 ftdm_log(FTDM_LOG_CRIT, "it seems boost events thread in span %s may be stuck, we may segfault :-(\n", span->name);
2310                 return FTDM_FAIL;
2311         }
2312 
2313         if (sangoma_boost_data->sigmod) {
2314                 ftdm_queue_destroy(&sangoma_boost_data->boost_queue);
2315         }
2316 
2317         return status;
2318 }
2319 
2320 static ftdm_state_map_t boost_state_map = {
2321         {
2322                 {
2323                         ZSD_OUTBOUND,
2324                         ZSM_UNACCEPTABLE,
2325                         {FTDM_ANY_STATE},
2326                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
2327                 },
2328                 {
2329                         ZSD_OUTBOUND,
2330                         ZSM_UNACCEPTABLE,
2331                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
2332                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
2333                 },
2334                 {
2335                         ZSD_OUTBOUND,
2336                         ZSM_UNACCEPTABLE,
2337                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2338                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_HOLD, FTDM_END}
2339                 },
2340                 {
2341                         ZSD_OUTBOUND,
2342                         ZSM_UNACCEPTABLE,
2343                         {FTDM_CHANNEL_STATE_HOLD, FTDM_END},
2344                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, 
2345                          FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
2346                 },
2347                 {
2348                         ZSD_OUTBOUND,
2349                         ZSM_UNACCEPTABLE,
2350                         {FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
2351                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
2352                 },
2353                 {
2354                         ZSD_OUTBOUND,
2355                         ZSM_UNACCEPTABLE,
2356                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
2357                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
2358                 },
2359                 {
2360                         ZSD_OUTBOUND,
2361                         ZSM_UNACCEPTABLE,
2362                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2363                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
2364                 },
2365                 {
2366                         ZSD_OUTBOUND,
2367                         ZSM_UNACCEPTABLE,
2368                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
2369                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2370                 },
2371                 {
2372                         ZSD_OUTBOUND,
2373                         ZSM_UNACCEPTABLE,
2374                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
2375                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
2376                 },
2377 
2378                 /****************************************/
2379                 {
2380                         ZSD_INBOUND,
2381                         ZSM_UNACCEPTABLE,
2382                         {FTDM_ANY_STATE},
2383                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
2384                 },
2385                 {
2386                         ZSD_INBOUND,
2387                         ZSM_UNACCEPTABLE,
2388                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
2389                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
2390                 },
2391                 {
2392                         ZSD_INBOUND,
2393                         ZSM_UNACCEPTABLE,
2394                         {FTDM_CHANNEL_STATE_DOWN},
2395                         {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
2396                 },
2397                 {
2398                         ZSD_INBOUND,
2399                         ZSM_UNACCEPTABLE,
2400                         {FTDM_CHANNEL_STATE_IN_LOOP},
2401                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
2402                 },
2403                 {
2404                         ZSD_INBOUND,
2405                         ZSM_UNACCEPTABLE,
2406                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2407                         {FTDM_CHANNEL_STATE_RING, FTDM_END}
2408                 },
2409                 {
2410                         ZSD_INBOUND,
2411                         ZSM_UNACCEPTABLE,
2412                         {FTDM_CHANNEL_STATE_RING, FTDM_END},
2413                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,FTDM_END}
2414                 },
2415                 {
2416                         ZSD_INBOUND,
2417                         ZSM_UNACCEPTABLE,
2418                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2419                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
2420                 },
2421                 {
2422                         ZSD_INBOUND,
2423                         ZSM_UNACCEPTABLE,
2424                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2425                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
2426                 },
2427                 {
2428                         ZSD_INBOUND,
2429                         ZSM_UNACCEPTABLE,
2430                         {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
2431                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
2432                 },
2433                 {
2434                         ZSD_INBOUND,
2435                         ZSM_UNACCEPTABLE,
2436                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
2437                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
2438                 },
2439                 
2440 
2441         }
2442 };
2443 
2444 static BOOST_WRITE_MSG_FUNCTION(ftdm_boost_write_msg)
2445 {
2446         sangomabc_short_event_t *shortmsg = NULL;
2447         ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
2448         sangomabc_queue_element_t *element = NULL;
2449 
2450         ftdm_assert_return(msg != NULL, FTDM_FAIL, "Boost message to write was null");
2451 
2452         if (!span) {
2453                 shortmsg = msg;
2454                 ftdm_log(FTDM_LOG_ERROR, "Unexpected boost message %d\n", shortmsg->event_id);
2455                 return FTDM_FAIL;
2456         }
2457         /* duplicate the event and enqueue it */
2458         element = ftdm_calloc(1, sizeof(*element));
2459         if (!element) {
2460                 return FTDM_FAIL;
2461         }
2462         memcpy(element->boostmsg, msg, msglen);
2463         element->size = msglen;
2464 
2465         sangoma_boost_data = span->signal_data;
2466         return ftdm_queue_enqueue(sangoma_boost_data->boost_queue, element);
2467 }
2468 
2469 static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
2470 {
2471         ftdm_sigmsg_t sig;
2472         ftdm_log(FTDM_LOG_NOTICE, "%d:%d Signaling link status changed to %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_signaling_status2str(status));
2473         
2474         memset(&sig, 0, sizeof(sig));
2475         sig.chan_id = ftdmchan->chan_id;
2476         sig.span_id = ftdmchan->span_id;
2477         sig.channel = ftdmchan;
2478         sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
2479         sig.raw_data = &status;
2480         ftdm_span_send_signal(ftdmchan->span, &sig);
2481         return;
2482 }
2483 
2484 static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_channel_sig_status)
2485 {
2486         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
2487         if (!sangoma_boost_data->sigmod) {
2488                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel with no signaling module configured\n");
2489                 return FTDM_FAIL;
2490         }
2491         if (!sangoma_boost_data->sigmod->set_channel_sig_status) {
2492                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel: method not implemented\n");
2493                 return FTDM_NOTIMPL;
2494         }
2495         return sangoma_boost_data->sigmod->set_channel_sig_status(ftdmchan, status);
2496 }
2497 
2498 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_channel_sig_status)
2499 {
2500         ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
2501         if (!sangoma_boost_data->sigmod) {
2502                 return FTDM_FAIL;
2503         }
2504         if (!sangoma_boost_data->sigmod->get_channel_sig_status) {
2505                 return FTDM_NOTIMPL;
2506         }
2507         return sangoma_boost_data->sigmod->get_channel_sig_status(ftdmchan, status);
2508 }
2509 
2510 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_span_sig_status)
2511 {
2512         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2513         if (!sangoma_boost_data->sigmod) {
2514                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span with no signaling module configured\n");
2515                 return FTDM_FAIL;
2516         }
2517         if (!sangoma_boost_data->sigmod->set_span_sig_status) {
2518                 ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span: method not implemented\n");
2519                 return FTDM_NOTIMPL;
2520         }
2521         return sangoma_boost_data->sigmod->set_span_sig_status(span, status);
2522 }
2523 
2524 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_span_sig_status)
2525 {
2526         ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
2527         if (!sangoma_boost_data->sigmod) {
2528                 return FTDM_FAIL;
2529         }
2530         if (!sangoma_boost_data->sigmod->get_span_sig_status) {
2531                 ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost span: method not implemented\n");
2532                 return FTDM_NOTIMPL;
2533         }
2534         return sangoma_boost_data->sigmod->get_span_sig_status(span, status);
2535 }
2536 
2537 /**
2538  * \brief Initialises an sangoma boost span from configuration variables
2539  * \param span Span to configure
2540  * \param sig_cb Callback function for event signals
2541  * \param ap List of configuration variables
2542  * \return Success or failure
2543  */
2544 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
2545 {
2546 #define FAIL_CONFIG_RETURN(retstatus) \
2547                 if (sangoma_boost_data) \
2548                         ftdm_safe_free(sangoma_boost_data); \
2549                 if (err) \
2550                         ftdm_safe_free(err) \
2551                 if (hash_locked) \
2552                         ftdm_mutex_unlock(g_boost_modules_mutex); \
2553                 if (lib) \
2554                         ftdm_dso_destroy(&lib); \
2555                 return retstatus;
2556 
2557         boost_sigmod_interface_t *sigmod_iface = NULL;
2558         ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
2559         const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
2560         const char *sigmod = NULL;
2561         int local_port = 53000, remote_port = 53000;
2562         const char *var = NULL, *val = NULL;
2563         int hash_locked = 0;
2564         ftdm_dso_lib_t lib = NULL;
2565         char path[255] = "";
2566         char *err = NULL;
2567         unsigned int j = 0;
2568         unsigned paramindex = 0;
2569         ftdm_status_t rc = FTDM_SUCCESS;
2570 
2571         for (; ftdm_parameters[paramindex].var; paramindex++) {
2572                 var = ftdm_parameters[paramindex].var;
2573                 val = ftdm_parameters[paramindex].val;
2574                 if (!strcasecmp(var, "sigmod")) {
2575                         sigmod = val;
2576                 } else if (!strcasecmp(var, "local_ip")) {
2577                         local_ip = val;
2578                 } else if (!strcasecmp(var, "remote_ip")) {
2579                         remote_ip = val;
2580                 } else if (!strcasecmp(var, "local_port")) {
2581                         local_port = atoi(val);
2582                 } else if (!strcasecmp(var, "remote_port")) {
2583                         remote_port = atoi(val);
2584                 } else if (!strcasecmp(var, "outbound-called-ton")) {
2585                         ftdm_span_set_ton(val, &span->default_caller_data.dnis.type);
2586                 } else if (!strcasecmp(var, "outbound-called-npi")) {
2587                         ftdm_span_set_npi(val, &span->default_caller_data.dnis.plan);
2588                 } else if (!strcasecmp(var, "outbound-calling-ton")) {
2589                         ftdm_span_set_ton(val, &span->default_caller_data.cid_num.type);
2590                 } else if (!strcasecmp(var, "outbound-calling-npi")) {
2591                         ftdm_span_set_npi(val, &span->default_caller_data.cid_num.plan);
2592                 } else if (!strcasecmp(var, "outbound-rdnis-ton")) {
2593                         ftdm_span_set_ton(val, &span->default_caller_data.rdnis.type);
2594                 } else if (!strcasecmp(var, "outbound-rdnis-npi")) {
2595                         ftdm_span_set_npi(val, &span->default_caller_data.rdnis.plan);
2596                 } else if (!sigmod) {
2597                         snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
2598                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2599                 }
2600         }
2601 
2602         if (!sigmod) {
2603 #ifndef HAVE_NETINET_SCTP_H
2604                 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);
2605                 ftdm_set_string(span->last_error, "No sigmod configuration was set and there is no SCTP available!");
2606                 FAIL_CONFIG_RETURN(FTDM_FAIL);
2607 #else
2608                 if (!local_ip && local_port && remote_ip && remote_port && sig_cb) {
2609                         ftdm_set_string(span->last_error, "missing Sangoma boost IP parameters");
2610                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2611                 }
2612 #endif
2613         }
2614 
2615         sangoma_boost_data = ftdm_calloc(1, sizeof(*sangoma_boost_data));
2616         if (!sangoma_boost_data) {
2617                 FAIL_CONFIG_RETURN(FTDM_FAIL);
2618         }
2619 
2620         /* WARNING: be sure to release this mutex on errors inside this if() */
2621         ftdm_mutex_lock(g_boost_modules_mutex);
2622         hash_locked = 1;
2623         if (sigmod && !(sigmod_iface = hashtable_search(g_boost_modules_hash, (void *)sigmod))) {
2624                 ftdm_build_dso_path(sigmod, path, sizeof(path));        
2625                 lib = ftdm_dso_open(path, &err);
2626                 if (!lib) {
2627                         ftdm_log(FTDM_LOG_ERROR, "Error loading Sangoma boost signaling module '%s': %s\n", path, err);
2628                         snprintf(span->last_error, sizeof(span->last_error), "Failed to load sangoma boost signaling module %s", path);
2629 
2630                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2631                 }
2632                 if (!(sigmod_iface = (boost_sigmod_interface_t *)ftdm_dso_func_sym(lib, BOOST_INTERFACE_NAME_STR, &err))) {
2633                         ftdm_log(FTDM_LOG_ERROR, "Failed to read Sangoma boost signaling module interface '%s': %s\n", path, err);
2634                         snprintf(span->last_error, sizeof(span->last_error), "Failed to read Sangoma boost signaling module interface '%s': %s", path, err);
2635 
2636                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2637                 }
2638                 rc = sigmod_iface->on_load();
2639                 if (rc != FTDM_SUCCESS) {
2640                         ftdm_log(FTDM_LOG_ERROR, "Failed to load Sangoma boost signaling module interface '%s': on_load method failed (%d)\n", path, rc);
2641                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2642                 }
2643                 sigmod_iface->pvt = lib;
2644                 sigmod_iface->set_write_msg_cb(ftdm_boost_write_msg);
2645                 sigmod_iface->set_sig_status_cb(ftdm_boost_sig_status_change);
2646                 hashtable_insert(g_boost_modules_hash, (void *)sigmod_iface->name, sigmod_iface, HASHTABLE_FLAG_NONE);
2647                 lib = NULL; /* destroying the lib will be done when going down and NOT on FAIL_CONFIG_RETURN */
2648         }
2649         ftdm_mutex_unlock(g_boost_modules_mutex);
2650         hash_locked = 0;
2651 
2652         if (sigmod_iface) {
2653                 /* try to create the boost queue */
2654                 if (ftdm_queue_create(&sangoma_boost_data->boost_queue, BOOST_QUEUE_SIZE) != FTDM_SUCCESS) {
2655                         ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost queue!\n", span->name);
2656                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2657                 }
2658                 ftdm_log(FTDM_LOG_NOTICE, "Span %s will use Sangoma Boost Signaling Module %s\n", span->name, sigmod_iface->name);
2659                 sangoma_boost_data->sigmod = sigmod_iface;
2660                 sigmod_iface->configure_span(span, ftdm_parameters);
2661         } else {
2662                 ftdm_log(FTDM_LOG_NOTICE, "Span %s will use boost socket mode\n", span->name);
2663                 ftdm_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
2664                 sangoma_boost_data->mcon.cfg.local_port = local_port;
2665                 ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
2666                 sangoma_boost_data->mcon.cfg.remote_port = remote_port;
2667         }
2668 
2669         for (j = 1; j <= span->chan_count; j++) {
2670                 span->channels[j]->call_data = ftdm_calloc(1, sizeof(sangoma_boost_call_t));
2671                 if (!span->channels[j]->call_data) {
2672                         FAIL_CONFIG_RETURN(FTDM_FAIL);
2673                 }
2674         }
2675 
2676         span->signal_cb = sig_cb;
2677         span->start = ftdm_sangoma_boost_start;
2678         span->stop = ftdm_sangoma_boost_stop;
2679         span->signal_data = sangoma_boost_data;
2680         span->signal_type = FTDM_SIGTYPE_SANGOMABOOST;
2681         span->outgoing_call = sangoma_boost_outgoing_call;
2682         span->channel_request = sangoma_boost_channel_request;
2683         span->get_channel_sig_status = sangoma_boost_get_channel_sig_status;
2684         span->set_channel_sig_status = sangoma_boost_set_channel_sig_status;
2685         span->get_span_sig_status = sangoma_boost_get_span_sig_status;
2686         span->set_span_sig_status = sangoma_boost_set_span_sig_status;
2687         span->state_map = &boost_state_map;
2688         sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
2689         sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
2690         ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
2691         ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
2692         if (sigmod_iface) {
2693                 /* the core will do the hunting */
2694                 span->channel_request = NULL;
2695         } 
2696         ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
2697         return FTDM_SUCCESS;
2698 }
2699 
2700 static ftdm_status_t ftdm_sangoma_boost_list_sigmods(ftdm_stream_handle_t *stream)
2701 {
2702         ftdm_hash_iterator_t *i = NULL;
2703         boost_sigmod_interface_t *sigmod_iface = NULL;
2704         const void *key = NULL;
2705         void *val = NULL;
2706 
2707         stream->write_function(stream, "List of loaded sigmod modules:\n");
2708         for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
2709                 hashtable_this(i, &key, NULL, &val);
2710                 if (key && val) {
2711                         sigmod_iface = val;
2712                         stream->write_function(stream, "  %s\n", sigmod_iface->name);
2713                 }
2714         }
2715         stream->write_function(stream, "\n");
2716         return FTDM_SUCCESS;
2717 }
2718 
2719 /**
2720  * \brief FreeTDM sangoma boost signaling module definition
2721  */
2722 EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
2723         /*.name =*/ "sangoma_boost",
2724         /*.io_load =*/ ftdm_sangoma_boost_io_init,
2725         /*.io_unload =*/ NULL,
2726         /*.sig_load = */ ftdm_sangoma_boost_init,
2727         /*.sig_configure =*/ NULL,
2728         /*.sig_unload = */ftdm_sangoma_boost_destroy,
2729         /*.configure_span_signaling = */ ftdm_sangoma_boost_configure_span
2730 };
2731 
2732 /* For Emacs:
2733  * Local Variables:
2734  * mode:c
2735  * indent-tabs-mode:t
2736  * tab-width:4
2737  * c-basic-offset:4
2738  * End:
2739  * For VIM:
2740  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
2741  */

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