This source file includes following definitions.
- __release_request_id_span_chan
- __release_request_id
- __next_request_id
- print_request_ids
- find_ftdmchan
- check_congestion
- FIO_CHANNEL_REQUEST_FUNCTION
- FIO_CHANNEL_OUTGOING_CALL_FUNCTION
- handle_call_progress
- handle_call_start_ack
- handle_call_done
- handle_call_start_nack
- handle_call_released
- handle_call_stop
- handle_call_answer
- handle_call_start
- handle_call_loop_start
- stop_loop
- handle_call_loop_stop
- handle_heartbeat
- handle_restart_ack
- handle_restart
- handle_incoming_digit
- event_process_states
- parse_sangoma_event
- state_advance
- advance_chan_states
- init_outgoing_array
- check_state
- check_events
- ftdm_sangoma_events_run
- ftdm_boost_connection_open
- ftdm_boost_wait_event
- ftdm_boost_read_event
- ftdm_sangoma_boost_run
- sigmod_ss7box_isup_exec_cmd
- ftdm_cli_span_state_cmd
- FIO_API_FUNCTION
- FIO_IO_LOAD_FUNCTION
- FIO_SIG_LOAD_FUNCTION
- FIO_SIG_UNLOAD_FUNCTION
- ftdm_sangoma_boost_start
- ftdm_sangoma_boost_stop
- BOOST_WRITE_MSG_FUNCTION
- BOOST_SIG_STATUS_CB_FUNCTION
- FIO_CHANNEL_SET_SIG_STATUS_FUNCTION
- FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
- FIO_SPAN_SET_SIG_STATUS_FUNCTION
- FIO_SPAN_GET_SIG_STATUS_FUNCTION
- FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
- ftdm_sangoma_boost_list_sigmods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
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
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
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
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
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
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
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
128
129
130
131
132
133
134
135
136
137
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
155
156
157
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
172
173
174
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
183
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
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
238
239
240
241
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
253
254
255
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
306
307
308
309
310
311
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
320
321
322
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
333
334
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
371
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
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
513
514
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
533
534
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
570
571
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
583
584
585
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
603
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
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
653
654
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
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
695
696
697
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
710
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
746
747
748
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
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
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
851
852
853
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
869
870
871
872
873
874
875
876
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 {
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
915
916
917
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
931
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
959
960
961
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
976
977
978
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
995
996
997
998
999
1000
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
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
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
1144
1145
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
1161
1162
1163
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
1172
1173
1174
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
1189
1190
1191
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
1225
1226
1227
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
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
1275
1276
1277
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
1291
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
1324
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
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
1366
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
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
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
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
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
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
1654
1655 static __inline__ void init_outgoing_array(void)
1656 {
1657 memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
1658
1659 }
1660
1661
1662
1663
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
1693
1694
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
1721
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
1768
1769
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
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
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
1842
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
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
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
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
1897
1898
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
1910 if (sangoma_boost_data->sigmod) {
1911 mcon->span = span;
1912 pcon->span = span;
1913
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
2000 } else {
2001
2002
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
2031
2032
2033
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
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
2143
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
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
2192
2193
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
2210
2211
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
2264
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
2283
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
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
2539
2540
2541
2542
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
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;
2648 }
2649 ftdm_mutex_unlock(g_boost_modules_mutex);
2650 hash_locked = 0;
2651
2652 if (sigmod_iface) {
2653
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
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
2721
2722 EX_DECLARE_DATA ftdm_module_t ftdm_module = {
2723 "sangoma_boost",
2724 ftdm_sangoma_boost_io_init,
2725 NULL,
2726 ftdm_sangoma_boost_init,
2727 NULL,
2728 ftdm_sangoma_boost_destroy,
2729 ftdm_sangoma_boost_configure_span
2730 };
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741