00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include "asterisk.h"
00056
00057 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00058
00059 #include <sys/time.h>
00060 #include <signal.h>
00061 #include <fcntl.h>
00062
00063 #include "asterisk/udptl.h"
00064 #include "asterisk/frame.h"
00065 #include "asterisk/channel.h"
00066 #include "asterisk/acl.h"
00067 #include "asterisk/config.h"
00068 #include "asterisk/lock.h"
00069 #include "asterisk/utils.h"
00070 #include "asterisk/netsock.h"
00071 #include "asterisk/cli.h"
00072 #include "asterisk/unaligned.h"
00073
00074 #define UDPTL_MTU 1200
00075
00076 #if !defined(FALSE)
00077 #define FALSE 0
00078 #endif
00079 #if !defined(TRUE)
00080 #define TRUE (!FALSE)
00081 #endif
00082
00083 #define LOG_TAG(u) S_OR(u->tag, "no tag")
00084
00085 static int udptlstart = 4500;
00086 static int udptlend = 4599;
00087 static int udptldebug;
00088 static struct ast_sockaddr udptldebugaddr;
00089 #ifdef SO_NO_CHECK
00090 static int nochecksums;
00091 #endif
00092 static int udptlfecentries;
00093 static int udptlfecspan;
00094 static int use_even_ports;
00095
00096 #define LOCAL_FAX_MAX_DATAGRAM 1400
00097 #define DEFAULT_FAX_MAX_DATAGRAM 400
00098 #define FAX_MAX_DATAGRAM_LIMIT 1400
00099 #define MAX_FEC_ENTRIES 5
00100 #define MAX_FEC_SPAN 5
00101
00102 #define UDPTL_BUF_MASK 15
00103
00104 typedef struct {
00105 int buf_len;
00106 uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
00107 } udptl_fec_tx_buffer_t;
00108
00109 typedef struct {
00110 int buf_len;
00111 uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
00112 unsigned int fec_len[MAX_FEC_ENTRIES];
00113 uint8_t fec[MAX_FEC_ENTRIES][LOCAL_FAX_MAX_DATAGRAM];
00114 unsigned int fec_span;
00115 unsigned int fec_entries;
00116 } udptl_fec_rx_buffer_t;
00117
00118
00119 struct ast_udptl {
00120 int fd;
00121 char resp;
00122 struct ast_frame f[16];
00123 unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
00124 unsigned int lasteventseqn;
00125 int nat;
00126 int flags;
00127 struct ast_sockaddr us;
00128 struct ast_sockaddr them;
00129 int *ioid;
00130 struct sched_context *sched;
00131 struct io_context *io;
00132 void *data;
00133 char *tag;
00134 ast_udptl_callback callback;
00135
00136
00137
00138
00139 enum ast_t38_ec_modes error_correction_scheme;
00140
00141
00142
00143
00144 unsigned int error_correction_entries;
00145
00146
00147
00148
00149 unsigned int error_correction_span;
00150
00151
00152
00153
00154 int far_max_datagram;
00155
00156
00157
00158
00159
00160 int local_max_datagram;
00161
00162
00163
00164
00165
00166
00167
00168 int far_max_ifp;
00169
00170
00171
00172
00173
00174 int local_max_ifp;
00175
00176 unsigned int tx_seq_no;
00177 unsigned int rx_seq_no;
00178
00179 udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1];
00180 udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
00181 };
00182
00183 static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
00184
00185 static inline int udptl_debug_test_addr(const struct ast_sockaddr *addr)
00186 {
00187 if (udptldebug == 0)
00188 return 0;
00189
00190 if (ast_sockaddr_isnull(&udptldebugaddr)) {
00191 return 1;
00192 }
00193
00194 if (ast_sockaddr_port(&udptldebugaddr)) {
00195 return !ast_sockaddr_cmp(&udptldebugaddr, addr);
00196 } else {
00197 return !ast_sockaddr_cmp_addr(&udptldebugaddr, addr);
00198 }
00199 }
00200
00201 static int decode_length(uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue)
00202 {
00203 if (*len >= limit)
00204 return -1;
00205 if ((buf[*len] & 0x80) == 0) {
00206 *pvalue = buf[*len];
00207 (*len)++;
00208 return 0;
00209 }
00210 if ((buf[*len] & 0x40) == 0) {
00211 if (*len == limit - 1)
00212 return -1;
00213 *pvalue = (buf[*len] & 0x3F) << 8;
00214 (*len)++;
00215 *pvalue |= buf[*len];
00216 (*len)++;
00217 return 0;
00218 }
00219 *pvalue = (buf[*len] & 0x3F) << 14;
00220 (*len)++;
00221
00222 ast_debug(1, "UDPTL packet with length greater than 16K received, decoding will fail\n");
00223 return 1;
00224 }
00225
00226
00227 static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets)
00228 {
00229 unsigned int octet_cnt = 0;
00230
00231 if (decode_length(buf, limit, len, &octet_cnt) != 0)
00232 return -1;
00233
00234 if (octet_cnt > 0) {
00235
00236 if ((*len + octet_cnt) > limit)
00237 return -1;
00238
00239 *p_num_octets = octet_cnt;
00240 *p_object = &buf[*len];
00241 *len += octet_cnt;
00242 }
00243
00244 return 0;
00245 }
00246
00247
00248 static unsigned int encode_length(uint8_t *buf, unsigned int *len, unsigned int value)
00249 {
00250 unsigned int multiplier;
00251
00252 if (value < 0x80) {
00253
00254 buf[*len] = value;
00255 (*len)++;
00256 return value;
00257 }
00258 if (value < 0x4000) {
00259
00260
00261 buf[*len] = ((0x8000 | value) >> 8) & 0xFF;
00262 (*len)++;
00263 buf[*len] = value & 0xFF;
00264 (*len)++;
00265 return value;
00266 }
00267
00268 multiplier = (value < 0x10000) ? (value >> 14) : 4;
00269
00270 buf[*len] = 0xC0 | multiplier;
00271 (*len)++;
00272 return multiplier << 14;
00273 }
00274
00275
00276 static int encode_open_type(const struct ast_udptl *udptl, uint8_t *buf, unsigned int buflen,
00277 unsigned int *len, const uint8_t *data, unsigned int num_octets)
00278 {
00279 unsigned int enclen;
00280 unsigned int octet_idx;
00281 uint8_t zero_byte;
00282
00283
00284 if (num_octets == 0) {
00285 zero_byte = 0;
00286 data = &zero_byte;
00287 num_octets = 1;
00288 }
00289
00290 for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) {
00291 if ((enclen = encode_length(buf, len, num_octets)) < 0)
00292 return -1;
00293 if (enclen + *len > buflen) {
00294 ast_log(LOG_ERROR, "UDPTL (%s): Buffer overflow detected (%d + %d > %d)\n",
00295 LOG_TAG(udptl), enclen, *len, buflen);
00296 return -1;
00297 }
00298 if (enclen > 0) {
00299 memcpy(&buf[*len], &data[octet_idx], enclen);
00300 *len += enclen;
00301 }
00302 if (enclen >= num_octets)
00303 break;
00304 }
00305
00306 return 0;
00307 }
00308
00309
00310 static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
00311 {
00312 int stat1;
00313 int stat2;
00314 int i;
00315 int j;
00316 int k;
00317 int l;
00318 int m;
00319 int x;
00320 int limit;
00321 int which;
00322 unsigned int ptr;
00323 unsigned int count;
00324 int total_count;
00325 int seq_no;
00326 const uint8_t *ifp = NULL;
00327 const uint8_t *data = NULL;
00328 unsigned int ifp_len = 0;
00329 int repaired[16];
00330 const uint8_t *bufs[ARRAY_LEN(s->f) - 1];
00331 unsigned int lengths[ARRAY_LEN(s->f) - 1];
00332 int span;
00333 int entries;
00334 int ifp_no;
00335
00336 ptr = 0;
00337 ifp_no = 0;
00338 memset(&s->f[0], 0, sizeof(s->f[0]));
00339
00340
00341 if (ptr + 2 > len)
00342 return -1;
00343 seq_no = (buf[0] << 8) | buf[1];
00344 ptr += 2;
00345
00346
00347 if ((stat1 = decode_open_type(buf, len, &ptr, &ifp, &ifp_len)) != 0)
00348 return -1;
00349
00350 if (ptr + 1 > len)
00351 return -1;
00352 if ((buf[ptr++] & 0x80) == 0) {
00353
00354 if (seq_no > s->rx_seq_no) {
00355
00356
00357 total_count = 0;
00358 do {
00359 if ((stat2 = decode_length(buf, len, &ptr, &count)) < 0)
00360 return -1;
00361 for (i = 0; i < count && total_count + i < ARRAY_LEN(bufs); i++) {
00362 if ((stat1 = decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i])) != 0)
00363 return -1;
00364 }
00365 total_count += i;
00366 }
00367 while (stat2 > 0 && total_count < ARRAY_LEN(bufs));
00368
00369 for (i = total_count; i > 0; i--) {
00370 if (seq_no - i >= s->rx_seq_no) {
00371
00372
00373
00374 s->f[ifp_no].frametype = AST_FRAME_MODEM;
00375 s->f[ifp_no].subclass.codec = AST_MODEM_T38;
00376
00377 s->f[ifp_no].mallocd = 0;
00378 s->f[ifp_no].seqno = seq_no - i;
00379 s->f[ifp_no].datalen = lengths[i - 1];
00380 s->f[ifp_no].data.ptr = (uint8_t *) bufs[i - 1];
00381 s->f[ifp_no].offset = 0;
00382 s->f[ifp_no].src = "UDPTL";
00383 if (ifp_no > 0)
00384 AST_LIST_NEXT(&s->f[ifp_no - 1], frame_list) = &s->f[ifp_no];
00385 AST_LIST_NEXT(&s->f[ifp_no], frame_list) = NULL;
00386 ifp_no++;
00387 }
00388 }
00389 }
00390 }
00391 else
00392 {
00393
00394
00395 if (ifp_len > LOCAL_FAX_MAX_DATAGRAM)
00396 return -1;
00397
00398 for ( ; seq_no > s->rx_seq_no; s->rx_seq_no++) {
00399 x = s->rx_seq_no & UDPTL_BUF_MASK;
00400 s->rx[x].buf_len = -1;
00401 s->rx[x].fec_len[0] = 0;
00402 s->rx[x].fec_span = 0;
00403 s->rx[x].fec_entries = 0;
00404 }
00405
00406 x = seq_no & UDPTL_BUF_MASK;
00407
00408 memset(repaired, 0, sizeof(repaired));
00409
00410
00411 memcpy(s->rx[x].buf, ifp, ifp_len);
00412 s->rx[x].buf_len = ifp_len;
00413 repaired[x] = TRUE;
00414
00415
00416
00417
00418 if (ptr + 2 > len)
00419 return -1;
00420 if (buf[ptr++] != 1)
00421 return -1;
00422 span = buf[ptr++];
00423 s->rx[x].fec_span = span;
00424
00425
00426
00427 if (ptr + 1 > len)
00428 return -1;
00429 entries = buf[ptr++];
00430 if (entries > MAX_FEC_ENTRIES) {
00431 return -1;
00432 }
00433 s->rx[x].fec_entries = entries;
00434
00435
00436 for (i = 0; i < entries; i++) {
00437 if ((stat1 = decode_open_type(buf, len, &ptr, &data, &s->rx[x].fec_len[i])) != 0)
00438 return -1;
00439 if (s->rx[x].fec_len[i] > LOCAL_FAX_MAX_DATAGRAM)
00440 return -1;
00441
00442
00443 memcpy(s->rx[x].fec[i], data, s->rx[x].fec_len[i]);
00444 #if 0
00445 fprintf(stderr, "FEC: ");
00446 for (j = 0; j < s->rx[x].fec_len[i]; j++)
00447 fprintf(stderr, "%02X ", data[j]);
00448 fprintf(stderr, "\n");
00449 #endif
00450 }
00451
00452
00453
00454 for (l = x; l != ((x - (16 - span*entries)) & UDPTL_BUF_MASK); l = (l - 1) & UDPTL_BUF_MASK) {
00455 if (s->rx[l].fec_len[0] <= 0)
00456 continue;
00457 for (m = 0; m < s->rx[l].fec_entries; m++) {
00458 limit = (l + m) & UDPTL_BUF_MASK;
00459 for (which = -1, k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit; k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) {
00460 if (s->rx[k].buf_len <= 0)
00461 which = (which == -1) ? k : -2;
00462 }
00463 if (which >= 0) {
00464
00465 for (j = 0; j < s->rx[l].fec_len[m]; j++) {
00466 s->rx[which].buf[j] = s->rx[l].fec[m][j];
00467 for (k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit; k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK)
00468 s->rx[which].buf[j] ^= (s->rx[k].buf_len > j) ? s->rx[k].buf[j] : 0;
00469 }
00470 s->rx[which].buf_len = s->rx[l].fec_len[m];
00471 repaired[which] = TRUE;
00472 }
00473 }
00474 }
00475
00476 for (l = (x + 1) & UDPTL_BUF_MASK, j = seq_no - UDPTL_BUF_MASK; l != x; l = (l + 1) & UDPTL_BUF_MASK, j++) {
00477 if (repaired[l]) {
00478
00479 s->f[ifp_no].frametype = AST_FRAME_MODEM;
00480 s->f[ifp_no].subclass.codec = AST_MODEM_T38;
00481
00482 s->f[ifp_no].mallocd = 0;
00483 s->f[ifp_no].seqno = j;
00484 s->f[ifp_no].datalen = s->rx[l].buf_len;
00485 s->f[ifp_no].data.ptr = s->rx[l].buf;
00486 s->f[ifp_no].offset = 0;
00487 s->f[ifp_no].src = "UDPTL";
00488 if (ifp_no > 0)
00489 AST_LIST_NEXT(&s->f[ifp_no - 1], frame_list) = &s->f[ifp_no];
00490 AST_LIST_NEXT(&s->f[ifp_no], frame_list) = NULL;
00491 ifp_no++;
00492 }
00493 }
00494 }
00495
00496
00497
00498 if (seq_no >= s->rx_seq_no) {
00499
00500 s->f[ifp_no].frametype = AST_FRAME_MODEM;
00501 s->f[ifp_no].subclass.codec = AST_MODEM_T38;
00502
00503 s->f[ifp_no].mallocd = 0;
00504 s->f[ifp_no].seqno = seq_no;
00505 s->f[ifp_no].datalen = ifp_len;
00506 s->f[ifp_no].data.ptr = (uint8_t *) ifp;
00507 s->f[ifp_no].offset = 0;
00508 s->f[ifp_no].src = "UDPTL";
00509 if (ifp_no > 0)
00510 AST_LIST_NEXT(&s->f[ifp_no - 1], frame_list) = &s->f[ifp_no];
00511 AST_LIST_NEXT(&s->f[ifp_no], frame_list) = NULL;
00512
00513 ifp_no++;
00514 }
00515
00516 s->rx_seq_no = seq_no + 1;
00517 return ifp_no;
00518 }
00519
00520
00521 static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len)
00522 {
00523 uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2] = { 0, };
00524 int i;
00525 int j;
00526 int seq;
00527 int entry;
00528 int entries;
00529 int span;
00530 int m;
00531 unsigned int len;
00532 int limit;
00533 int high_tide;
00534
00535 seq = s->tx_seq_no & 0xFFFF;
00536
00537
00538 entry = seq & UDPTL_BUF_MASK;
00539
00540
00541
00542 s->tx[entry].buf_len = ifp_len;
00543 memcpy(s->tx[entry].buf, ifp, ifp_len);
00544
00545
00546
00547 len = 0;
00548
00549 buf[len++] = (seq >> 8) & 0xFF;
00550 buf[len++] = seq & 0xFF;
00551
00552
00553 if (encode_open_type(s, buf, buflen, &len, ifp, ifp_len) < 0)
00554 return -1;
00555
00556
00557 switch (s->error_correction_scheme)
00558 {
00559 case UDPTL_ERROR_CORRECTION_NONE:
00560
00561 buf[len++] = 0x00;
00562
00563
00564 if (encode_length(buf, &len, 0) < 0)
00565 return -1;
00566 break;
00567 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00568
00569 buf[len++] = 0x00;
00570 if (s->tx_seq_no > s->error_correction_entries)
00571 entries = s->error_correction_entries;
00572 else
00573 entries = s->tx_seq_no;
00574
00575
00576 if (encode_length(buf, &len, entries) < 0)
00577 return -1;
00578
00579 for (i = 0; i < entries; i++) {
00580 j = (entry - i - 1) & UDPTL_BUF_MASK;
00581 if (encode_open_type(s, buf, buflen, &len, s->tx[j].buf, s->tx[j].buf_len) < 0) {
00582 ast_debug(1, "UDPTL (%s): Encoding failed at i=%d, j=%d\n",
00583 LOG_TAG(s), i, j);
00584 return -1;
00585 }
00586 }
00587 break;
00588 case UDPTL_ERROR_CORRECTION_FEC:
00589 span = s->error_correction_span;
00590 entries = s->error_correction_entries;
00591 if (seq < s->error_correction_span*s->error_correction_entries) {
00592
00593 entries = seq/s->error_correction_span;
00594 if (seq < s->error_correction_span)
00595 span = 0;
00596 }
00597
00598 buf[len++] = 0x80;
00599
00600
00601 buf[len++] = 1;
00602 buf[len++] = span;
00603
00604
00605 buf[len++] = entries;
00606 for (m = 0; m < entries; m++) {
00607
00608 limit = (entry + m) & UDPTL_BUF_MASK;
00609 high_tide = 0;
00610 for (i = (limit - span*entries) & UDPTL_BUF_MASK; i != limit; i = (i + entries) & UDPTL_BUF_MASK) {
00611 if (high_tide < s->tx[i].buf_len) {
00612 for (j = 0; j < high_tide; j++)
00613 fec[j] ^= s->tx[i].buf[j];
00614 for ( ; j < s->tx[i].buf_len; j++)
00615 fec[j] = s->tx[i].buf[j];
00616 high_tide = s->tx[i].buf_len;
00617 } else {
00618 for (j = 0; j < s->tx[i].buf_len; j++)
00619 fec[j] ^= s->tx[i].buf[j];
00620 }
00621 }
00622 if (encode_open_type(s, buf, buflen, &len, fec, high_tide) < 0)
00623 return -1;
00624 }
00625 break;
00626 }
00627
00628 s->tx_seq_no++;
00629 return len;
00630 }
00631
00632 int ast_udptl_fd(const struct ast_udptl *udptl)
00633 {
00634 return udptl->fd;
00635 }
00636
00637 void ast_udptl_set_data(struct ast_udptl *udptl, void *data)
00638 {
00639 udptl->data = data;
00640 }
00641
00642 void ast_udptl_set_callback(struct ast_udptl *udptl, ast_udptl_callback callback)
00643 {
00644 udptl->callback = callback;
00645 }
00646
00647 void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
00648 {
00649 udptl->nat = nat;
00650 }
00651
00652 static int udptlread(int *id, int fd, short events, void *cbdata)
00653 {
00654 struct ast_udptl *udptl = cbdata;
00655 struct ast_frame *f;
00656
00657 if ((f = ast_udptl_read(udptl))) {
00658 if (udptl->callback)
00659 udptl->callback(udptl, f, udptl->data);
00660 }
00661 return 1;
00662 }
00663
00664 struct ast_frame *ast_udptl_read(struct ast_udptl *udptl)
00665 {
00666 int res;
00667 struct ast_sockaddr addr;
00668 uint8_t *buf;
00669
00670 buf = udptl->rawdata + AST_FRIENDLY_OFFSET;
00671
00672
00673 res = ast_recvfrom(udptl->fd,
00674 buf,
00675 sizeof(udptl->rawdata) - AST_FRIENDLY_OFFSET,
00676 0,
00677 &addr);
00678 if (res < 0) {
00679 if (errno != EAGAIN)
00680 ast_log(LOG_WARNING, "UDPTL (%s): read error: %s\n",
00681 LOG_TAG(udptl), strerror(errno));
00682 ast_assert(errno != EBADF);
00683 return &ast_null_frame;
00684 }
00685
00686
00687 if (ast_sockaddr_isnull(&udptl->them)) {
00688 return &ast_null_frame;
00689 }
00690
00691 if (udptl->nat) {
00692
00693 if (ast_sockaddr_cmp(&udptl->them, &addr)) {
00694 ast_sockaddr_copy(&udptl->them, &addr);
00695 ast_debug(1, "UDPTL (%s): NAT, Using address %s\n",
00696 LOG_TAG(udptl), ast_sockaddr_stringify(&udptl->them));
00697 }
00698 }
00699
00700 if (udptl_debug_test_addr(&addr)) {
00701 int seq_no;
00702
00703
00704 if (res < 2) {
00705
00706 seq_no = -1;
00707 } else {
00708 seq_no = (buf[0] << 8) | buf[1];
00709 }
00710
00711 ast_verb(1, "UDPTL (%s): packet from %s (seq %d, len %d)\n",
00712 LOG_TAG(udptl), ast_sockaddr_stringify(&addr), seq_no, res);
00713 }
00714 if (udptl_rx_packet(udptl, buf, res) < 1) {
00715 return &ast_null_frame;
00716 }
00717
00718 return &udptl->f[0];
00719 }
00720
00721 static void calculate_local_max_datagram(struct ast_udptl *udptl)
00722 {
00723 unsigned int new_max = 0;
00724
00725 if (udptl->local_max_ifp == -1) {
00726 ast_log(LOG_WARNING, "UDPTL (%s): Cannot calculate local_max_datagram before local_max_ifp has been set.\n",
00727 LOG_TAG(udptl));
00728 udptl->local_max_datagram = -1;
00729 return;
00730 }
00731
00732
00733
00734
00735
00736
00737
00738 switch (udptl->error_correction_scheme) {
00739 case UDPTL_ERROR_CORRECTION_NONE:
00740
00741
00742
00743 new_max = 5 + udptl->local_max_ifp;
00744 break;
00745 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00746
00747
00748
00749 new_max = 5 + udptl->local_max_ifp + 2 + (3 * udptl->local_max_ifp);
00750 break;
00751 case UDPTL_ERROR_CORRECTION_FEC:
00752
00753
00754
00755 new_max = 5 + udptl->local_max_ifp + 4 + udptl->local_max_ifp;
00756 break;
00757 }
00758
00759 udptl->local_max_datagram = MIN(new_max * 1.05, LOCAL_FAX_MAX_DATAGRAM);
00760 }
00761
00762 static void calculate_far_max_ifp(struct ast_udptl *udptl)
00763 {
00764 unsigned new_max = 0;
00765
00766 if (udptl->far_max_datagram == -1) {
00767 ast_log(LOG_WARNING, "UDPTL (%s): Cannot calculate far_max_ifp before far_max_datagram has been set.\n",
00768 LOG_TAG(udptl));
00769 udptl->far_max_ifp = -1;
00770 return;
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 switch (udptl->error_correction_scheme) {
00787 case UDPTL_ERROR_CORRECTION_NONE:
00788
00789
00790
00791 new_max = udptl->far_max_datagram - 5;
00792 break;
00793 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 for (;;) {
00807 new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1);
00808
00809 if ((new_max < 80) && (udptl->error_correction_entries > 1)) {
00810
00811
00812
00813 --udptl->error_correction_entries;
00814 } else {
00815 break;
00816 }
00817 }
00818 break;
00819 case UDPTL_ERROR_CORRECTION_FEC:
00820
00821
00822
00823 new_max = (udptl->far_max_datagram - 10) / 2;
00824 break;
00825 }
00826
00827 udptl->far_max_ifp = new_max * 0.95;
00828 }
00829
00830 enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
00831 {
00832 return udptl->error_correction_scheme;
00833 }
00834
00835 void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
00836 {
00837 udptl->error_correction_scheme = ec;
00838 switch (ec) {
00839 case UDPTL_ERROR_CORRECTION_FEC:
00840 udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
00841 if (udptl->error_correction_entries == 0) {
00842 udptl->error_correction_entries = 3;
00843 }
00844 if (udptl->error_correction_span == 0) {
00845 udptl->error_correction_span = 3;
00846 }
00847 break;
00848 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00849 udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
00850 if (udptl->error_correction_entries == 0) {
00851 udptl->error_correction_entries = 3;
00852 }
00853 break;
00854 default:
00855
00856 break;
00857 };
00858
00859 udptl->local_max_datagram = -1;
00860 udptl->far_max_ifp = -1;
00861 }
00862
00863 void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
00864 {
00865
00866
00867 if ((signed int) max_ifp > 0) {
00868 udptl->local_max_ifp = max_ifp;
00869
00870 udptl->local_max_datagram = -1;
00871 }
00872 }
00873
00874 unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
00875 {
00876 if (udptl->local_max_datagram == -1) {
00877 calculate_local_max_datagram(udptl);
00878 }
00879
00880
00881 if (udptl->local_max_datagram < 0) {
00882 return 0;
00883 }
00884 return udptl->local_max_datagram;
00885 }
00886
00887 void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram)
00888 {
00889 if (!max_datagram || (max_datagram > FAX_MAX_DATAGRAM_LIMIT)) {
00890 udptl->far_max_datagram = DEFAULT_FAX_MAX_DATAGRAM;
00891 } else {
00892 udptl->far_max_datagram = max_datagram;
00893 }
00894
00895 udptl->far_max_ifp = -1;
00896 }
00897
00898 unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl)
00899 {
00900 if (udptl->far_max_datagram < 0) {
00901 return 0;
00902 }
00903 return udptl->far_max_datagram;
00904 }
00905
00906 unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
00907 {
00908 if (udptl->far_max_ifp == -1) {
00909 calculate_far_max_ifp(udptl);
00910 }
00911
00912 if (udptl->far_max_ifp < 0) {
00913 return 0;
00914 }
00915 return udptl->far_max_ifp;
00916 }
00917
00918 struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct ast_sockaddr *addr)
00919 {
00920 struct ast_udptl *udptl;
00921 int x;
00922 int startplace;
00923 int i;
00924 long int flags;
00925
00926 if (!(udptl = ast_calloc(1, sizeof(*udptl))))
00927 return NULL;
00928
00929 udptl->error_correction_span = udptlfecspan;
00930 udptl->error_correction_entries = udptlfecentries;
00931
00932 udptl->far_max_datagram = -1;
00933 udptl->far_max_ifp = -1;
00934 udptl->local_max_ifp = -1;
00935 udptl->local_max_datagram = -1;
00936
00937 for (i = 0; i <= UDPTL_BUF_MASK; i++) {
00938 udptl->rx[i].buf_len = -1;
00939 udptl->tx[i].buf_len = -1;
00940 }
00941
00942 if ((udptl->fd = socket(ast_sockaddr_is_ipv6(addr) ?
00943 AF_INET6 : AF_INET, SOCK_DGRAM, 0)) < 0) {
00944 ast_free(udptl);
00945 ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
00946 return NULL;
00947 }
00948 flags = fcntl(udptl->fd, F_GETFL);
00949 fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK);
00950 #ifdef SO_NO_CHECK
00951 if (nochecksums)
00952 setsockopt(udptl->fd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
00953 #endif
00954
00955 x = (udptlstart == udptlend) ? udptlstart : (ast_random() % (udptlend - udptlstart)) + udptlstart;
00956 if (use_even_ports && (x & 1)) {
00957 ++x;
00958 }
00959 startplace = x;
00960 for (;;) {
00961 ast_sockaddr_copy(&udptl->us, addr);
00962 ast_sockaddr_set_port(&udptl->us, x);
00963 if (ast_bind(udptl->fd, &udptl->us) == 0) {
00964 break;
00965 }
00966 if (errno != EADDRINUSE) {
00967 ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno));
00968 close(udptl->fd);
00969 ast_free(udptl);
00970 return NULL;
00971 }
00972 if (use_even_ports) {
00973 x += 2;
00974 } else {
00975 ++x;
00976 }
00977 if (x > udptlend)
00978 x = udptlstart;
00979 if (x == startplace) {
00980 ast_log(LOG_WARNING, "No UDPTL ports remaining\n");
00981 close(udptl->fd);
00982 ast_free(udptl);
00983 return NULL;
00984 }
00985 }
00986 if (io && sched && callbackmode) {
00987
00988 udptl->sched = sched;
00989 udptl->io = io;
00990 udptl->ioid = ast_io_add(udptl->io, udptl->fd, udptlread, AST_IO_IN, udptl);
00991 }
00992 return udptl;
00993 }
00994
00995 void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format, ...)
00996 {
00997 va_list ap;
00998
00999 ast_free(udptl->tag);
01000 udptl->tag = NULL;
01001 va_start(ap, format);
01002 if (ast_vasprintf(&udptl->tag, format, ap) == -1) {
01003 udptl->tag = NULL;
01004 }
01005 va_end(ap);
01006 }
01007
01008 int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos)
01009 {
01010 return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL");
01011 }
01012
01013 void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
01014 {
01015 ast_sockaddr_copy(&udptl->them, them);
01016 }
01017
01018 void ast_udptl_get_peer(const struct ast_udptl *udptl, struct ast_sockaddr *them)
01019 {
01020 ast_sockaddr_copy(them, &udptl->them);
01021 }
01022
01023 void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
01024 {
01025 ast_sockaddr_copy(us, &udptl->us);
01026 }
01027
01028 void ast_udptl_stop(struct ast_udptl *udptl)
01029 {
01030 ast_sockaddr_setnull(&udptl->them);
01031 }
01032
01033 void ast_udptl_destroy(struct ast_udptl *udptl)
01034 {
01035 if (udptl->ioid)
01036 ast_io_remove(udptl->io, udptl->ioid);
01037 if (udptl->fd > -1)
01038 close(udptl->fd);
01039 if (udptl->tag)
01040 ast_free(udptl->tag);
01041 ast_free(udptl);
01042 }
01043
01044 int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
01045 {
01046 unsigned int seq;
01047 unsigned int len = f->datalen;
01048 int res;
01049
01050 const int bufsize = (s->far_max_datagram > 0) ? s->far_max_datagram : DEFAULT_FAX_MAX_DATAGRAM;
01051 uint8_t buf[bufsize];
01052
01053 memset(buf, 0, sizeof(buf));
01054
01055
01056 if (ast_sockaddr_isnull(&s->them)) {
01057 return 0;
01058 }
01059
01060
01061 if (f->datalen == 0)
01062 return 0;
01063
01064 if ((f->frametype != AST_FRAME_MODEM) ||
01065 (f->subclass.codec != AST_MODEM_T38)) {
01066 ast_log(LOG_WARNING, "UDPTL (%s): UDPTL can only send T.38 data.\n",
01067 LOG_TAG(s));
01068 return -1;
01069 }
01070
01071 if (len > s->far_max_ifp) {
01072 ast_log(LOG_WARNING,
01073 "UDPTL (%s): UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss will occur."
01074 "You may need to override the T38FaxMaxDatagram value for this endpoint in the channel driver configuration.\n",
01075 LOG_TAG(s), len, s->far_max_ifp);
01076 len = s->far_max_ifp;
01077 }
01078
01079
01080 seq = s->tx_seq_no & 0xFFFF;
01081
01082
01083 len = udptl_build_packet(s, buf, sizeof(buf), f->data.ptr, len);
01084
01085 if ((signed int) len > 0 && !ast_sockaddr_isnull(&s->them)) {
01086 if ((res = ast_sendto(s->fd, buf, len, 0, &s->them)) < 0)
01087 ast_log(LOG_NOTICE, "UDPTL (%s): Transmission error to %s: %s\n",
01088 LOG_TAG(s), ast_sockaddr_stringify(&s->them), strerror(errno));
01089 if (udptl_debug_test_addr(&s->them))
01090 ast_verb(1, "UDPTL (%s): packet to %s (seq %d, len %d)\n",
01091 LOG_TAG(s), ast_sockaddr_stringify(&s->them), seq, len);
01092 }
01093
01094 return 0;
01095 }
01096
01097 void ast_udptl_proto_unregister(struct ast_udptl_protocol *proto)
01098 {
01099 AST_RWLIST_WRLOCK(&protos);
01100 AST_RWLIST_REMOVE(&protos, proto, list);
01101 AST_RWLIST_UNLOCK(&protos);
01102 }
01103
01104 int ast_udptl_proto_register(struct ast_udptl_protocol *proto)
01105 {
01106 struct ast_udptl_protocol *cur;
01107
01108 AST_RWLIST_WRLOCK(&protos);
01109 AST_RWLIST_TRAVERSE(&protos, cur, list) {
01110 if (cur->type == proto->type) {
01111 ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
01112 AST_RWLIST_UNLOCK(&protos);
01113 return -1;
01114 }
01115 }
01116 AST_RWLIST_INSERT_TAIL(&protos, proto, list);
01117 AST_RWLIST_UNLOCK(&protos);
01118 return 0;
01119 }
01120
01121 static struct ast_udptl_protocol *get_proto(struct ast_channel *chan)
01122 {
01123 struct ast_udptl_protocol *cur = NULL;
01124
01125 AST_RWLIST_RDLOCK(&protos);
01126 AST_RWLIST_TRAVERSE(&protos, cur, list) {
01127 if (cur->type == chan->tech->type)
01128 break;
01129 }
01130 AST_RWLIST_UNLOCK(&protos);
01131
01132 return cur;
01133 }
01134
01135 int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
01136 {
01137 struct ast_frame *f;
01138 struct ast_channel *who;
01139 struct ast_channel *cs[3];
01140 struct ast_udptl *p0;
01141 struct ast_udptl *p1;
01142 struct ast_udptl_protocol *pr0;
01143 struct ast_udptl_protocol *pr1;
01144 struct ast_sockaddr ac0;
01145 struct ast_sockaddr ac1;
01146 struct ast_sockaddr t0;
01147 struct ast_sockaddr t1;
01148 void *pvt0;
01149 void *pvt1;
01150 int to;
01151
01152 ast_channel_lock(c0);
01153 while (ast_channel_trylock(c1)) {
01154 ast_channel_unlock(c0);
01155 usleep(1);
01156 ast_channel_lock(c0);
01157 }
01158 pr0 = get_proto(c0);
01159 pr1 = get_proto(c1);
01160 if (!pr0) {
01161 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
01162 ast_channel_unlock(c0);
01163 ast_channel_unlock(c1);
01164 return -1;
01165 }
01166 if (!pr1) {
01167 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
01168 ast_channel_unlock(c0);
01169 ast_channel_unlock(c1);
01170 return -1;
01171 }
01172 pvt0 = c0->tech_pvt;
01173 pvt1 = c1->tech_pvt;
01174 p0 = pr0->get_udptl_info(c0);
01175 p1 = pr1->get_udptl_info(c1);
01176 if (!p0 || !p1) {
01177
01178 ast_channel_unlock(c0);
01179 ast_channel_unlock(c1);
01180 return -2;
01181 }
01182 if (pr0->set_udptl_peer(c0, p1)) {
01183 ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
01184 memset(&ac1, 0, sizeof(ac1));
01185 } else {
01186
01187 ast_udptl_get_peer(p1, &ac1);
01188 }
01189 if (pr1->set_udptl_peer(c1, p0)) {
01190 ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
01191 memset(&ac0, 0, sizeof(ac0));
01192 } else {
01193
01194 ast_udptl_get_peer(p0, &ac0);
01195 }
01196 ast_channel_unlock(c0);
01197 ast_channel_unlock(c1);
01198 cs[0] = c0;
01199 cs[1] = c1;
01200 cs[2] = NULL;
01201 for (;;) {
01202 if ((c0->tech_pvt != pvt0) ||
01203 (c1->tech_pvt != pvt1) ||
01204 (c0->masq || c0->masqr || c1->masq || c1->masqr)) {
01205 ast_debug(1, "Oooh, something is weird, backing out\n");
01206
01207 return -3;
01208 }
01209 to = -1;
01210 ast_udptl_get_peer(p1, &t1);
01211 ast_udptl_get_peer(p0, &t0);
01212 if (ast_sockaddr_cmp(&t1, &ac1)) {
01213 ast_debug(1, "Oooh, '%s' changed end address to %s\n",
01214 c1->name, ast_sockaddr_stringify(&t1));
01215 ast_debug(1, "Oooh, '%s' was %s\n",
01216 c1->name, ast_sockaddr_stringify(&ac1));
01217 ast_sockaddr_copy(&ac1, &t1);
01218 }
01219 if (ast_sockaddr_cmp(&t0, &ac0)) {
01220 ast_debug(1, "Oooh, '%s' changed end address to %s\n",
01221 c0->name, ast_sockaddr_stringify(&t0));
01222 ast_debug(1, "Oooh, '%s' was %s\n",
01223 c0->name, ast_sockaddr_stringify(&ac0));
01224 ast_sockaddr_copy(&ac0, &t0);
01225 }
01226 who = ast_waitfor_n(cs, 2, &to);
01227 if (!who) {
01228 ast_debug(1, "Ooh, empty read...\n");
01229
01230 if (ast_check_hangup(c0) || ast_check_hangup(c1))
01231 break;
01232 continue;
01233 }
01234 f = ast_read(who);
01235 if (!f) {
01236 *fo = f;
01237 *rc = who;
01238 ast_debug(1, "Oooh, got a %s\n", f ? "digit" : "hangup");
01239
01240 return 0;
01241 } else {
01242 if (f->frametype == AST_FRAME_MODEM) {
01243
01244 if (who == c0) {
01245 ast_write(c1, f);
01246 } else if (who == c1) {
01247 ast_write(c0, f);
01248 }
01249 }
01250 ast_frfree(f);
01251 }
01252
01253 cs[2] = cs[0];
01254 cs[0] = cs[1];
01255 cs[1] = cs[2];
01256 }
01257 return -1;
01258 }
01259
01260 static char *handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01261 {
01262 switch (cmd) {
01263 case CLI_INIT:
01264 e->command = "udptl set debug {on|off|ip}";
01265 e->usage =
01266 "Usage: udptl set debug {on|off|ip host[:port]}\n"
01267 " Enable or disable dumping of UDPTL packets.\n"
01268 " If ip is specified, limit the dumped packets to those to and from\n"
01269 " the specified 'host' with optional port.\n";
01270 return NULL;
01271 case CLI_GENERATE:
01272 return NULL;
01273 }
01274
01275 if (a->argc < 4 || a->argc > 5)
01276 return CLI_SHOWUSAGE;
01277
01278 if (a->argc == 4) {
01279 if (!strncasecmp(a->argv[3], "on", 2)) {
01280 udptldebug = 1;
01281 memset(&udptldebugaddr, 0, sizeof(udptldebugaddr));
01282 ast_cli(a->fd, "UDPTL Debugging Enabled\n");
01283 } else if (!strncasecmp(a->argv[3], "off", 3)) {
01284 udptldebug = 0;
01285 ast_cli(a->fd, "UDPTL Debugging Disabled\n");
01286 } else {
01287 return CLI_SHOWUSAGE;
01288 }
01289 } else {
01290 struct ast_sockaddr *addrs;
01291 if (strncasecmp(a->argv[3], "ip", 2))
01292 return CLI_SHOWUSAGE;
01293 if (!ast_sockaddr_resolve(&addrs, a->argv[4], 0, 0)) {
01294 return CLI_SHOWUSAGE;
01295 }
01296 ast_sockaddr_copy(&udptldebugaddr, &addrs[0]);
01297 ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_sockaddr_stringify(&udptldebugaddr));
01298 udptldebug = 1;
01299 ast_free(addrs);
01300 }
01301
01302 return CLI_SUCCESS;
01303 }
01304
01305
01306 static struct ast_cli_entry cli_udptl[] = {
01307 AST_CLI_DEFINE(handle_cli_udptl_set_debug, "Enable/Disable UDPTL debugging")
01308 };
01309
01310 static void __ast_udptl_reload(int reload)
01311 {
01312 struct ast_config *cfg;
01313 const char *s;
01314 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01315
01316 cfg = ast_config_load2("udptl.conf", "udptl", config_flags);
01317 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
01318 return;
01319 }
01320
01321 udptlstart = 4500;
01322 udptlend = 4999;
01323 udptlfecentries = 0;
01324 udptlfecspan = 0;
01325 use_even_ports = 0;
01326
01327 if (cfg) {
01328 if ((s = ast_variable_retrieve(cfg, "general", "udptlstart"))) {
01329 udptlstart = atoi(s);
01330 if (udptlstart < 1024) {
01331 ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n");
01332 udptlstart = 1024;
01333 }
01334 if (udptlstart > 65535) {
01335 ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n");
01336 udptlstart = 65535;
01337 }
01338 }
01339 if ((s = ast_variable_retrieve(cfg, "general", "udptlend"))) {
01340 udptlend = atoi(s);
01341 if (udptlend < 1024) {
01342 ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n");
01343 udptlend = 1024;
01344 }
01345 if (udptlend > 65535) {
01346 ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n");
01347 udptlend = 65535;
01348 }
01349 }
01350 if ((s = ast_variable_retrieve(cfg, "general", "udptlchecksums"))) {
01351 #ifdef SO_NO_CHECK
01352 if (ast_false(s))
01353 nochecksums = 1;
01354 else
01355 nochecksums = 0;
01356 #else
01357 if (ast_false(s))
01358 ast_log(LOG_WARNING, "Disabling UDPTL checksums is not supported on this operating system!\n");
01359 #endif
01360 }
01361 if (ast_variable_retrieve(cfg, "general", "T38FaxUdpEC")) {
01362 ast_log(LOG_WARNING, "T38FaxUdpEC in udptl.conf is no longer supported; use the t38pt_udptl configuration option in sip.conf instead.\n");
01363 }
01364 if (ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram")) {
01365 ast_log(LOG_WARNING, "T38FaxMaxDatagram in udptl.conf is no longer supported; value is now supplied by T.38 applications.\n");
01366 }
01367 if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECEntries"))) {
01368 udptlfecentries = atoi(s);
01369 if (udptlfecentries < 1) {
01370 ast_log(LOG_WARNING, "Too small UDPTLFECEntries value. Defaulting to 1.\n");
01371 udptlfecentries = 1;
01372 }
01373 if (udptlfecentries > MAX_FEC_ENTRIES) {
01374 ast_log(LOG_WARNING, "Too large UDPTLFECEntries value. Defaulting to %d.\n", MAX_FEC_ENTRIES);
01375 udptlfecentries = MAX_FEC_ENTRIES;
01376 }
01377 }
01378 if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECSpan"))) {
01379 udptlfecspan = atoi(s);
01380 if (udptlfecspan < 1) {
01381 ast_log(LOG_WARNING, "Too small UDPTLFECSpan value. Defaulting to 1.\n");
01382 udptlfecspan = 1;
01383 }
01384 if (udptlfecspan > MAX_FEC_SPAN) {
01385 ast_log(LOG_WARNING, "Too large UDPTLFECSpan value. Defaulting to %d.\n", MAX_FEC_SPAN);
01386 udptlfecspan = MAX_FEC_SPAN;
01387 }
01388 }
01389 if ((s = ast_variable_retrieve(cfg, "general", "use_even_ports"))) {
01390 use_even_ports = ast_true(s);
01391 }
01392 ast_config_destroy(cfg);
01393 }
01394 if (udptlstart >= udptlend) {
01395 ast_log(LOG_WARNING, "Unreasonable values for UDPTL start/end ports; defaulting to 4500-4999.\n");
01396 udptlstart = 4500;
01397 udptlend = 4999;
01398 }
01399 if (use_even_ports && (udptlstart & 1)) {
01400 ++udptlstart;
01401 ast_log(LOG_NOTICE, "Odd numbered udptlstart specified but use_even_ports enabled. udptlstart is now %d\n", udptlstart);
01402 }
01403 if (use_even_ports && (udptlend & 1)) {
01404 --udptlend;
01405 ast_log(LOG_NOTICE, "Odd numbered udptlend specified but use_event_ports enabled. udptlend is now %d\n", udptlend);
01406 }
01407 ast_verb(2, "UDPTL allocating from port range %d -> %d\n", udptlstart, udptlend);
01408 }
01409
01410 int ast_udptl_reload(void)
01411 {
01412 __ast_udptl_reload(1);
01413 return 0;
01414 }
01415
01416 void ast_udptl_init(void)
01417 {
01418 ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
01419 __ast_udptl_reload(0);
01420 }