114#define UDPTL_MTU 1200
123#define LOG_TAG(u) S_OR(u->tag, "no tag")
125#define DEFAULT_UDPTLSTART 4000
126#define DEFAULT_UDPTLEND 4999
131#define LOCAL_FAX_MAX_DATAGRAM 1400
132#define DEFAULT_FAX_MAX_DATAGRAM 400
133#define FAX_MAX_DATAGRAM_LIMIT 1400
134#define MAX_FEC_ENTRIES 5
135#define MAX_FEC_SPAN 5
137#define UDPTL_BUF_MASK 15
241 .category =
"general",
276 if ((
buf[*
len] & 0x80) == 0) {
281 if ((
buf[*
len] & 0x40) == 0) {
282 if (*
len == limit - 1)
284 *pvalue = (
buf[*
len] & 0x3F) << 8;
290 *pvalue = (
buf[*
len] & 0x3F) << 14;
293 ast_debug(1,
"UDPTL packet with length greater than 16K received, decoding will fail\n");
298static int decode_open_type(uint8_t *
buf,
unsigned int limit,
unsigned int *
len,
const uint8_t **p_object,
unsigned int *p_num_octets)
300 unsigned int octet_cnt = 0;
306 if ((*
len + octet_cnt) > limit) {
310 *p_num_octets = octet_cnt;
320 unsigned int multiplier;
328 if (
value < 0x4000) {
338 multiplier = (
value < 0x10000) ? (
value >> 14) : 4;
340 buf[*
len] = 0xC0 | multiplier;
342 return multiplier << 14;
347 unsigned int *
len,
const uint8_t *data,
unsigned int num_octets)
350 unsigned int octet_idx;
354 if (num_octets == 0) {
360 for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) {
362 if (enclen + *
len > buflen) {
368 memcpy(&
buf[*
len], &data[octet_idx], enclen);
371 if (enclen >= num_octets)
386 const uint8_t *ifp =
NULL;
387 const uint8_t *data =
NULL;
388 unsigned int ifp_len = 0;
398 memset(&s->
f[0], 0,
sizeof(s->
f[0]));
403 seq_no = (
buf[0] << 8) |
buf[1];
416 if (seq_no < 0x000F && s->rx_seq_no > 0xFFF0) {
430 if ((
buf[ptr++] & 0x80) == 0) {
440 for (i = 0; i < count && total_count + i <
ARRAY_LEN(bufs); i++) {
445 if (!bufs[total_count + i] || !lengths[total_count + i]) {
453 while (stat2 > 0 && total_count <
ARRAY_LEN(bufs));
455 for (i = total_count; i > 0; i--) {
459 ast_debug(3,
"Recovering lost packet via secondary %d, len %u\n", seq_no - i, lengths[i - 1]);
464 s->
f[ifp_no].
seqno = seq_no - i;
465 s->
f[ifp_no].
datalen = lengths[i - 1];
466 s->
f[ifp_no].
data.
ptr = (uint8_t *) bufs[i - 1];
468 s->
f[ifp_no].
src =
"UDPTL";
497 memset(repaired, 0,
sizeof(repaired));
500 memcpy(s->
rx[x].
buf, ifp, ifp_len);
518 entries =
buf[ptr++];
525 for (i = 0; i < entries; i++) {
534 fprintf(stderr,
"FEC: ");
535 for (j = 0; j < s->
rx[x].
fec_len[i]; j++)
536 fprintf(stderr,
"%02hhX ", data[j]);
537 fprintf(stderr,
"\n");
559 which = (which == -1) ? k : -2;
563 for (j = 0; j < s->
rx[l].
fec_len[m]; j++) {
569 repaired[which] =
TRUE;
585 s->
f[ifp_no].
src =
"UDPTL";
602 s->
f[ifp_no].
seqno = seq_no;
604 s->
f[ifp_no].
data.
ptr = (uint8_t *) ifp;
606 s->
f[ifp_no].
src =
"UDPTL";
675 for (i = 0; i < entries; i++) {
678 ast_debug(1,
"UDPTL (%s): Encoding failed at i=%d, j=%d\n",
690 if (seq < s->error_correction_span)
702 for (m = 0; m < entries; m++) {
707 if (high_tide < s->tx[i].buf_len) {
708 for (j = 0; j < high_tide; j++)
709 fec[j] ^= s->
tx[i].
buf[j];
711 fec[j] = s->
tx[i].
buf[j];
715 fec[j] ^= s->
tx[i].
buf[j];
803 ast_debug(1,
"UDPTL (%s): NAT, Using address %s\n",
816 seq_no = (
buf[0] << 8) |
buf[1];
819 ast_verb(1,
"UDPTL (%s): packet from %s (seq %d, len %d)\n",
831 unsigned int new_max = 0;
834 ast_log(
LOG_WARNING,
"UDPTL (%s): Cannot calculate local_max_datagram before local_max_ifp has been set.\n",
872 unsigned new_max = 0;
875 ast_log(
LOG_WARNING,
"UDPTL (%s): Cannot calculate far_max_ifp before far_max_datagram has been set.\n",
975 if ((
signed int) max_ifp > 0) {
1034 if (!cfg || !cfg->general) {
1039 if (!(udptl =
ast_calloc(1,
sizeof(*udptl)))) {
1057 AF_INET6 : AF_INET, SOCK_DGRAM, 0)) < 0) {
1064 if (cfg->general->nochecksums)
1065 setsockopt(udptl->
fd, SOL_SOCKET, SO_NO_CHECK, &cfg->general->nochecksums,
sizeof(cfg->general->nochecksums));
1069 x = (cfg->general->start == cfg->general->end) ? cfg->general->start : (
ast_random() % (cfg->general->end - cfg->general->start)) + cfg->general->start;
1070 if (cfg->general->use_even_ports && (x & 1)) {
1080 if (
errno != EADDRINUSE &&
errno != EACCES) {
1086 if (cfg->general->use_even_ports) {
1091 if (x > cfg->general->end)
1092 x = cfg->general->start;
1093 if (x == startplace) {
1100 if (
io &&
sched && callbackmode) {
1116 va_start(ap, format);
1165 uint8_t
buf[bufsize];
1167 memset(
buf, 0,
sizeof(
buf));
1187 "UDPTL (%s): UDPTL asked to send %u bytes of IFP when far end only prepared to accept %d bytes; data loss will occur."
1188 "You may need to override the T38FaxMaxDatagram value for this endpoint in the channel driver configuration.\n",
1205 ast_verb(1,
"UDPTL (%s): packet to %s (seq %u, len %u)\n",
1217 e->
command =
"udptl set debug {on|off|ip}";
1219 "Usage: udptl set debug {on|off|ip host[:port]}\n"
1220 " Enable or disable dumping of UDPTL packets.\n"
1221 " If ip is specified, limit the dumped packets to those to and from\n"
1222 " the specified 'host' with optional port.\n";
1228 if (
a->argc < 4 ||
a->argc > 5)
1232 if (!strncasecmp(
a->argv[3],
"on", 2)) {
1235 ast_cli(
a->fd,
"UDPTL Debugging Enabled\n");
1236 }
else if (!strncasecmp(
a->argv[3],
"off", 3)) {
1238 ast_cli(
a->fd,
"UDPTL Debugging Disabled\n");
1244 if (strncasecmp(
a->argv[3],
"ip", 2))
1264 e->
command =
"udptl show config";
1266 "Usage: udptl show config\n"
1267 " Display UDPTL configuration options\n";
1277 ast_cli(
a->fd,
"UDPTL Global options\n");
1278 ast_cli(
a->fd,
"--------------------\n");
1279 ast_cli(
a->fd,
"udptlstart: %u\n", cfg->general->start);
1280 ast_cli(
a->fd,
"udptlend: %u\n", cfg->general->end);
1281 ast_cli(
a->fd,
"udptlfecentries: %u\n", cfg->general->fecentries);
1282 ast_cli(
a->fd,
"udptlfecspan: %u\n", cfg->general->fecspan);
1317 if (!strcasecmp(
var->name,
"t38faxudpec")) {
1319 }
else if (!strcasecmp(
var->name,
"t38faxmaxdatagram")) {
1320 ast_log(
LOG_WARNING,
"t38faxmaxdatagram in udptl.conf is no longer supported; value is now supplied by T.38 applications.\n");
1332 ast_log(
LOG_ERROR,
"Failed to load udptl.conf and failed to initialize defaults.\n");
1351 ast_log(
LOG_WARNING,
"Disabling UDPTL checksums is not supported on this operating system!\n");
1438 .
requires =
"extconfig",
Access Control of various sorts.
static const struct adsi_event events[]
static volatile unsigned int seq
Asterisk main include file. File version handling, generic pbx functions.
#define ast_vasprintf(ret, fmt, ap)
A wrapper for vasprintf()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_t_global_obj_release(holder, tag)
static struct console_pvt globals
static struct ast_sched_context * sched
static struct io_context * io
General Asterisk PBX channel definitions.
Standard Command Line Interface.
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Configuration option-handling.
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Asterisk internal frame definitions.
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
struct ast_frame ast_null_frame
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
int * ast_io_add(struct io_context *ioc, int fd, ast_io_cb callback, short events, void *data)
Adds an IO context.
int ast_io_remove(struct io_context *ioc, int *id)
Removes an IO context.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Asterisk locking-related definitions:
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
@ AST_MODULE_LOAD_SUCCESS
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares the addresses of two ast_sockaddr structures.
ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags, const struct ast_sockaddr *dest_addr)
Wrapper around sendto(2) that uses ast_sockaddr.
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
Set type of service.
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized,...
ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags, struct ast_sockaddr *src_addr)
Wrapper around recvfrom(2) that uses struct ast_sockaddr.
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
The representation of a single configuration file to be processed.
Type information about a category-level configurable object.
descriptor for a cli entry.
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Socket address structure.
Structure for an UDPTL session.
ast_udptl_callback callback
struct ast_sched_context * sched
unsigned int lasteventseqn
unsigned int error_correction_entries
udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK+1]
unsigned char rawdata[8192+AST_FRIENDLY_OFFSET]
unsigned int error_correction_span
enum ast_t38_ec_modes error_correction_scheme
udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK+1]
Structure for variables, used for configurations and for channel variables.
Global IO variables are now in a struct in order to be made threadsafe.
struct udptl_global_options * general
uint8_t fec[MAX_FEC_ENTRIES][LOCAL_FAX_MAX_DATAGRAM]
unsigned int fec_len[MAX_FEC_ENTRIES]
uint8_t buf[LOCAL_FAX_MAX_DATAGRAM]
uint8_t buf[LOCAL_FAX_MAX_DATAGRAM]
unsigned int use_even_ports
void ast_udptl_destroy(struct ast_udptl *udptl)
static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
static int encode_open_type(const struct ast_udptl *udptl, uint8_t *buf, unsigned int buflen, unsigned int *len, const uint8_t *data, unsigned int num_octets)
static void * udptl_snapshot_alloc(void)
static int removed_options_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int udptl_debug_test_addr(const struct ast_sockaddr *addr)
#define DEFAULT_UDPTLSTART
static struct aco_file udptl_conf
static struct ast_cli_entry cli_udptl[]
void ast_udptl_stop(struct ast_udptl *udptl)
int ast_udptl_fd(const struct ast_udptl *udptl)
void ast_udptl_get_peer(const struct ast_udptl *udptl, struct ast_sockaddr *them)
static void calculate_far_max_ifp(struct ast_udptl *udptl)
static struct aco_type general_option
int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
static void udptl_config_destructor(void *obj)
void ast_udptl_set_peer(struct ast_udptl *udptl, const struct ast_sockaddr *them)
void ast_udptl_set_tag(struct ast_udptl *udptl, const char *format,...)
Associates a character string 'tag' with a UDPTL session.
static AO2_GLOBAL_OBJ_STATIC(globals)
void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
static unsigned int encode_length(uint8_t *buf, unsigned int *len, unsigned int value)
unsigned int ast_udptl_get_far_max_ifp(struct ast_udptl *udptl)
retrieves far max ifp
void ast_udptl_setnat(struct ast_udptl *udptl, int nat)
static int reload_module(void)
#define LOCAL_FAX_MAX_DATAGRAM
void ast_udptl_get_us(const struct ast_udptl *udptl, struct ast_sockaddr *us)
#define DEFAULT_FAX_MAX_DATAGRAM
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
static int udptl_pre_apply_config(void)
static struct aco_type * general_options[]
CONFIG_INFO_CORE("udptl", cfg_info, globals, udptl_snapshot_alloc,.files=ACO_FILES(&udptl_conf),.pre_apply_config=udptl_pre_apply_config,)
int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos)
static char * handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define FAX_MAX_DATAGRAM_LIMIT
unsigned int ast_udptl_get_local_max_datagram(struct ast_udptl *udptl)
retrieves local_max_datagram.
void ast_udptl_set_data(struct ast_udptl *udptl, void *data)
static void calculate_local_max_datagram(struct ast_udptl *udptl)
void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram)
sets far max datagram size. If max_datagram is = 0, the far max datagram size is set to a default val...
static int load_module(void)
void ast_udptl_set_callback(struct ast_udptl *udptl, ast_udptl_callback callback)
static int udptlread(int *id, int fd, short events, void *cbdata)
static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets)
static void __ast_udptl_reload(int reload)
static int unload_module(void)
static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len)
unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl)
static struct ast_sockaddr udptldebugaddr
static int decode_length(uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue)
void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
struct ast_udptl * ast_udptl_new_with_bindaddr(struct ast_sched_context *sched, struct io_context *io, int callbackmode, struct ast_sockaddr *addr)
static char * handle_cli_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
int(* ast_udptl_callback)(struct ast_udptl *udptl, struct ast_frame *f, void *data)
@ UDPTL_ERROR_CORRECTION_FEC
@ UDPTL_ERROR_CORRECTION_NONE
@ UDPTL_ERROR_CORRECTION_REDUNDANCY
Handle unaligned data access.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
long int ast_random(void)