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 ftdm_status_t 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         ftdm_channel_complete_state(ftdmchan);
 282 
 283         switch (ftdmchan->state) {
 284         case FTDM_CHANNEL_STATE_DOWN:
 285                 {                       
 286                         ftdmchan->call_data = NULL;
 287                         ftdm_channel_close(&ftdmchan);
 288 
 289                         peerchan->call_data = NULL;
 290                         ftdm_channel_close(&peerchan);
 291                 }
 292                 break;
 293 
 294         case FTDM_CHANNEL_STATE_PROGRESS:
 295         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 296         case FTDM_CHANNEL_STATE_UP:
 297         case FTDM_CHANNEL_STATE_HANGUP:
 298                 break;
 299 
 300         case FTDM_CHANNEL_STATE_RING:
 301                 {
 302                         sig.event_id = FTDM_SIGEVENT_START;
 303                         if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
 304                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
 305                         }
 306                 }
 307                 break;
 308 
 309         case FTDM_CHANNEL_STATE_TERMINATING:
 310                 {
 311                         if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP) {
 312                                 sig.event_id = FTDM_SIGEVENT_STOP;
 313                                 status = ftdm_span_send_signal(ftdmchan->span, &sig);
 314                         }
 315                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 316                 }
 317                 break;
 318 
 319         default:
 320                 {
 321                         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));
 322                 }
 323                 break;
 324         }
 325 
 326         return FTDM_SUCCESS;
 327 }
 328 
 329 static __inline__ void pritap_check_state(ftdm_span_t *span)
 330 {
 331         if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
 332                 uint32_t j;
 333                 ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
 334                 for(j = 1; j <= span->chan_count; j++) {
 335                         ftdm_mutex_lock(span->channels[j]->mutex);
 336                         ftdm_channel_advance_states(span->channels[j]);
 337                         ftdm_mutex_unlock(span->channels[j]->mutex);
 338                 }
 339         }
 340 }
 341 
 342 static int pri_io_read(struct pri *pri, void *buf, int buflen)
 343 {
 344         int res;
 345         ftdm_status_t zst;
 346         pritap_t *pritap = pri_get_userdata(pri);
 347         ftdm_size_t len = buflen;
 348 
 349         if ((zst = ftdm_channel_read(pritap->dchan, buf, &len)) != FTDM_SUCCESS) {
 350                 if (zst == FTDM_FAIL) {
 351                         ftdm_log(FTDM_LOG_CRIT, "span %d D channel read fail! [%s]\n", pritap->span->span_id, pritap->dchan->last_error);
 352                 } else {
 353                         ftdm_log(FTDM_LOG_CRIT, "span %d D channel read timeout!\n", pritap->span->span_id);
 354                 }
 355                 return -1;
 356         }
 357 
 358         res = (int)len;
 359 
 360         memset(&((unsigned char*)buf)[res],0,2);
 361 
 362         res += 2;
 363 
 364         return res;
 365 }
 366 
 367 static int pri_io_write(struct pri *pri, void *buf, int buflen)
 368 {
 369         pritap_t *pritap = pri_get_userdata(pri);
 370         ftdm_size_t len = buflen - 2; 
 371 
 372         if (ftdm_channel_write(pritap->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
 373                 ftdm_log(FTDM_LOG_CRIT, "span %d D channel write failed! [%s]\n", pritap->span->span_id, pritap->dchan->last_error);
 374                 return -1; 
 375         }   
 376 
 377         return (int)buflen;
 378 }
 379 
 380 static int tap_pri_get_crv(struct pri *ctrl, q931_call *call)
 381 {
 382         int callmode = 0;
 383         int crv = pri_get_crv(ctrl, call, &callmode);
 384         crv <<= 3;
 385         crv |= (callmode & 0x7);
 386         return crv;
 387 }
 388 
 389 static passive_call_t *tap_pri_get_pcall_bycrv(pritap_t *pritap, int crv)
 390 {
 391         int i;
 392         int tstcrv;
 393 
 394         ftdm_mutex_lock(pritap->pcalls_lock);
 395 
 396         for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
 397                 tstcrv = pritap->pcalls[i].callref ? tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref) : 0;
 398                 if (pritap->pcalls[i].callref && tstcrv == crv) {
 399                         if (!pritap->pcalls[i].inuse) {
 400                                 ftdm_log(FTDM_LOG_ERROR, "Found crv %d in slot %d of span %s with call %p but is no longer in use!\n", 
 401                                                 crv, i, pritap->span->name, pritap->pcalls[i].callref);
 402                                 continue;
 403                         }
 404 
 405                         ftdm_mutex_unlock(pritap->pcalls_lock);
 406 
 407                         return &pritap->pcalls[i];
 408                 }
 409         }
 410 
 411         ftdm_mutex_unlock(pritap->pcalls_lock);
 412 
 413         return NULL;
 414 }
 415 
 416 static passive_call_t *tap_pri_get_pcall(pritap_t *pritap, void *callref)
 417 {
 418         int i;
 419         int crv;
 420 
 421         ftdm_mutex_lock(pritap->pcalls_lock);
 422 
 423         for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
 424                 if (pritap->pcalls[i].callref && !pritap->pcalls[i].inuse) {
 425                         crv = tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref);
 426                         /* garbage collection */
 427                         ftdm_log(FTDM_LOG_DEBUG, "Garbage collecting callref %d/%p from span %s in slot %d\n", 
 428                                         crv, pritap->pcalls[i].callref, pritap->span->name, i);
 429                         pri_passive_destroycall(pritap->pri, pritap->pcalls[i].callref);
 430                         memset(&pritap->pcalls[i], 0, sizeof(pritap->pcalls[0]));
 431                 }
 432                 if (callref == pritap->pcalls[i].callref) {
 433                         pritap->pcalls[i].inuse = 1;
 434 
 435                         ftdm_mutex_unlock(pritap->pcalls_lock);
 436 
 437                         return &pritap->pcalls[i];
 438                 }
 439         }
 440 
 441         ftdm_mutex_unlock(pritap->pcalls_lock);
 442 
 443         return NULL;
 444 }
 445 
 446 static void tap_pri_put_pcall(pritap_t *pritap, void *callref)
 447 {
 448         int i;
 449         int crv;
 450         int tstcrv;
 451 
 452         if (!callref) {
 453                 ftdm_log(FTDM_LOG_ERROR, "Cannot put pcall for null callref in span %s\n", pritap->span->name);
 454                 return;
 455         }
 456 
 457         ftdm_mutex_lock(pritap->pcalls_lock);
 458 
 459         crv = tap_pri_get_crv(pritap->pri, callref);
 460         for (i = 0; i < ftdm_array_len(pritap->pcalls); i++) {
 461                 if (!pritap->pcalls[i].callref) {
 462                         continue;
 463                 }
 464                 tstcrv = tap_pri_get_crv(pritap->pri, pritap->pcalls[i].callref);
 465                 if (tstcrv == crv) {
 466                         ftdm_log(FTDM_LOG_DEBUG, "releasing slot %d in span %s used by callref %d/%p\n", i, 
 467                                         pritap->span->name, crv, pritap->pcalls[i].callref);
 468                         if (!pritap->pcalls[i].inuse) {
 469                                 ftdm_log(FTDM_LOG_ERROR, "slot %d in span %s used by callref %d/%p was released already?\n", 
 470                                                 i, pritap->span->name, crv, pritap->pcalls[i].callref);
 471                         }
 472                         pritap->pcalls[i].inuse = 0;
 473                 }
 474         }
 475 
 476         ftdm_mutex_unlock(pritap->pcalls_lock);
 477 }
 478 
 479 static __inline__ ftdm_channel_t *tap_pri_get_fchan(pritap_t *pritap, passive_call_t *pcall, int channel)
 480 {
 481         ftdm_channel_t *fchan = NULL;
 482         int chanpos = PRI_CHANNEL(channel);
 483         if (!chanpos || chanpos > pritap->span->chan_count) {
 484                 ftdm_log(FTDM_LOG_CRIT, "Invalid pri tap channel %d requested in span %s\n", channel, pritap->span->name);
 485                 return NULL;
 486         }
 487 
 488         fchan = pritap->span->channels[PRI_CHANNEL(channel)];
 489         if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
 490                 ftdm_log(FTDM_LOG_ERROR, "Channel %d requested in span %s is already in use!\n", channel, pritap->span->name);
 491                 return NULL;
 492         }
 493 
 494         if (ftdm_channel_open_chan(fchan) != FTDM_SUCCESS) {
 495                 ftdm_log(FTDM_LOG_ERROR, "Could not open tap channel %d requested in span %s\n", channel, pritap->span->name);
 496                 return NULL;
 497         }
 498 
 499         memset(&fchan->caller_data, 0, sizeof(fchan->caller_data));
 500 
 501         ftdm_set_string(fchan->caller_data.cid_num.digits, pcall->callingnum.digits);
 502         if (!ftdm_strlen_zero(pcall->callingname)) {
 503                 ftdm_set_string(fchan->caller_data.cid_name, pcall->callingname);
 504         } else {
 505                 ftdm_set_string(fchan->caller_data.cid_name, pcall->callingnum.digits);
 506         }
 507         ftdm_set_string(fchan->caller_data.ani.digits, pcall->callingani.digits);
 508         ftdm_set_string(fchan->caller_data.dnis.digits, pcall->callednum.digits);
 509 
 510         return fchan;
 511 }
 512 
 513 static void handle_pri_passive_event(pritap_t *pritap, pri_event *e)
 514 {
 515         passive_call_t *pcall = NULL;
 516         passive_call_t *peerpcall = NULL;
 517         ftdm_channel_t *fchan = NULL;
 518         ftdm_channel_t *peerfchan = NULL;
 519         int layer1, transcap = 0;
 520         int crv = 0;
 521         pritap_t *peertap = pritap->peerspan->signal_data;
 522 
 523         switch (e->e) {
 524 
 525         case PRI_EVENT_RING:
 526                 /* we cannot use ftdm_channel_t because we still dont know which channel will be used 
 527                  * (ie, flexible channel was requested), thus, we need our own list of call references */
 528                 crv = tap_pri_get_crv(pritap->pri, e->ring.call);
 529                 ftdm_log(FTDM_LOG_DEBUG, "Ring on channel %s:%d:%d with callref %d\n", 
 530                                 pritap->span->name, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), crv);
 531                 pcall = tap_pri_get_pcall_bycrv(pritap, crv);
 532                 if (pcall) {
 533                         ftdm_log(FTDM_LOG_WARNING, "There is a call with callref %d already, ignoring duplicated ring event\n", crv);
 534                         break;
 535                 }
 536                 pcall = tap_pri_get_pcall(pritap, NULL);
 537                 if (!pcall) {
 538                         ftdm_log(FTDM_LOG_ERROR, "Failed to get a free passive PRI call slot for callref %d, this is a bug!\n", crv);
 539                         break;
 540                 }
 541                 pcall->callref = e->ring.call;
 542                 ftdm_set_string(pcall->callingnum.digits, e->ring.callingnum);
 543                 ftdm_set_string(pcall->callingani.digits, e->ring.callingani);
 544                 ftdm_set_string(pcall->callednum.digits, e->ring.callednum);
 545                 ftdm_set_string(pcall->callingname, e->ring.callingname);
 546                 break;
 547 
 548         case PRI_EVENT_PROGRESS:
 549                 crv = tap_pri_get_crv(pritap->pri, e->ring.call);
 550                 ftdm_log(FTDM_LOG_DEBUG, "Progress on channel %s:%d:%d with callref %d\n", 
 551                                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 552                 break;
 553 
 554         case PRI_EVENT_PROCEEDING:
 555                 crv = tap_pri_get_crv(pritap->pri, e->proceeding.call);
 556                 /* at this point we should know the real b chan that will be used and can therefore proceed to notify about the call, but
 557                  * only if a couple of call tests are passed first */
 558                 ftdm_log(FTDM_LOG_DEBUG, "Proceeding on channel %s:%d:%d with callref %d\n", 
 559                                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 560 
 561                 /* check that we already know about this call in the peer PRI (which was the one receiving the PRI_EVENT_RING event) */
 562                 if (!(pcall = tap_pri_get_pcall_bycrv(peertap, crv))) {
 563                         ftdm_log(FTDM_LOG_DEBUG, 
 564                                 "ignoring proceeding in channel %s:%d:%d for callref %d since we don't know about it",
 565                                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 566                         break;
 567                 }
 568                 if (pcall->proceeding) {
 569                         ftdm_log(FTDM_LOG_DEBUG, "Ignoring duplicated proceeding with callref %d\n", crv);
 570                         break;
 571                 }
 572                 peerpcall = tap_pri_get_pcall(pritap, NULL);
 573                 if (!peerpcall) {
 574                         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", 
 575                                         crv, pritap->span->name);
 576                         break;
 577                 }
 578                 peerpcall->callref = e->proceeding.call;
 579 
 580                 /* check that the layer 1 and trans capability are supported */
 581                 layer1 = pri_get_layer1(peertap->pri, pcall->callref);
 582                 transcap = pri_get_transcap(peertap->pri, pcall->callref);
 583 
 584                 if (PRI_LAYER_1_ULAW != layer1 && PRI_LAYER_1_ALAW != layer1) {
 585                         ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported layer 1 format %d\n", crv, layer1);
 586                         break;
 587                 }
 588                 
 589                 if (transcap != PRI_TRANS_CAP_SPEECH && transcap != PRI_TRANS_CAP_3_1K_AUDIO && transcap != PRI_TRANS_CAP_7K_AUDIO) {
 590                         ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported capability %d\n", crv, transcap);
 591                         break;
 592                 }
 593 
 594                 fchan = tap_pri_get_fchan(pritap, pcall, e->proceeding.channel);
 595                 if (!fchan) {
 596                         ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n",
 597                                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 598                         break;
 599                 }
 600                 pcall->fchan = fchan;
 601 
 602                 peerfchan = tap_pri_get_fchan(peertap, pcall, e->proceeding.channel);
 603                 if (!peerfchan) {
 604                         ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n",
 605                                 peertap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 606                         break;
 607                 }
 608                 peerpcall->fchan = fchan;
 609 
 610                 fchan->call_data = peerfchan;
 611                 peerfchan->call_data = fchan;
 612 
 613                 ftdm_set_state_locked(fchan, FTDM_CHANNEL_STATE_RING);
 614                 break;
 615 
 616         case PRI_EVENT_ANSWER:
 617                 crv = tap_pri_get_crv(pritap->pri, e->answer.call);
 618                 ftdm_log(FTDM_LOG_DEBUG, "Answer on channel %s:%d:%d with callref %d\n", 
 619                                 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
 620                 if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
 621                         ftdm_log(FTDM_LOG_DEBUG, 
 622                                 "ignoring answer in channel %s:%d:%d for callref %d since we don't know about it",
 623                                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 624                         break;
 625                 }
 626                 ftdm_log_chan(pcall->fchan, FTDM_LOG_NOTICE, "Tapped call was answered in state %s\n", ftdm_channel_state2str(pcall->fchan->state));
 627                 break;
 628 
 629         case PRI_EVENT_HANGUP_REQ:
 630                 crv = tap_pri_get_crv(pritap->pri, e->hangup.call);
 631                 ftdm_log(FTDM_LOG_DEBUG, "Hangup on channel %s:%d:%d with callref %d\n", 
 632                                 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
 633 
 634                 if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
 635                         ftdm_log(FTDM_LOG_DEBUG, 
 636                                 "ignoring hangup in channel %s:%d:%d for callref %d since we don't know about it",
 637                                 pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
 638                         break;
 639                 }
 640 
 641                 fchan = pcall->fchan;
 642                 ftdm_set_state_locked(fchan, FTDM_CHANNEL_STATE_TERMINATING);
 643                 break;
 644 
 645         case PRI_EVENT_HANGUP_ACK:
 646                 crv = tap_pri_get_crv(pritap->pri, e->hangup.call);
 647                 ftdm_log(FTDM_LOG_DEBUG, "Hangup ack on channel %s:%d:%d with callref %d\n", 
 648                                 pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
 649                 tap_pri_put_pcall(pritap, e->hangup.call);
 650                 tap_pri_put_pcall(peertap, e->hangup.call);
 651                 break;
 652 
 653         default:
 654                 ftdm_log(FTDM_LOG_DEBUG, "Ignoring passive event %s on span %s\n", pri_event2str(e->gen.e), pritap->span->name);
 655                 break;
 656 
 657         }
 658 }
 659 
 660 static void *ftdm_pritap_run(ftdm_thread_t *me, void *obj)
 661 {
 662         ftdm_span_t *span = (ftdm_span_t *) obj;
 663         pritap_t *pritap = span->signal_data;
 664         pri_event *event = NULL;
 665         struct pollfd dpoll = { 0, 0, 0 };
 666         int rc = 0;
 667 
 668         ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread started on span %d\n", span->span_id);
 669         
 670         pritap->span = span;
 671 
 672         ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
 673         
 674         if (ftdm_channel_open(span->span_id, pritap->dchan->chan_id, &pritap->dchan) != FTDM_SUCCESS) {
 675                 ftdm_log(FTDM_LOG_ERROR, "Failed to open D-channel for span %s\n", span->name);
 676                 goto done;
 677         }
 678 
 679         if ((pritap->pri = pri_new_cb(pritap->dchan->sockfd, PRI_NETWORK, PRI_SWITCH_NI2, pri_io_read, pri_io_write, pritap))){
 680                 pri_set_debug(pritap->pri, pritap->debug);
 681         } else {
 682                 ftdm_log(FTDM_LOG_CRIT, "Failed to create tapping PRI\n");
 683                 goto done;
 684         }
 685 
 686         dpoll.fd = pritap->dchan->sockfd;
 687 
 688         while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
 689 
 690 
 691                 pritap_check_state(span);
 692 
 693                 dpoll.revents = 0;
 694                 dpoll.events = POLLIN;
 695 
 696                 rc = poll(&dpoll, 1, 10);
 697 
 698                 if (rc < 0) {
 699                         if (errno == EINTR) {
 700                                 ftdm_log(FTDM_LOG_DEBUG, "D-channel waiting interrupted, continuing ...\n");
 701                                 continue;
 702                         }
 703                         ftdm_log(FTDM_LOG_ERROR, "poll failed: %s\n", strerror(errno));
 704                         continue;
 705                 }
 706 
 707                 pri_schedule_run(pritap->pri);
 708 
 709                 if (rc) {
 710                         if (dpoll.revents & POLLIN) {
 711                                 event = pri_read_event(pritap->pri);
 712                                 if (event) {
 713                                         handle_pri_passive_event(pritap, event);
 714                                 }
 715                         } else {
 716                                 ftdm_log(FTDM_LOG_WARNING, "nothing to read?\n");
 717                         }
 718                 }
 719 
 720                 pritap_check_state(span);
 721         }
 722 
 723 done:
 724         ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread ended on span %d\n", span->span_id);
 725 
 726         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 727         ftdm_clear_flag(pritap, PRITAP_RUNNING);
 728 
 729         return NULL;
 730 }
 731 
 732 static ftdm_status_t ftdm_pritap_stop(ftdm_span_t *span)
 733 {
 734         pritap_t *pritap = span->signal_data;
 735 
 736         if (!ftdm_test_flag(pritap, PRITAP_RUNNING)) {
 737                 return FTDM_FAIL;
 738         }
 739 
 740         ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
 741 
 742         while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
 743                 ftdm_sleep(100);
 744         }
 745 
 746         ftdm_mutex_destroy(&pritap->pcalls_lock);
 747         return FTDM_SUCCESS;
 748 }
 749 
 750 static ftdm_status_t ftdm_pritap_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size)
 751 {
 752         ftdm_status_t status;
 753         fio_codec_t codec_func;
 754         ftdm_channel_t *peerchan = ftdmchan->call_data;
 755         int16_t chanbuf[size];
 756         int16_t peerbuf[size];
 757         int16_t mixedbuf[size];
 758         int i = 0;
 759         ftdm_size_t sizeread = size;
 760 
 761         if (!FTDM_IS_VOICE_CHANNEL(ftdmchan) || !ftdmchan->call_data) {
 762                 return FTDM_SUCCESS;
 763         }
 764 
 765         if (ftdmchan->native_codec != peerchan->native_codec) {
 766                 ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Invalid peer channel with format %d, ours = %d\n", 
 767                                 peerchan->native_codec, ftdmchan->native_codec);
 768                 return FTDM_FAIL;
 769         }
 770 
 771         memcpy(chanbuf, data, size);
 772         status = peerchan->fio->read(peerchan, peerbuf, &sizeread);
 773         if (status != FTDM_SUCCESS) {
 774                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to read from peer channel!\n");
 775                 return FTDM_FAIL;
 776         }
 777         if (sizeread != size) {
 778                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "read from peer channel only %d bytes!\n", sizeread);
 779                 return FTDM_FAIL;
 780         }
 781 
 782         codec_func = peerchan->native_codec == FTDM_CODEC_ULAW ? fio_ulaw2slin : peerchan->native_codec == FTDM_CODEC_ALAW ? fio_alaw2slin : NULL;
 783         if (codec_func) {
 784                 sizeread = size;
 785                 codec_func(chanbuf, sizeof(chanbuf), &sizeread);
 786                 sizeread = size;
 787                 codec_func(peerbuf, sizeof(peerbuf), &sizeread);
 788         }
 789 
 790         for (i = 0; i < size; i++) {
 791                 mixedbuf[i] = ftdm_saturated_add(chanbuf[i], peerbuf[i]);
 792         }
 793 
 794         codec_func = peerchan->native_codec == FTDM_CODEC_ULAW ? fio_slin2ulaw : peerchan->native_codec == FTDM_CODEC_ALAW ? fio_slin2alaw : NULL;
 795         if (codec_func) {
 796                 size = sizeof(mixedbuf);
 797                 codec_func(mixedbuf, size, &size);
 798         }
 799         memcpy(data, mixedbuf, size);
 800         return FTDM_SUCCESS;
 801 }
 802 
 803 static ftdm_status_t ftdm_pritap_start(ftdm_span_t *span)
 804 {
 805         ftdm_status_t ret;
 806         pritap_t *pritap = span->signal_data;
 807 
 808         if (ftdm_test_flag(pritap, PRITAP_RUNNING)) {
 809                 return FTDM_FAIL;
 810         }
 811 
 812         ftdm_mutex_create(&pritap->pcalls_lock);
 813 
 814         ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
 815         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 816 
 817         ftdm_set_flag(pritap, PRITAP_RUNNING);
 818         ret = ftdm_thread_create_detached(ftdm_pritap_run, span);
 819 
 820         if (ret != FTDM_SUCCESS) {
 821                 return ret;
 822         }
 823 
 824         return ret;
 825 }
 826 
 827 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span)
 828 {
 829         uint32_t i;
 830         const char *var, *val;
 831         const char *debug = NULL;
 832         ftdm_channel_t *dchan = NULL;
 833         pritap_t *pritap = NULL;
 834         ftdm_span_t *peerspan = NULL;
 835         unsigned paramindex = 0;
 836 
 837         if (span->trunk_type >= FTDM_TRUNK_NONE) {
 838                 ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type));
 839                 span->trunk_type = FTDM_TRUNK_T1;
 840         }
 841         
 842         for (i = 1; i <= span->chan_count; i++) {
 843                 if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
 844                         dchan = span->channels[i];
 845                 }
 846         }
 847 
 848         if (!dchan) {
 849                 ftdm_log(FTDM_LOG_ERROR, "No d-channel specified in freetdm.conf!\n", ftdm_trunk_type2str(span->trunk_type));
 850                 return FTDM_FAIL;
 851         }
 852         
 853         for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
 854                 var = ftdm_parameters[paramindex].var;
 855                 val = ftdm_parameters[paramindex].val;
 856                 ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI key=value, %s=%s\n", var, val);
 857 
 858                 if (!strcasecmp(var, "debug")) {
 859                         debug = val;
 860                 } else if (!strcasecmp(var, "peerspan")) {
 861                         if (ftdm_span_find_by_name(val, &peerspan) != FTDM_SUCCESS) {
 862                                 ftdm_log(FTDM_LOG_ERROR, "Invalid tapping peer span %s\n", val);
 863                                 break;
 864                         }
 865                 } else {
 866                         ftdm_log(FTDM_LOG_ERROR,  "Unknown pri tapping parameter [%s]", var);
 867                 }
 868         }
 869 
 870         if (!peerspan) {
 871                 ftdm_log(FTDM_LOG_ERROR, "No valid peerspan was specified!\n");
 872                 return FTDM_FAIL;
 873         }
 874     
 875         pritap = ftdm_calloc(1, sizeof(*pritap));
 876         if (!pritap) {
 877                 return FTDM_FAIL;
 878         }
 879 
 880         pritap->debug = parse_debug(debug);
 881         pritap->dchan = dchan;
 882         pritap->peerspan = peerspan;
 883 
 884         span->start = ftdm_pritap_start;
 885         span->stop = ftdm_pritap_stop;
 886         span->sig_read = ftdm_pritap_sig_read;
 887         span->signal_cb = sig_cb;
 888         
 889         span->signal_data = pritap;
 890         span->signal_type = FTDM_SIGTYPE_ISDN;
 891         span->outgoing_call = pritap_outgoing_call;
 892 
 893         span->get_channel_sig_status = pritap_get_channel_sig_status;
 894         span->get_span_sig_status = pritap_get_span_sig_status;
 895         
 896         span->state_map = &pritap_state_map;
 897         span->state_processor = state_advance;
 898 
 899         return FTDM_SUCCESS;
 900 }
 901 
 902 /**
 903  * \brief FreeTDM pritap signaling and IO module definition
 904  */
 905 ftdm_module_t ftdm_module = { 
 906         "pritap",
 907         ftdm_pritap_io_init,
 908         ftdm_pritap_unload,
 909         ftdm_pritap_init,
 910         NULL,
 911         NULL,
 912         ftdm_pritap_configure_span,
 913 };
 914 
 915 
 916 /* For Emacs:
 917  * Local Variables:
 918  * mode:c
 919  * indent-tabs-mode:t
 920  * tab-width:4
 921  * c-basic-offset:4
 922  * End:
 923  * For VIM:
 924  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
 925  */

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