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