root/src/ftmod/ftmod_pritap/ftmod_pritap.c

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

DEFINITIONS

This source file includes following definitions.
  1. FIO_IO_UNLOAD_FUNCTION
  2. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  3. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  4. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  5. s_pri_error
  6. s_pri_message
  7. parse_debug
  8. FIO_API_FUNCTION
  9. FIO_IO_LOAD_FUNCTION
  10. FIO_SIG_LOAD_FUNCTION
  11. state_advance
  12. pritap_check_state
  13. pri_io_read
  14. pri_io_write
  15. tap_pri_get_crv
  16. tap_pri_get_pcall_bycrv
  17. tap_pri_get_pcall
  18. tap_pri_put_pcall
  19. tap_pri_get_fchan
  20. handle_pri_passive_event
  21. ftdm_pritap_run
  22. ftdm_pritap_stop
  23. ftdm_pritap_sig_read
  24. ftdm_pritap_start
  25. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION

   1 /*
   2  * Copyright (c) 2010, Moises Silva <moy@sangoma.com>
   3  * All rights reserved.
   4  * 
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 
   9  * * Redistributions of source code must retain the above copyright
  10  * notice, this list of conditions and the following disclaimer.
  11  * 
  12  * * Redistributions in binary form must reproduce the above copyright
  13  * notice, this list of conditions and the following disclaimer in the
  14  * documentation and/or other materials provided with the distribution.
  15  * 
  16  * * Neither the name of the original author; nor the names of any contributors
  17  * may be used to endorse or promote products derived from this software
  18  * without specific prior written permission.
  19  * 
  20  * 
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 
  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                         /* garbage collection */
 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                 /* we cannot use ftdm_channel_t because we still dont know which channel will be used 
 529                  * (ie, flexible channel was requested), thus, we need our own list of call references */
 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                 /* at this point we should know the real b chan that will be used and can therefore proceed to notify about the call, but
 559                  * only if a couple of call tests are passed first */
 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                 /* check that we already know about this call in the peer PRI (which was the one receiving the PRI_EVENT_RING event) */
 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                 /* check that the layer 1 and trans capability are supported */
 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  * \brief FreeTDM pritap signaling and IO module definition
 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 /* For Emacs:
 918  * Local Variables:
 919  * mode:c
 920  * indent-tabs-mode:t
 921  * tab-width:4
 922  * c-basic-offset:4
 923  * End:
 924  * For VIM:
 925  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
 926  */

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