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