root/src/ftmod/ftmod_libpri/lpwrap_pri.c

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

DEFINITIONS

This source file includes following definitions.
  1. gettimeofday
  2. lpwrap_pri_event_str
  3. __pri_lpwrap_read
  4. __pri_lpwrap_write
  5. lpwrap_init_pri
  6. lpwrap_init_bri
  7. lpwrap_one_loop
  8. lpwrap_run_pri

   1 /*
   2  * Copyright (c) 2009, Anthony Minessale II
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  * * Redistributions of source code must retain the above copyright
  10  * notice, this list of conditions and the following disclaimer.
  11  *
  12  * * Redistributions in binary form must reproduce the above copyright
  13  * notice, this list of conditions and the following disclaimer in the
  14  * documentation and/or other materials provided with the distribution.
  15  *
  16  * * Neither the name of the original author; nor the names of any contributors
  17  * may be used to endorse or promote products derived from this software
  18  * without specific prior written permission.
  19  *
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 
  34 //#define IODEBUG
  35 
  36 #include "private/ftdm_core.h"
  37 #include "lpwrap_pri.h"
  38 
  39 #ifndef HAVE_GETTIMEOFDAY
  40 #ifdef WIN32
  41 #include <mmsystem.h>
  42 
  43 static __inline int gettimeofday(struct timeval *tp, void *nothing)
  44 {
  45 #ifdef WITHOUT_MM_LIB
  46         SYSTEMTIME st;
  47         time_t tt;
  48         struct tm tmtm;
  49         /* mktime converts local to UTC */
  50         GetLocalTime (&st);
  51         tmtm.tm_sec = st.wSecond;
  52         tmtm.tm_min = st.wMinute;
  53         tmtm.tm_hour = st.wHour;
  54         tmtm.tm_mday = st.wDay;
  55         tmtm.tm_mon = st.wMonth - 1;
  56         tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
  57         tt = mktime (&tmtm);
  58         tp->tv_sec = tt;
  59         tp->tv_usec = st.wMilliseconds * 1000;
  60 #else
  61         /**
  62          ** The earlier time calculations using GetLocalTime
  63          ** had a time resolution of 10ms.The timeGetTime, part
  64          ** of multimedia apis offer a better time resolution
  65          ** of 1ms.Need to link against winmm.lib for this
  66          **/
  67         unsigned long Ticks = 0;
  68         unsigned long Sec =0;
  69         unsigned long Usec = 0;
  70         Ticks = timeGetTime();
  71 
  72         Sec = Ticks/1000;
  73         Usec = (Ticks - (Sec*1000))*1000;
  74         tp->tv_sec = Sec;
  75         tp->tv_usec = Usec;
  76 #endif /* WITHOUT_MM_LIB */
  77         (void)nothing;
  78         return 0;
  79 }
  80 #endif /* WIN32 */
  81 #endif /* HAVE_GETTIMEOFDAY */
  82 
  83 static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
  84         {0, LPWRAP_PRI_EVENT_ANY, "ANY"},
  85         {1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
  86         {2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
  87         {3, LPWRAP_PRI_EVENT_RESTART, "RESTART"},
  88         {4, LPWRAP_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
  89         {5, LPWRAP_PRI_EVENT_RING, "RING"},
  90         {6, LPWRAP_PRI_EVENT_HANGUP, "HANGUP"},
  91         {7, LPWRAP_PRI_EVENT_RINGING, "RINGING"},
  92         {8, LPWRAP_PRI_EVENT_ANSWER, "ANSWER"},
  93         {9, LPWRAP_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
  94         {10, LPWRAP_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
  95         {11, LPWRAP_PRI_EVENT_FACILITY, "FACILITY"},
  96         {12, LPWRAP_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
  97         {13, LPWRAP_PRI_EVENT_PROCEEDING, "PROCEEDING"},
  98         {14, LPWRAP_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
  99         {15, LPWRAP_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
 100         {16, LPWRAP_PRI_EVENT_NOTIFY, "NOTIFY"},
 101         {17, LPWRAP_PRI_EVENT_PROGRESS, "PROGRESS"},
 102         {18, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"},
 103         {19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
 104 };
 105 
 106 #define LINE "--------------------------------------------------------------------------------"
 107 
 108 const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
 109 {
 110         if (event_id < 0 || event_id >= LPWRAP_PRI_EVENT_MAX)
 111                 return "";
 112 
 113         return LPWRAP_PRI_EVENT_LIST[event_id].name;
 114 }
 115 
 116 static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
 117 {
 118         struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
 119         ftdm_size_t len = buflen;
 120         ftdm_status_t zst;
 121         int res;
 122 
 123         if ((zst = ftdm_channel_read(spri->dchan, buf, &len)) != FTDM_SUCCESS) {
 124                 if (zst == FTDM_FAIL) {
 125                         ftdm_log(FTDM_LOG_CRIT, "span %d D-READ FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
 126                         spri->errs++;
 127                 } else {
 128                         ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
 129                 }
 130                 /* we cannot return -1, libpri seems to expect values >= 0 */
 131                 return 0;
 132         }
 133         spri->errs = 0;
 134         res = (int)len;
 135 
 136         if (res > 0) {
 137                 memset(&((unsigned char*)buf)[res], 0, 2);
 138                 res += 2;
 139 #ifdef IODEBUG
 140                 {
 141                         char bb[2048] = { 0 };
 142 
 143                         print_hex_bytes(buf, res - 2, bb, sizeof(bb));
 144                         ftdm_log(FTDM_LOG_DEBUG, "READ %d\n", res - 2);
 145                 }
 146 #endif
 147         }
 148         return res;
 149 }
 150 
 151 static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
 152 {
 153         struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
 154         ftdm_size_t len = buflen - 2;
 155 
 156         if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
 157                 ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
 158                 /* we cannot return -1, libpri seems to expect values >= 0 */
 159                 return 0;
 160         }
 161 
 162 #ifdef IODEBUG
 163         {
 164                 char bb[2048] = { 0 };
 165 
 166                 print_hex_bytes(buf, buflen - 2, bb, sizeof(bb));
 167                 ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n", (int)buflen - 2);
 168         }
 169 #endif
 170         return (int)buflen;
 171 }
 172 
 173 int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug)
 174 {
 175         int ret = -1;
 176 
 177         memset(spri, 0, sizeof(struct lpwrap_pri));
 178         spri->dchan = dchan;
 179         spri->span  = span;
 180 
 181         if (!spri->dchan) {
 182                 ftdm_log(FTDM_LOG_ERROR, "No D-Channel available, unable to create PRI\n");
 183                 return ret;
 184         }
 185 
 186         if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))) {
 187                 unsigned char buf[4] = { 0 };
 188                 size_t buflen = sizeof(buf), len = 0;
 189 
 190                 pri_set_debug(spri->pri, debug);
 191 #ifdef HAVE_LIBPRI_AOC
 192                 pri_aoc_events_enable(spri->pri, 1);
 193 #endif
 194                 ftdm_channel_write(spri->dchan, buf, buflen, &len);
 195 
 196                 ret = 0;
 197         } else {
 198                 ftdm_log(FTDM_LOG_ERROR, "Unable to create PRI\n");
 199         }
 200         return ret;
 201 }
 202 
 203 int lpwrap_init_bri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int ptp, int debug)
 204 {
 205         int ret = -1;
 206 
 207 #ifdef HAVE_LIBPRI_BRI
 208         memset(spri, 0, sizeof(struct lpwrap_pri));
 209         spri->dchan = dchan;
 210         spri->span  = span;
 211 
 212         if (!spri->dchan) {
 213                 ftdm_log(FTDM_LOG_ERROR, "No D-Channel available, unable to create BRI\n");
 214                 return ret;
 215         }
 216 
 217         if ((spri->pri = pri_new_bri_cb(spri->dchan->sockfd, ptp, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))) {
 218                 unsigned char buf[4] = { 0 };
 219                 size_t buflen = sizeof(buf), len = 0;
 220 
 221                 pri_set_debug(spri->pri, debug);
 222 #ifdef HAVE_LIBPRI_AOC
 223                 pri_aoc_events_enable(spri->pri, 1);
 224 #endif
 225                 ftdm_channel_write(spri->dchan, buf, buflen, &len);
 226 
 227                 ret = 0;
 228         } else {
 229                 ftdm_log(FTDM_LOG_ERROR, "Unable to create BRI\n");
 230         }
 231 #else
 232         ftdm_log(FTDM_LOG_ERROR, "Installed libpri version (%s) has no BRI support\n",
 233                         pri_get_version());
 234 #endif
 235         return ret;
 236 }
 237 
 238 
 239 int lpwrap_one_loop(struct lpwrap_pri *spri)
 240 {
 241         fd_set rfds, efds;
 242         struct timeval now = {0,0}, *next = NULL;
 243         pri_event *event = NULL;
 244         event_handler handler;
 245         int sel;
 246 
 247         if (spri->on_loop) {
 248                 if ((sel = spri->on_loop(spri)) < 0) {
 249                         return sel;
 250                 }
 251         }
 252 
 253         if (spri->errs >= 2) {
 254                 spri->errs = 0;
 255                 return -1;
 256         }
 257 
 258         FD_ZERO(&rfds);
 259         FD_ZERO(&efds);
 260 
 261 #ifdef _MSC_VER
 262         //Windows macro for FD_SET includes a warning C4127: conditional expression is constant
 263 #pragma warning(push)
 264 #pragma warning(disable:4127)
 265 #endif
 266 
 267         FD_SET(pri_fd(spri->pri), &rfds);
 268         FD_SET(pri_fd(spri->pri), &efds);
 269 
 270 #ifdef _MSC_VER
 271 #pragma warning(pop)
 272 #endif
 273 
 274         now.tv_sec = 0;
 275         now.tv_usec = 100000;
 276 
 277         sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
 278         if (!sel) {
 279                 if ((next = pri_schedule_next(spri->pri))) {
 280                         gettimeofday(&now, NULL);
 281                         if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
 282                                 //ftdm_log(FTDM_LOG_DEBUG, "Check event\n");
 283                                 event = pri_schedule_run(spri->pri);
 284                         }
 285                 }
 286         } else if (sel > 0) {
 287                 event = pri_check_event(spri->pri);
 288         }
 289 
 290         if (event) {
 291                 /* 0 is catchall event handler */
 292                 if (event->e < 0 || event->e >= LPWRAP_PRI_EVENT_MAX) {
 293                         handler = spri->eventmap[0];
 294                 } else if (spri->eventmap[event->e]) {
 295                         handler = spri->eventmap[event->e];
 296                 } else {
 297                         handler = spri->eventmap[0];
 298                 }
 299 
 300                 if (handler) {
 301                         handler(spri, event->e, event);
 302                 } else {
 303                         ftdm_log(FTDM_LOG_CRIT, "No event handler found for event %d.\n", event->e);
 304                 }
 305         }
 306         return sel;
 307 }
 308 
 309 int lpwrap_run_pri(struct lpwrap_pri *spri)
 310 {
 311         int ret = 0;
 312 
 313         for (;;) {
 314                 if ((ret = lpwrap_one_loop(spri)) < 0) {
 315 #ifndef WIN32 //This needs to be adressed fror WIN32 still
 316                         if (errno == EINTR){
 317                                 /* Igonore an interrupted system call */
 318                                 continue;
 319                         }
 320 #endif
 321                         ftdm_log(FTDM_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
 322                         break;
 323                 }
 324         }
 325         return ret;
 326 }
 327 
 328 /* For Emacs:
 329  * Local Variables:
 330  * mode:c
 331  * indent-tabs-mode:t
 332  * tab-width:4
 333  * c-basic-offset:4
 334  * End:
 335  * For VIM:
 336  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
 337  */

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