This source file includes following definitions.
- FIO_IO_UNLOAD_FUNCTION
- FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
- FIO_SPAN_GET_SIG_STATUS_FUNCTION
- FIO_CHANNEL_OUTGOING_CALL_FUNCTION
- s_pri_error
- s_pri_message
- parse_debug
- FIO_API_FUNCTION
- FIO_IO_LOAD_FUNCTION
- FIO_SIG_LOAD_FUNCTION
- state_advance
- pritap_check_state
- pri_io_read
- pri_io_write
- tap_pri_get_crv
- tap_pri_get_pcall_bycrv
- tap_pri_get_pcall
- tap_pri_put_pcall
- tap_pri_get_fchan
- handle_pri_passive_event
- ftdm_pritap_run
- ftdm_pritap_stop
- ftdm_pritap_sig_read
- ftdm_pritap_start
- FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
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 #include <libpri.h>
35 #include <poll.h>
36 #include "private/ftdm_core.h"
37
38 #define PRI_SPAN(p) (((p) >> 8) & 0xff)
39 #define PRI_CHANNEL(p) ((p) & 0xff)
40
41 typedef enum {
42 PRITAP_RUNNING = (1 << 0),
43 } pritap_flags_t;
44
45 typedef struct {
46 void *callref;
47 ftdm_number_t callingnum;
48 ftdm_number_t callingani;
49 ftdm_number_t callednum;
50 ftdm_channel_t *fchan;
51 char callingname[80];
52 int proceeding:1;
53 int inuse:1;
54 } passive_call_t;
55
56 typedef struct pritap {
57 int32_t flags;
58 struct pri *pri;
59 int debug;
60 ftdm_channel_t *dchan;
61 ftdm_span_t *span;
62 ftdm_span_t *peerspan;
63 ftdm_mutex_t *pcalls_lock;
64 passive_call_t pcalls[FTDM_MAX_CHANNELS_PHYSICAL_SPAN];
65 } pritap_t;
66
67 static FIO_IO_UNLOAD_FUNCTION(ftdm_pritap_unload)
68 {
69 return FTDM_SUCCESS;
70 }
71
72 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(pritap_get_channel_sig_status)
73 {
74 *status = FTDM_SIG_STATE_UP;
75 return FTDM_SUCCESS;
76 }
77
78 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(pritap_get_span_sig_status)
79 {
80 *status = FTDM_SIG_STATE_UP;
81 return FTDM_SUCCESS;
82 }
83
84
85 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(pritap_outgoing_call)
86 {
87 ftdm_log(FTDM_LOG_ERROR, "Cannot dial on PRI tapping line!\n");
88 return FTDM_FAIL;
89 }
90
91 static void s_pri_error(struct pri *pri, char *s)
92 {
93 ftdm_log(FTDM_LOG_ERROR, "%s", s);
94 }
95
96 static void s_pri_message(struct pri *pri, char *s)
97 {
98 ftdm_log(FTDM_LOG_DEBUG, "%s", s);
99 }
100
101 static int parse_debug(const char *in)
102 {
103 int flags = 0;
104
105 if (!in) {
106 return 0;
107 }
108
109 if (strstr(in, "q921_raw")) {
110 flags |= PRI_DEBUG_Q921_RAW;
111 }
112
113 if (strstr(in, "q921_dump")) {
114 flags |= PRI_DEBUG_Q921_DUMP;
115 }
116
117 if (strstr(in, "q921_state")) {
118 flags |= PRI_DEBUG_Q921_STATE;
119 }
120
121 if (strstr(in, "config")) {
122 flags |= PRI_DEBUG_CONFIG;
123 }
124
125 if (strstr(in, "q931_dump")) {
126 flags |= PRI_DEBUG_Q931_DUMP;
127 }
128
129 if (strstr(in, "q931_state")) {
130 flags |= PRI_DEBUG_Q931_STATE;
131 }
132
133 if (strstr(in, "q931_anomaly")) {
134 flags |= PRI_DEBUG_Q931_ANOMALY;
135 }
136
137 if (strstr(in, "apdu")) {
138 flags |= PRI_DEBUG_APDU;
139 }
140
141 if (strstr(in, "aoc")) {
142 flags |= PRI_DEBUG_AOC;
143 }
144
145 if (strstr(in, "all")) {
146 flags |= PRI_DEBUG_ALL;
147 }
148
149 if (strstr(in, "none")) {
150 flags = 0;
151 }
152
153 return flags;
154 }
155
156 static ftdm_io_interface_t ftdm_pritap_interface;
157
158 static ftdm_status_t ftdm_pritap_start(ftdm_span_t *span);
159
160 static FIO_API_FUNCTION(ftdm_pritap_api)
161 {
162 char *mycmd = NULL, *argv[10] = { 0 };
163 int argc = 0;
164
165 if (data) {
166 mycmd = ftdm_strdup(data);
167 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
168 }
169
170 if (argc > 2) {
171 if (!strcasecmp(argv[0], "debug")) {
172 ftdm_span_t *span = NULL;
173
174 if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
175 pritap_t *pritap = span->signal_data;
176 if (span->start != ftdm_pritap_start) {
177 stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
178 goto done;
179 }
180
181 pri_set_debug(pritap->pri, parse_debug(argv[2]));
182 stream->write_function(stream, "%s: +OK debug set.\n", __FILE__);
183 goto done;
184 } else {
185 stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
186 goto done;
187 }
188 }
189
190 }
191
192 stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
193
194 done:
195
196 ftdm_safe_free(mycmd);
197
198 return FTDM_SUCCESS;
199 }
200
201 static FIO_IO_LOAD_FUNCTION(ftdm_pritap_io_init)
202 {
203 memset(&ftdm_pritap_interface, 0, sizeof(ftdm_pritap_interface));
204
205 ftdm_pritap_interface.name = "pritap";
206 ftdm_pritap_interface.api = ftdm_pritap_api;
207
208 *fio = &ftdm_pritap_interface;
209
210 return FTDM_SUCCESS;
211 }
212
213 static FIO_SIG_LOAD_FUNCTION(ftdm_pritap_init)
214 {
215 pri_set_error(s_pri_error);
216 pri_set_message(s_pri_message);
217 return FTDM_SUCCESS;
218 }
219
220 static ftdm_state_map_t pritap_state_map = {
221 {
222 {
223 ZSD_INBOUND,
224 ZSM_UNACCEPTABLE,
225 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
226 {FTDM_CHANNEL_STATE_RING, FTDM_END}
227 },
228 {
229 ZSD_INBOUND,
230 ZSM_UNACCEPTABLE,
231 {FTDM_CHANNEL_STATE_RING, FTDM_END},
232 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
233 },
234 {
235 ZSD_INBOUND,
236 ZSM_UNACCEPTABLE,
237 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
238 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
239 },
240 {
241 ZSD_INBOUND,
242 ZSM_UNACCEPTABLE,
243 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
244 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
245 },
246 {
247 ZSD_INBOUND,
248 ZSM_UNACCEPTABLE,
249 {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
250 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
251 },
252 {
253 ZSD_INBOUND,
254 ZSM_UNACCEPTABLE,
255 {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
256 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END},
257 },
258 {
259 ZSD_INBOUND,
260 ZSM_UNACCEPTABLE,
261 {FTDM_CHANNEL_STATE_UP, FTDM_END},
262 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
263 },
264
265 }
266 };
267
268 static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
269 {
270 ftdm_status_t status;
271 ftdm_sigmsg_t sig;
272 ftdm_channel_t *peerchan = ftdmchan->call_data;
273
274 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state %s\n", ftdm_channel_state2str(ftdmchan->state));
275
276 memset(&sig, 0, sizeof(sig));
277 sig.chan_id = ftdmchan->chan_id;
278 sig.span_id = ftdmchan->span_id;
279 sig.channel = ftdmchan;
280
281 switch (ftdmchan->state) {
282 case FTDM_CHANNEL_STATE_DOWN:
283 {
284 ftdm_channel_done(ftdmchan);
285 ftdmchan->call_data = NULL;
286
287 ftdm_channel_done(peerchan);
288 peerchan->call_data = NULL;
289 }
290 break;
291
292 case FTDM_CHANNEL_STATE_PROGRESS:
293 case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
294 case FTDM_CHANNEL_STATE_UP:
295 case FTDM_CHANNEL_STATE_HANGUP:
296 break;
297
298 case FTDM_CHANNEL_STATE_RING:
299 {
300 sig.event_id = FTDM_SIGEVENT_START;
301 if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
302 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
303 }
304 }
305 break;
306
307 case FTDM_CHANNEL_STATE_TERMINATING:
308 {
309 if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP) {
310 sig.event_id = FTDM_SIGEVENT_STOP;
311 status = ftdm_span_send_signal(ftdmchan->span, &sig);
312 }
313 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
314 }
315 break;
316
317 default:
318 {
319 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ignoring state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(ftdmchan->state));
320 }
321 break;
322 }
323
324 return;
325 }
326
327 static __inline__ void pritap_check_state(ftdm_span_t *span)
328 {
329 if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
330 uint32_t j;
331 ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
332 for(j = 1; j <= span->chan_count; j++) {
333 if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
334 ftdm_mutex_lock(span->channels[j]->mutex);
335 ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
336 state_advance(span->channels[j]);
337 ftdm_channel_complete_state(span->channels[j]);
338 ftdm_mutex_unlock(span->channels[j]->mutex);
339 }
340 }
341 }
342 }
343
344 static int pri_io_read(struct pri *pri, void *buf, int buflen)
345 {
346 int res;
347 ftdm_status_t zst;
348 pritap_t *pritap = pri_get_userdata(pri);
349 ftdm_size_t len = buflen;
350
351 if ((zst = ftdm_channel_read(pritap->dchan, buf, &len)) != FTDM_SUCCESS) {
352 if (zst == FTDM_FAIL) {
353 ftdm_log(FTDM_LOG_CRIT, "span %d D channel read fail! [%s]\n", pritap->span->span_id, pritap->dchan->last_error);
354 } else {
355 ftdm_log(FTDM_LOG_CRIT, "span %d D channel read timeout!\n", pritap->span->span_id);
356 }
357 return -1;
358 }
359
360 res = (int)len;
361
362 memset(&((unsigned char*)buf)[res],0,2);
363
364 res += 2;
365
366 return res;
367 }
368
369 static int pri_io_write(struct pri *pri, void *buf, int buflen)
370 {
371 pritap_t *pritap = pri_get_userdata(pri);
372 ftdm_size_t len = buflen - 2;
373
374 if (ftdm_channel_write(pritap->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
375 ftdm_log(FTDM_LOG_CRIT, "span %d D channel write failed! [%s]\n", pritap->span->span_id, pritap->dchan->last_error);
376 return -1;
377 }
378
379 return (int)buflen;
380 }
381
382 static int tap_pri_get_crv(struct pri *ctrl, q931_call *call)
383 {
384 int callmode = 0;
385 int crv = pri_get_crv(ctrl, call, &callmode);
386 crv <<= 3;
387 crv |= (callmode & 0x7);
388 return crv;
389 }
390
391 static passive_call_t *tap_pri_get_pcall_bycrv(pritap_t *pritap, int crv)
392 {
393 int i;
394 int tstcrv;
395
396 ftdm_mutex_lock(pritap->pcalls_lock);
397
398 for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
399 tstcrv = pritap->pcalls[i].callref ? tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref) : 0;
400 if (pritap->pcalls[i].callref && tstcrv == crv) {
401 if (!pritap->pcalls[i].inuse) {
402 ftdm_log(FTDM_LOG_ERROR, "Found crv %d in slot %d of span %s with call %p but is no longer in use!\n",
403 crv, i, pritap->span->name, pritap->pcalls[i].callref);
404 continue;
405 }
406
407 ftdm_mutex_unlock(pritap->pcalls_lock);
408
409 return &pritap->pcalls[i];
410 }
411 }
412
413 ftdm_mutex_unlock(pritap->pcalls_lock);
414
415 return NULL;
416 }
417
418 static passive_call_t *tap_pri_get_pcall(pritap_t *pritap, void *callref)
419 {
420 int i;
421 int crv;
422
423 ftdm_mutex_lock(pritap->pcalls_lock);
424
425 for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
426 if (pritap->pcalls[i].callref && !pritap->pcalls[i].inuse) {
427 crv = tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref);
428
429 ftdm_log(FTDM_LOG_DEBUG, "Garbage collecting callref %d/%p from span %s in slot %d\n",
430 crv, pritap->pcalls[i].callref, pritap->span->name, i);
431 pri_passive_destroycall(pritap->pri, pritap->pcalls[i].callref);
432 memset(&pritap->pcalls[i], 0, sizeof(pritap->pcalls[0]));
433 }
434 if (callref == pritap->pcalls[i].callref) {
435 pritap->pcalls[i].inuse = 1;
436
437 ftdm_mutex_unlock(pritap->pcalls_lock);
438
439 return &pritap->pcalls[i];
440 }
441 }
442
443 ftdm_mutex_unlock(pritap->pcalls_lock);
444
445 return NULL;
446 }
447
448 static void tap_pri_put_pcall(pritap_t *pritap, void *callref)
449 {
450 int i;
451 int crv;
452 int tstcrv;
453
454 if (!callref) {
455 ftdm_log(FTDM_LOG_ERROR, "Cannot put pcall for null callref in span %s\n", pritap->span->name);
456 return;
457 }
458
459 ftdm_mutex_lock(pritap->pcalls_lock);
460
461 crv = tap_pri_get_crv(pritap->pri, callref);
462 for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
463 if (!pritap->pcalls[i].callref) {
464 continue;
465 }
466 tstcrv = tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref);
467 if (tstcrv == crv) {
468 ftdm_log(FTDM_LOG_DEBUG, "releasing slot %d in span %s used by callref %d/%p\n", i,
469 pritap->span->name, crv, pritap->pcalls[i].callref);
470 if (!pritap->pcalls[i].inuse) {
471 ftdm_log(FTDM_LOG_ERROR, "slot %d in span %s used by callref %d/%p was released already?\n",
472 i, pritap->span->name, crv, pritap->pcalls[i].callref);
473 }
474 pritap->pcalls[i].inuse = 0;
475 }
476 }
477
478 ftdm_mutex_unlock(pritap->pcalls_lock);
479 }
480
481 static __inline__ ftdm_channel_t *tap_pri_get_fchan(pritap_t *pritap, passive_call_t *pcall, int channel)
482 {
483 ftdm_channel_t *fchan = NULL;
484 int chanpos = PRI_CHANNEL(channel);
485 if (!chanpos || chanpos > pritap->span->chan_count) {
486 ftdm_log(FTDM_LOG_CRIT, "Invalid pri tap channel %d requested in span %s\n", channel, pritap->span->name);
487 return NULL;
488 }
489
490 fchan = pritap->span->channels[PRI_CHANNEL(channel)];
491 if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
492 ftdm_log(FTDM_LOG_ERROR, "Channel %d requested in span %s is already in use!\n", channel, pritap->span->name);
493 return NULL;
494 }
495
496 if (ftdm_channel_open_chan(fchan) != FTDM_SUCCESS) {
497 ftdm_log(FTDM_LOG_ERROR, "Could not open tap channel %d requested in span %s\n", channel, pritap->span->name);
498 return NULL;
499 }
500
501 memset(&fchan->caller_data, 0, sizeof(fchan->caller_data));
502
503 ftdm_set_string(fchan->caller_data.cid_num.digits, pcall->callingnum.digits);
504 if (!ftdm_strlen_zero(pcall->callingname)) {
505 ftdm_set_string(fchan->caller_data.cid_name, pcall->callingname);
506 } else {
507 ftdm_set_string(fchan->caller_data.cid_name, pcall->callingnum.digits);
508 }
509 ftdm_set_string(fchan->caller_data.ani.digits, pcall->callingani.digits);
510 ftdm_set_string(fchan->caller_data.dnis.digits, pcall->callednum.digits);
511
512 return fchan;
513 }
514
515 static void handle_pri_passive_event(pritap_t *pritap, pri_event *e)
516 {
517 passive_call_t *pcall = NULL;
518 passive_call_t *peerpcall = NULL;
519 ftdm_channel_t *fchan = NULL;
520 ftdm_channel_t *peerfchan = NULL;
521 int layer1, transcap = 0;
522 int crv = 0;
523 pritap_t *peertap = pritap->peerspan->signal_data;
524
525 switch (e->e) {
526
527 case PRI_EVENT_RING:
528
529
530 crv = tap_pri_get_crv(pritap->pri, e->ring.call);
531 ftdm_log(FTDM_LOG_DEBUG, "Ring on channel %s:%d:%d with callref %d\n",
532 pritap->span->name, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), crv);
533 pcall = tap_pri_get_pcall_bycrv(pritap, crv);
534 if (pcall) {
535 ftdm_log(FTDM_LOG_WARNING, "There is a call with callref %d already, ignoring duplicated ring event\n", crv);
536 break;
537 }
538 pcall = tap_pri_get_pcall(pritap, NULL);
539 if (!pcall) {
540 ftdm_log(FTDM_LOG_ERROR, "Failed to get a free passive PRI call slot for callref %d, this is a bug!\n", crv);
541 break;
542 }
543 pcall->callref = e->ring.call;
544 ftdm_set_string(pcall->callingnum.digits, e->ring.callingnum);
545 ftdm_set_string(pcall->callingani.digits, e->ring.callingani);
546 ftdm_set_string(pcall->callednum.digits, e->ring.callednum);
547 ftdm_set_string(pcall->callingname, e->ring.callingname);
548 break;
549
550 case PRI_EVENT_PROGRESS:
551 crv = tap_pri_get_crv(pritap->pri, e->ring.call);
552 ftdm_log(FTDM_LOG_DEBUG, "Progress on channel %s:%d:%d with callref %d\n",
553 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
554 break;
555
556 case PRI_EVENT_PROCEEDING:
557 crv = tap_pri_get_crv(pritap->pri, e->proceeding.call);
558
559
560 ftdm_log(FTDM_LOG_DEBUG, "Proceeding on channel %s:%d:%d with callref %d\n",
561 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
562
563
564 if (!(pcall = tap_pri_get_pcall_bycrv(peertap, crv))) {
565 ftdm_log(FTDM_LOG_DEBUG,
566 "ignoring proceeding in channel %s:%d:%d for callref %d since we don't know about it",
567 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
568 break;
569 }
570 if (pcall->proceeding) {
571 ftdm_log(FTDM_LOG_DEBUG, "Ignoring duplicated proceeding with callref %d\n", crv);
572 break;
573 }
574 peerpcall = tap_pri_get_pcall(pritap, NULL);
575 if (!peerpcall) {
576 ftdm_log(FTDM_LOG_ERROR, "Failed to get a free peer PRI passive call slot for callref %d in span %s, this is a bug!\n",
577 crv, pritap->span->name);
578 break;
579 }
580 peerpcall->callref = e->proceeding.call;
581
582
583 layer1 = pri_get_layer1(peertap->pri, pcall->callref);
584 transcap = pri_get_transcap(peertap->pri, pcall->callref);
585
586 if (PRI_LAYER_1_ULAW != layer1 && PRI_LAYER_1_ALAW != layer1) {
587 ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported layer 1 format %d\n", crv, layer1);
588 break;
589 }
590
591 if (transcap != PRI_TRANS_CAP_SPEECH && transcap != PRI_TRANS_CAP_3_1K_AUDIO && transcap != PRI_TRANS_CAP_7K_AUDIO) {
592 ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported capability %d\n", crv, transcap);
593 break;
594 }
595
596 fchan = tap_pri_get_fchan(pritap, pcall, e->proceeding.channel);
597 if (!fchan) {
598 ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n",
599 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
600 break;
601 }
602 pcall->fchan = fchan;
603
604 peerfchan = tap_pri_get_fchan(peertap, pcall, e->proceeding.channel);
605 if (!peerfchan) {
606 ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n",
607 peertap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
608 break;
609 }
610 peerpcall->fchan = fchan;
611
612 fchan->call_data = peerfchan;
613 peerfchan->call_data = fchan;
614
615 ftdm_set_state_locked(fchan, FTDM_CHANNEL_STATE_RING);
616 break;
617
618 case PRI_EVENT_ANSWER:
619 crv = tap_pri_get_crv(pritap->pri, e->answer.call);
620 ftdm_log(FTDM_LOG_DEBUG, "Answer on channel %s:%d:%d with callref %d\n",
621 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
622 if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
623 ftdm_log(FTDM_LOG_DEBUG,
624 "ignoring answer in channel %s:%d:%d for callref %d since we don't know about it",
625 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
626 break;
627 }
628 ftdm_log_chan(pcall->fchan, FTDM_LOG_NOTICE, "Tapped call was answered in state %s\n", ftdm_channel_state2str(pcall->fchan->state));
629 break;
630
631 case PRI_EVENT_HANGUP_REQ:
632 crv = tap_pri_get_crv(pritap->pri, e->hangup.call);
633 ftdm_log(FTDM_LOG_DEBUG, "Hangup on channel %s:%d:%d with callref %d\n",
634 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
635
636 if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
637 ftdm_log(FTDM_LOG_DEBUG,
638 "ignoring hangup in channel %s:%d:%d for callref %d since we don't know about it",
639 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
640 break;
641 }
642
643 fchan = pcall->fchan;
644 ftdm_set_state_locked(fchan, FTDM_CHANNEL_STATE_TERMINATING);
645 break;
646
647 case PRI_EVENT_HANGUP_ACK:
648 crv = tap_pri_get_crv(pritap->pri, e->hangup.call);
649 ftdm_log(FTDM_LOG_DEBUG, "Hangup ack on channel %s:%d:%d with callref %d\n",
650 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
651 tap_pri_put_pcall(pritap, e->hangup.call);
652 tap_pri_put_pcall(peertap, e->hangup.call);
653 break;
654
655 default:
656 ftdm_log(FTDM_LOG_DEBUG, "Ignoring passive event %s on span %s\n", pri_event2str(e->gen.e), pritap->span->name);
657 break;
658
659 }
660 }
661
662 static void *ftdm_pritap_run(ftdm_thread_t *me, void *obj)
663 {
664 ftdm_span_t *span = (ftdm_span_t *) obj;
665 pritap_t *pritap = span->signal_data;
666 pri_event *event = NULL;
667 struct pollfd dpoll = { 0, 0, 0 };
668 int rc = 0;
669
670 ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread started on span %d\n", span->span_id);
671
672 pritap->span = span;
673
674 ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
675
676 if (ftdm_channel_open(span->span_id, pritap->dchan->chan_id, &pritap->dchan) != FTDM_SUCCESS) {
677 ftdm_log(FTDM_LOG_ERROR, "Failed to open D-channel for span %s\n", span->name);
678 goto done;
679 }
680
681 if ((pritap->pri = pri_new_cb(pritap->dchan->sockfd, PRI_NETWORK, PRI_SWITCH_NI2, pri_io_read, pri_io_write, pritap))){
682 pri_set_debug(pritap->pri, pritap->debug);
683 } else {
684 ftdm_log(FTDM_LOG_CRIT, "Failed to create tapping PRI\n");
685 goto done;
686 }
687
688 dpoll.fd = pritap->dchan->sockfd;
689
690 while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
691
692
693 pritap_check_state(span);
694
695 dpoll.revents = 0;
696 dpoll.events = POLLIN;
697
698 rc = poll(&dpoll, 1, 10);
699
700 if (rc < 0) {
701 if (errno == EINTR) {
702 ftdm_log(FTDM_LOG_DEBUG, "D-channel waiting interrupted, continuing ...\n");
703 continue;
704 }
705 ftdm_log(FTDM_LOG_ERROR, "poll failed: %s\n", strerror(errno));
706 continue;
707 }
708
709 pri_schedule_run(pritap->pri);
710
711 if (rc) {
712 if (dpoll.revents & POLLIN) {
713 event = pri_read_event(pritap->pri);
714 if (event) {
715 handle_pri_passive_event(pritap, event);
716 }
717 } else {
718 ftdm_log(FTDM_LOG_WARNING, "nothing to read?\n");
719 }
720 }
721
722 pritap_check_state(span);
723 }
724
725 done:
726 ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread ended on span %d\n", span->span_id);
727
728 ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
729 ftdm_clear_flag(pritap, PRITAP_RUNNING);
730
731 return NULL;
732 }
733
734 static ftdm_status_t ftdm_pritap_stop(ftdm_span_t *span)
735 {
736 pritap_t *pritap = span->signal_data;
737
738 if (!ftdm_test_flag(pritap, PRITAP_RUNNING)) {
739 return FTDM_FAIL;
740 }
741
742 ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
743
744 while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
745 ftdm_sleep(100);
746 }
747
748 ftdm_mutex_destroy(&pritap->pcalls_lock);
749 return FTDM_SUCCESS;
750 }
751
752 static ftdm_status_t ftdm_pritap_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size)
753 {
754 ftdm_status_t status;
755 fio_codec_t codec_func;
756 ftdm_channel_t *peerchan = ftdmchan->call_data;
757 int16_t chanbuf[size];
758 int16_t peerbuf[size];
759 int16_t mixedbuf[size];
760 int i = 0;
761 ftdm_size_t sizeread = size;
762
763 if (!FTDM_IS_VOICE_CHANNEL(ftdmchan) || !ftdmchan->call_data) {
764 return FTDM_SUCCESS;
765 }
766
767 if (ftdmchan->native_codec != peerchan->native_codec) {
768 ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Invalid peer channel with format %d, ours = %d\n",
769 peerchan->native_codec, ftdmchan->native_codec);
770 return FTDM_FAIL;
771 }
772
773 memcpy(chanbuf, data, size);
774 status = peerchan->fio->read(peerchan, peerbuf, &sizeread);
775 if (status != FTDM_SUCCESS) {
776 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to read from peer channel!\n");
777 return FTDM_FAIL;
778 }
779 if (sizeread != size) {
780 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "read from peer channel only %d bytes!\n", sizeread);
781 return FTDM_FAIL;
782 }
783
784 codec_func = peerchan->native_codec == FTDM_CODEC_ULAW ? fio_ulaw2slin : peerchan->native_codec == FTDM_CODEC_ALAW ? fio_alaw2slin : NULL;
785 if (codec_func) {
786 sizeread = size;
787 codec_func(chanbuf, sizeof(chanbuf), &sizeread);
788 sizeread = size;
789 codec_func(peerbuf, sizeof(peerbuf), &sizeread);
790 }
791
792 for (i = 0; i < size; i++) {
793 mixedbuf[i] = ftdm_saturated_add(chanbuf[i], peerbuf[i]);
794 }
795
796 codec_func = peerchan->native_codec == FTDM_CODEC_ULAW ? fio_slin2ulaw : peerchan->native_codec == FTDM_CODEC_ALAW ? fio_slin2alaw : NULL;
797 if (codec_func) {
798 size = sizeof(mixedbuf);
799 codec_func(mixedbuf, size, &size);
800 }
801 memcpy(data, mixedbuf, size);
802 return FTDM_SUCCESS;
803 }
804
805 static ftdm_status_t ftdm_pritap_start(ftdm_span_t *span)
806 {
807 ftdm_status_t ret;
808 pritap_t *pritap = span->signal_data;
809
810 if (ftdm_test_flag(pritap, PRITAP_RUNNING)) {
811 return FTDM_FAIL;
812 }
813
814 ftdm_mutex_create(&pritap->pcalls_lock);
815
816 ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
817 ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
818
819 ftdm_set_flag(pritap, PRITAP_RUNNING);
820 ret = ftdm_thread_create_detached(ftdm_pritap_run, span);
821
822 if (ret != FTDM_SUCCESS) {
823 return ret;
824 }
825
826 return ret;
827 }
828
829 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span)
830 {
831 uint32_t i;
832 const char *var, *val;
833 const char *debug = NULL;
834 ftdm_channel_t *dchan = NULL;
835 pritap_t *pritap = NULL;
836 ftdm_span_t *peerspan = NULL;
837 unsigned paramindex = 0;
838
839 if (span->trunk_type >= FTDM_TRUNK_NONE) {
840 ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type));
841 span->trunk_type = FTDM_TRUNK_T1;
842 }
843
844 for (i = 1; i <= span->chan_count; i++) {
845 if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
846 dchan = span->channels[i];
847 }
848 }
849
850 if (!dchan) {
851 ftdm_log(FTDM_LOG_ERROR, "No d-channel specified in freetdm.conf!\n", ftdm_trunk_type2str(span->trunk_type));
852 return FTDM_FAIL;
853 }
854
855 for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
856 var = ftdm_parameters[paramindex].var;
857 val = ftdm_parameters[paramindex].val;
858 ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI key=value, %s=%s\n", var, val);
859
860 if (!strcasecmp(var, "debug")) {
861 debug = val;
862 } else if (!strcasecmp(var, "peerspan")) {
863 if (ftdm_span_find_by_name(val, &peerspan) != FTDM_SUCCESS) {
864 ftdm_log(FTDM_LOG_ERROR, "Invalid tapping peer span %s\n", val);
865 break;
866 }
867 } else {
868 ftdm_log(FTDM_LOG_ERROR, "Unknown pri tapping parameter [%s]", var);
869 }
870 }
871
872 if (!peerspan) {
873 ftdm_log(FTDM_LOG_ERROR, "No valid peerspan was specified!\n");
874 return FTDM_FAIL;
875 }
876
877 pritap = ftdm_calloc(1, sizeof(*pritap));
878 if (!pritap) {
879 return FTDM_FAIL;
880 }
881
882 pritap->debug = parse_debug(debug);
883 pritap->dchan = dchan;
884 pritap->peerspan = peerspan;
885
886 span->start = ftdm_pritap_start;
887 span->stop = ftdm_pritap_stop;
888 span->sig_read = ftdm_pritap_sig_read;
889 span->signal_cb = sig_cb;
890
891 span->signal_data = pritap;
892 span->signal_type = FTDM_SIGTYPE_ISDN;
893 span->outgoing_call = pritap_outgoing_call;
894
895 span->get_channel_sig_status = pritap_get_channel_sig_status;
896 span->get_span_sig_status = pritap_get_span_sig_status;
897
898 span->state_map = &pritap_state_map;
899
900 return FTDM_SUCCESS;
901 }
902
903
904
905
906 ftdm_module_t ftdm_module = {
907 "pritap",
908 ftdm_pritap_io_init,
909 ftdm_pritap_unload,
910 ftdm_pritap_init,
911 NULL,
912 NULL,
913 ftdm_pritap_configure_span,
914 };
915
916
917
918
919
920
921
922
923
924
925
926