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: 308579 $")
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 int verbose;
00174
00175 unsigned int tx_seq_no;
00176 unsigned int rx_seq_no;
00177 unsigned int rx_expected_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, "(%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;
00327 const uint8_t *data;
00328 unsigned int ifp_len;
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];
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, "(%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 if (s->verbose)
00629 fprintf(stderr, "\n");
00630
00631 s->tx_seq_no++;
00632 return len;
00633 }
00634
00635 int ast_udptl_fd(const struct ast_udptl *udptl)
00636 {
00637 return udptl->fd;
00638 }
00639
00640 void ast_udptl_set_data(struct ast_udptl *udptl, void *data)
00641 {
00642 udptl->data = data;
00643 }
00644
00645 void ast_udptl_set_callback(struct ast_udptl *udptl, ast_udptl_callback callback)
00646 {
00647 udptl->callback = callback;
00648 }
00649
00650 void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
00651 {
00652 udptl->nat = nat;
00653 }
00654
00655 static int udptlread(int *id, int fd, short events, void *cbdata)
00656 {
00657 struct ast_udptl *udptl = cbdata;
00658 struct ast_frame *f;
00659
00660 if ((f = ast_udptl_read(udptl))) {
00661 if (udptl->callback)
00662 udptl->callback(udptl, f, udptl->data);
00663 }
00664 return 1;
00665 }
00666
00667 struct ast_frame *ast_udptl_read(struct ast_udptl *udptl)
00668 {
00669 int res;
00670 struct ast_sockaddr addr;
00671 uint16_t seqno = 0;
00672 uint16_t *udptlheader;
00673
00674
00675 res = ast_recvfrom(udptl->fd,
00676 udptl->rawdata + AST_FRIENDLY_OFFSET,
00677 sizeof(udptl->rawdata) - AST_FRIENDLY_OFFSET,
00678 0,
00679 &addr);
00680 udptlheader = (uint16_t *)(udptl->rawdata + AST_FRIENDLY_OFFSET);
00681 if (res < 0) {
00682 if (errno != EAGAIN)
00683 ast_log(LOG_WARNING, "(%s): UDPTL read error: %s\n",
00684 LOG_TAG(udptl), strerror(errno));
00685 ast_assert(errno != EBADF);
00686 return &ast_null_frame;
00687 }
00688
00689
00690 if (ast_sockaddr_isnull(&udptl->them)) {
00691 return &ast_null_frame;
00692 }
00693
00694 if (udptl->nat) {
00695
00696 if (ast_sockaddr_cmp(&udptl->them, &addr)) {
00697 ast_sockaddr_copy(&udptl->them, &addr);
00698 ast_debug(1, "UDPTL NAT (%s): Using address %s\n",
00699 LOG_TAG(udptl), ast_sockaddr_stringify(&udptl->them));
00700 }
00701 }
00702
00703 if (udptl_debug_test_addr(&addr)) {
00704 ast_verb(1, "UDPTL (%s): packet from %s (type %d, seq %d, len %d)\n",
00705 LOG_TAG(udptl), ast_sockaddr_stringify(&addr), 0, seqno, res);
00706 }
00707 if (udptl_rx_packet(udptl, udptl->rawdata + AST_FRIENDLY_OFFSET, res) < 1)
00708 return &ast_null_frame;
00709
00710 return &udptl->f[0];
00711 }
00712
00713 static void calculate_local_max_datagram(struct ast_udptl *udptl)
00714 {
00715 unsigned int new_max = 0;
00716
00717 if (udptl->local_max_ifp == -1) {
00718 ast_log(LOG_WARNING, "(%s): Cannot calculate local_max_datagram before local_max_ifp has been set.\n",
00719 LOG_TAG(udptl));
00720 udptl->local_max_datagram = -1;
00721 return;
00722 }
00723
00724
00725
00726
00727
00728
00729
00730 switch (udptl->error_correction_scheme) {
00731 case UDPTL_ERROR_CORRECTION_NONE:
00732
00733
00734
00735 new_max = 5 + udptl->local_max_ifp;
00736 break;
00737 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00738
00739
00740
00741 new_max = 5 + udptl->local_max_ifp + 2 + (3 * udptl->local_max_ifp);
00742 break;
00743 case UDPTL_ERROR_CORRECTION_FEC:
00744
00745
00746
00747 new_max = 5 + udptl->local_max_ifp + 4 + udptl->local_max_ifp;
00748 break;
00749 }
00750
00751 udptl->local_max_datagram = MIN(new_max * 1.05, LOCAL_FAX_MAX_DATAGRAM);
00752 }
00753
00754 static void calculate_far_max_ifp(struct ast_udptl *udptl)
00755 {
00756 unsigned new_max = 0;
00757
00758 if (udptl->far_max_datagram == -1) {
00759 ast_log(LOG_WARNING, "(%s): Cannot calculate far_max_ifp before far_max_datagram has been set.\n",
00760 LOG_TAG(udptl));
00761 udptl->far_max_ifp = -1;
00762 return;
00763 }
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 switch (udptl->error_correction_scheme) {
00779 case UDPTL_ERROR_CORRECTION_NONE:
00780
00781
00782
00783 new_max = udptl->far_max_datagram - 5;
00784 break;
00785 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798 for (;;) {
00799 new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1);
00800
00801 if ((new_max < 80) && (udptl->error_correction_entries > 1)) {
00802
00803
00804
00805 --udptl->error_correction_entries;
00806 } else {
00807 break;
00808 }
00809 }
00810 break;
00811 case UDPTL_ERROR_CORRECTION_FEC:
00812
00813
00814
00815 new_max = (udptl->far_max_datagram - 10) / 2;
00816 break;
00817 }
00818
00819 udptl->far_max_ifp = new_max * 0.95;
00820 }
00821
00822 enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
00823 {
00824 return udptl->error_correction_scheme;
00825 }
00826
00827 void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
00828 {
00829 udptl->error_correction_scheme = ec;
00830 switch (ec) {
00831 case UDPTL_ERROR_CORRECTION_FEC:
00832 udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
00833 if (udptl->error_correction_entries == 0) {
00834 udptl->error_correction_entries = 3;
00835 }
00836 if (udptl->error_correction_span == 0) {
00837 udptl->error_correction_span = 3;
00838 }
00839 break;
00840 case UDPTL_ERROR_CORRECTION_REDUNDANCY:
00841 udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
00842 if (udptl->error_correction_entries == 0) {
00843 udptl->error_correction_entries = 3;
00844 }
00845 break;
00846 default:
00847
00848 break;
00849 };
00850
00851 udptl->local_max_datagram = -1;
00852 udptl->far_max_ifp = -1;
00853 }
00854
00855 void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
00856 {
00857
00858
00859 if ((signed int) max_ifp > 0) {
00860 udptl->local_max_ifp = max_ifp;
00861
00862 udptl->local_max_datagram = -1;
00863 }
00864 }
00865
00866 unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
00867 {
00868 if (udptl->local_max_datagram == -1) {
00869 calculate_local_max_datagram(udptl);
00870 }
00871
00872
00873 if (udptl->local_max_datagram < 0) {
00874 return 0;
00875 }
00876 return udptl->local_max_datagram;
00877 }
00878
00879 void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram)
00880 {
00881 if (!max_datagram || (max_datagram > FAX_MAX_DATAGRAM_LIMIT)) {
00882 udptl->far_max_datagram = DEFAULT_FAX_MAX_DATAGRAM;
00883 } else {
00884 udptl->far_max_datagram = max_datagram;
00885 }
00886
00887 udptl->far_max_ifp = -1;
00888 }
00889
00890 unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl)
00891 {
00892 if (udptl->far_max_datagram < 0) {
00893 return 0;
00894 }
00895 return udptl->far_max_datagram;
00896 }
00897
00898 unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
00899 {
00900 if (udptl->far_max_ifp == -1) {
00901 calculate_far_max_ifp(udptl);
00902 }
00903
00904 if (udptl->far_max_ifp < 0) {
00905 return 0;
00906 }
00907 return udptl->far_max_ifp;
00908 }
00909
00910 struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct ast_sockaddr *addr)
00911 {
00912 struct ast_udptl *udptl;
00913 int x;
00914 int startplace;
00915 int i;
00916 long int flags;
00917
00918 if (!(udptl = ast_calloc(1, sizeof(*udptl))))
00919 return NULL;
00920
00921 udptl->error_correction_span = udptlfecspan;
00922 udptl->error_correction_entries = udptlfecentries;
00923
00924 udptl->far_max_datagram = -1;
00925 udptl->far_max_ifp = -1;
00926 udptl->local_max_ifp = -1;
00927 udptl->local_max_datagram = -1;
00928
00929 for (i = 0; i <= UDPTL_BUF_MASK; i++) {
00930 udptl->rx[i].buf_len = -1;
00931 udptl->tx[i].buf_len = -1;
00932 }
00933
00934 if ((udptl->fd = socket(ast_sockaddr_is_ipv6(addr) ?
00935 AF_INET6 : AF_INET, SOCK_DGRAM, 0)) < 0) {
00936 ast_free(udptl);
00937 ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
00938 return NULL;
00939 }
00940 flags = fcntl(udptl->fd, F_GETFL);
00941 fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK);
00942 #ifdef SO_NO_CHECK
00943 if (nochecksums)
00944 setsockopt(udptl->fd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
00945 #endif
00946
00947 x = (udptlstart == udptlend) ? udptlstart : (ast_random() % (udptlend - udptlstart)) + udptlstart;
00948 if (use_even_ports && (x & 1)) {
00949 ++x;
00950 }
00951 startplace = x;
00952 for (;;) {
00953 ast_sockaddr_copy(&udptl->us, addr);
00954 ast_sockaddr_set_port(&udptl->us, x);
00955 if (ast_bind(udptl->fd, &udptl->us) == 0) {
00956 break;
00957 }
00958 if (errno != EADDRINUSE) {
00959 ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno));
00960 close(udptl->fd);
00961 ast_free(udptl);
00962 return NULL;
00963 }
00964 if (use_even_ports) {
00965 x += 2;
00966 } else {
00967 ++x;
00968 }
00969 if (x > udptlend)
00970 x = udptlstart;
00971 if (x == startplace) {
00972 ast_log(LOG_WARNING, "No UDPTL ports remaining\n");
00973 close(udptl->fd);
00974 ast_free(udptl);
00975 return NULL;
00976 }
00977 }
00978 if (io && sched && callbackmode) {
00979
00980 udptl->sched = sched;
00981 udptl->io = io;
00982 udptl->ioid = ast_io_add(udptl->io, udptl->fd, udptlread, AST_IO_IN, udptl);
00983 }
00984 return udptl;
00985 }
00986
00987 void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format, ...)
00988 {
00989 va_list ap;
00990
00991 if (udptl->tag) {
00992 ast_free(udptl->tag);
00993 udptl->tag = NULL;
00994 }
00995 va_start(ap, format);
00996 if (ast_vasprintf(&udptl->tag, format, ap) == -1) {
00997 udptl->tag = NULL;
00998 }
00999 va_end(ap);
01000 }
01001
01002 int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos)
01003 {
01004 return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL");
01005 }
01006
01007 void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
01008 {
01009 ast_sockaddr_copy(&udptl->them, them);
01010 }
01011
01012 void ast_udptl_get_peer(const struct ast_udptl *udptl, struct ast_sockaddr *them)
01013 {
01014 ast_sockaddr_copy(them, &udptl->them);
01015 }
01016
01017 void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
01018 {
01019 ast_sockaddr_copy(us, &udptl->us);
01020 }
01021
01022 void ast_udptl_stop(struct ast_udptl *udptl)
01023 {
01024 ast_sockaddr_setnull(&udptl->them);
01025 }
01026
01027 void ast_udptl_destroy(struct ast_udptl *udptl)
01028 {
01029 if (udptl->ioid)
01030 ast_io_remove(udptl->io, udptl->ioid);
01031 if (udptl->fd > -1)
01032 close(udptl->fd);
01033 if (udptl->tag)
01034 ast_free(udptl->tag);
01035 ast_free(udptl);
01036 }
01037
01038 int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
01039 {
01040 unsigned int seq;
01041 unsigned int len = f->datalen;
01042 int res;
01043
01044 const int bufsize = (s->far_max_datagram > 0) ? s->far_max_datagram : DEFAULT_FAX_MAX_DATAGRAM;
01045 uint8_t buf[bufsize];
01046
01047 memset(buf, 0, sizeof(buf));
01048
01049
01050 if (ast_sockaddr_isnull(&s->them)) {
01051 return 0;
01052 }
01053
01054
01055 if (f->datalen == 0)
01056 return 0;
01057
01058 if ((f->frametype != AST_FRAME_MODEM) ||
01059 (f->subclass.codec != AST_MODEM_T38)) {
01060 ast_log(LOG_WARNING, "(%s): UDPTL can only send T.38 data.\n",
01061 LOG_TAG(s));
01062 return -1;
01063 }
01064
01065 if (len > s->far_max_ifp) {
01066 ast_log(LOG_WARNING,
01067 "(%s): UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss will occur."
01068 "You may need to override the T38FaxMaxDatagram value for this endpoint in the channel driver configuration.\n",
01069 LOG_TAG(s), len, s->far_max_ifp);
01070 len = s->far_max_ifp;
01071 }
01072
01073
01074 seq = s->tx_seq_no & 0xFFFF;
01075
01076
01077 len = udptl_build_packet(s, buf, sizeof(buf), f->data.ptr, len);
01078
01079 if ((signed int) len > 0 && !ast_sockaddr_isnull(&s->them)) {
01080 if ((res = ast_sendto(s->fd, buf, len, 0, &s->them)) < 0)
01081 ast_log(LOG_NOTICE, "(%s): UDPTL Transmission error to %s: %s\n",
01082 LOG_TAG(s), ast_sockaddr_stringify(&s->them), strerror(errno));
01083 if (udptl_debug_test_addr(&s->them))
01084 ast_verb(1, "UDPTL (%s): packet to %s (type %d, seq %d, len %d)\n",
01085 LOG_TAG(s), ast_sockaddr_stringify(&s->them), 0, seq, len);
01086 }
01087
01088 return 0;
01089 }
01090
01091 void ast_udptl_proto_unregister(struct ast_udptl_protocol *proto)
01092 {
01093 AST_RWLIST_WRLOCK(&protos);
01094 AST_RWLIST_REMOVE(&protos, proto, list);
01095 AST_RWLIST_UNLOCK(&protos);
01096 }
01097
01098 int ast_udptl_proto_register(struct ast_udptl_protocol *proto)
01099 {
01100 struct ast_udptl_protocol *cur;
01101
01102 AST_RWLIST_WRLOCK(&protos);
01103 AST_RWLIST_TRAVERSE(&protos, cur, list) {
01104 if (cur->type == proto->type) {
01105 ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
01106 AST_RWLIST_UNLOCK(&protos);
01107 return -1;
01108 }
01109 }
01110 AST_RWLIST_INSERT_TAIL(&protos, proto, list);
01111 AST_RWLIST_UNLOCK(&protos);
01112 return 0;
01113 }
01114
01115 static struct ast_udptl_protocol *get_proto(struct ast_channel *chan)
01116 {
01117 struct ast_udptl_protocol *cur = NULL;
01118
01119 AST_RWLIST_RDLOCK(&protos);
01120 AST_RWLIST_TRAVERSE(&protos, cur, list) {
01121 if (cur->type == chan->tech->type)
01122 break;
01123 }
01124 AST_RWLIST_UNLOCK(&protos);
01125
01126 return cur;
01127 }
01128
01129 int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
01130 {
01131 struct ast_frame *f;
01132 struct ast_channel *who;
01133 struct ast_channel *cs[3];
01134 struct ast_udptl *p0;
01135 struct ast_udptl *p1;
01136 struct ast_udptl_protocol *pr0;
01137 struct ast_udptl_protocol *pr1;
01138 struct ast_sockaddr ac0;
01139 struct ast_sockaddr ac1;
01140 struct ast_sockaddr t0;
01141 struct ast_sockaddr t1;
01142 void *pvt0;
01143 void *pvt1;
01144 int to;
01145
01146 ast_channel_lock(c0);
01147 while (ast_channel_trylock(c1)) {
01148 ast_channel_unlock(c0);
01149 usleep(1);
01150 ast_channel_lock(c0);
01151 }
01152 pr0 = get_proto(c0);
01153 pr1 = get_proto(c1);
01154 if (!pr0) {
01155 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
01156 ast_channel_unlock(c0);
01157 ast_channel_unlock(c1);
01158 return -1;
01159 }
01160 if (!pr1) {
01161 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
01162 ast_channel_unlock(c0);
01163 ast_channel_unlock(c1);
01164 return -1;
01165 }
01166 pvt0 = c0->tech_pvt;
01167 pvt1 = c1->tech_pvt;
01168 p0 = pr0->get_udptl_info(c0);
01169 p1 = pr1->get_udptl_info(c1);
01170 if (!p0 || !p1) {
01171
01172 ast_channel_unlock(c0);
01173 ast_channel_unlock(c1);
01174 return -2;
01175 }
01176 if (pr0->set_udptl_peer(c0, p1)) {
01177 ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
01178 memset(&ac1, 0, sizeof(ac1));
01179 } else {
01180
01181 ast_udptl_get_peer(p1, &ac1);
01182 }
01183 if (pr1->set_udptl_peer(c1, p0)) {
01184 ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
01185 memset(&ac0, 0, sizeof(ac0));
01186 } else {
01187
01188 ast_udptl_get_peer(p0, &ac0);
01189 }
01190 ast_channel_unlock(c0);
01191 ast_channel_unlock(c1);
01192 cs[0] = c0;
01193 cs[1] = c1;
01194 cs[2] = NULL;
01195 for (;;) {
01196 if ((c0->tech_pvt != pvt0) ||
01197 (c1->tech_pvt != pvt1) ||
01198 (c0->masq || c0->masqr || c1->masq || c1->masqr)) {
01199 ast_debug(1, "Oooh, something is weird, backing out\n");
01200
01201 return -3;
01202 }
01203 to = -1;
01204 ast_udptl_get_peer(p1, &t1);
01205 ast_udptl_get_peer(p0, &t0);
01206 if (ast_sockaddr_cmp(&t1, &ac1)) {
01207 ast_debug(1, "Oooh, '%s' changed end address to %s\n",
01208 c1->name, ast_sockaddr_stringify(&t1));
01209 ast_debug(1, "Oooh, '%s' was %s\n",
01210 c1->name, ast_sockaddr_stringify(&ac1));
01211 ast_sockaddr_copy(&ac1, &t1);
01212 }
01213 if (ast_sockaddr_cmp(&t0, &ac0)) {
01214 ast_debug(1, "Oooh, '%s' changed end address to %s\n",
01215 c0->name, ast_sockaddr_stringify(&t0));
01216 ast_debug(1, "Oooh, '%s' was %s\n",
01217 c0->name, ast_sockaddr_stringify(&ac0));
01218 ast_sockaddr_copy(&ac0, &t0);
01219 }
01220 who = ast_waitfor_n(cs, 2, &to);
01221 if (!who) {
01222 ast_debug(1, "Ooh, empty read...\n");
01223
01224 if (ast_check_hangup(c0) || ast_check_hangup(c1))
01225 break;
01226 continue;
01227 }
01228 f = ast_read(who);
01229 if (!f) {
01230 *fo = f;
01231 *rc = who;
01232 ast_debug(1, "Oooh, got a %s\n", f ? "digit" : "hangup");
01233
01234 return 0;
01235 } else {
01236 if (f->frametype == AST_FRAME_MODEM) {
01237
01238 if (who == c0) {
01239 ast_write(c1, f);
01240 } else if (who == c1) {
01241 ast_write(c0, f);
01242 }
01243 }
01244 ast_frfree(f);
01245 }
01246
01247 cs[2] = cs[0];
01248 cs[0] = cs[1];
01249 cs[1] = cs[2];
01250 }
01251 return -1;
01252 }
01253
01254 static char *handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01255 {
01256 switch (cmd) {
01257 case CLI_INIT:
01258 e->command = "udptl set debug {on|off|ip}";
01259 e->usage =
01260 "Usage: udptl set debug {on|off|ip host[:port]}\n"
01261 " Enable or disable dumping of UDPTL packets.\n"
01262 " If ip is specified, limit the dumped packets to those to and from\n"
01263 " the specified 'host' with optional port.\n";
01264 return NULL;
01265 case CLI_GENERATE:
01266 return NULL;
01267 }
01268
01269 if (a->argc < 4 || a->argc > 5)
01270 return CLI_SHOWUSAGE;
01271
01272 if (a->argc == 4) {
01273 if (!strncasecmp(a->argv[3], "on", 2)) {
01274 udptldebug = 1;
01275 memset(&udptldebugaddr, 0, sizeof(udptldebugaddr));
01276 ast_cli(a->fd, "UDPTL Debugging Enabled\n");
01277 } else if (!strncasecmp(a->argv[3], "off", 3)) {
01278 udptldebug = 0;
01279 ast_cli(a->fd, "UDPTL Debugging Disabled\n");
01280 } else {
01281 return CLI_SHOWUSAGE;
01282 }
01283 } else {
01284 struct ast_sockaddr *addrs;
01285 if (strncasecmp(a->argv[3], "ip", 2))
01286 return CLI_SHOWUSAGE;
01287 if (!ast_sockaddr_resolve(&addrs, a->argv[4], 0, 0)) {
01288 return CLI_SHOWUSAGE;
01289 }
01290 ast_sockaddr_copy(&udptldebugaddr, &addrs[0]);
01291 ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_sockaddr_stringify(&udptldebugaddr));
01292 udptldebug = 1;
01293 ast_free(addrs);
01294 }
01295
01296 return CLI_SUCCESS;
01297 }
01298
01299
01300 static struct ast_cli_entry cli_udptl[] = {
01301 AST_CLI_DEFINE(handle_cli_udptl_set_debug, "Enable/Disable UDPTL debugging")
01302 };
01303
01304 static void __ast_udptl_reload(int reload)
01305 {
01306 struct ast_config *cfg;
01307 const char *s;
01308 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01309
01310 cfg = ast_config_load2("udptl.conf", "udptl", config_flags);
01311 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
01312 return;
01313 }
01314
01315 udptlstart = 4500;
01316 udptlend = 4999;
01317 udptlfecentries = 0;
01318 udptlfecspan = 0;
01319 use_even_ports = 0;
01320
01321 if (cfg) {
01322 if ((s = ast_variable_retrieve(cfg, "general", "udptlstart"))) {
01323 udptlstart = atoi(s);
01324 if (udptlstart < 1024) {
01325 ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n");
01326 udptlstart = 1024;
01327 }
01328 if (udptlstart > 65535) {
01329 ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n");
01330 udptlstart = 65535;
01331 }
01332 }
01333 if ((s = ast_variable_retrieve(cfg, "general", "udptlend"))) {
01334 udptlend = atoi(s);
01335 if (udptlend < 1024) {
01336 ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n");
01337 udptlend = 1024;
01338 }
01339 if (udptlend > 65535) {
01340 ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n");
01341 udptlend = 65535;
01342 }
01343 }
01344 if ((s = ast_variable_retrieve(cfg, "general", "udptlchecksums"))) {
01345 #ifdef SO_NO_CHECK
01346 if (ast_false(s))
01347 nochecksums = 1;
01348 else
01349 nochecksums = 0;
01350 #else
01351 if (ast_false(s))
01352 ast_log(LOG_WARNING, "Disabling UDPTL checksums is not supported on this operating system!\n");
01353 #endif
01354 }
01355 if ((s = ast_variable_retrieve(cfg, "general", "T38FaxUdpEC"))) {
01356 ast_log(LOG_WARNING, "T38FaxUdpEC in udptl.conf is no longer supported; use the t38pt_udptl configuration option in sip.conf instead.\n");
01357 }
01358 if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) {
01359 ast_log(LOG_WARNING, "T38FaxMaxDatagram in udptl.conf is no longer supported; value is now supplied by T.38 applications.\n");
01360 }
01361 if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECEntries"))) {
01362 udptlfecentries = atoi(s);
01363 if (udptlfecentries < 1) {
01364 ast_log(LOG_WARNING, "Too small UDPTLFECEntries value. Defaulting to 1.\n");
01365 udptlfecentries = 1;
01366 }
01367 if (udptlfecentries > MAX_FEC_ENTRIES) {
01368 ast_log(LOG_WARNING, "Too large UDPTLFECEntries value. Defaulting to %d.\n", MAX_FEC_ENTRIES);
01369 udptlfecentries = MAX_FEC_ENTRIES;
01370 }
01371 }
01372 if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECSpan"))) {
01373 udptlfecspan = atoi(s);
01374 if (udptlfecspan < 1) {
01375 ast_log(LOG_WARNING, "Too small UDPTLFECSpan value. Defaulting to 1.\n");
01376 udptlfecspan = 1;
01377 }
01378 if (udptlfecspan > MAX_FEC_SPAN) {
01379 ast_log(LOG_WARNING, "Too large UDPTLFECSpan value. Defaulting to %d.\n", MAX_FEC_SPAN);
01380 udptlfecspan = MAX_FEC_SPAN;
01381 }
01382 }
01383 if ((s = ast_variable_retrieve(cfg, "general", "use_even_ports"))) {
01384 use_even_ports = ast_true(s);
01385 }
01386 ast_config_destroy(cfg);
01387 }
01388 if (udptlstart >= udptlend) {
01389 ast_log(LOG_WARNING, "Unreasonable values for UDPTL start/end ports; defaulting to 4500-4999.\n");
01390 udptlstart = 4500;
01391 udptlend = 4999;
01392 }
01393 if (use_even_ports && (udptlstart & 1)) {
01394 ++udptlstart;
01395 ast_log(LOG_NOTICE, "Odd numbered udptlstart specified but use_even_ports enabled. udptlstart is now %d\n", udptlstart);
01396 }
01397 if (use_even_ports && (udptlend & 1)) {
01398 --udptlend;
01399 ast_log(LOG_NOTICE, "Odd numbered udptlend specified but use_event_ports enabled. udptlend is now %d\n", udptlend);
01400 }
01401 ast_verb(2, "UDPTL allocating from port range %d -> %d\n", udptlstart, udptlend);
01402 }
01403
01404 int ast_udptl_reload(void)
01405 {
01406 __ast_udptl_reload(1);
01407 return 0;
01408 }
01409
01410 void ast_udptl_init(void)
01411 {
01412 ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
01413 __ast_udptl_reload(0);
01414 }