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