diff options
Diffstat (limited to 'main/udptl.c')
-rw-r--r-- | main/udptl.c | 271 |
1 files changed, 175 insertions, 96 deletions
diff --git a/main/udptl.c b/main/udptl.c index e39a9e7f2..35211ccb0 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -81,7 +81,7 @@ static struct sockaddr_in udptldebugaddr; /*!< Debug packets to/from this host #ifdef SO_NO_CHECK static int nochecksums; #endif -static int udptlfectype; +static enum ast_t38_ec_modes udptlfectype; static int udptlfecentries; static int udptlfecspan; static int udptlmaxdatagram; @@ -100,10 +100,10 @@ typedef struct { typedef struct { int buf_len; uint8_t buf[LOCAL_FAX_MAX_DATAGRAM]; - int fec_len[MAX_FEC_ENTRIES]; + unsigned int fec_len[MAX_FEC_ENTRIES]; uint8_t fec[MAX_FEC_ENTRIES][LOCAL_FAX_MAX_DATAGRAM]; - int fec_span; - int fec_entries; + unsigned int fec_span; + unsigned int fec_entries; } udptl_fec_rx_buffer_t; /*! \brief Structure for an UDPTL session */ @@ -122,35 +122,51 @@ struct ast_udptl { struct io_context *io; void *data; ast_udptl_callback callback; - int udptl_offered_from_local; /*! This option indicates the error correction scheme used in transmitted UDPTL - packets. */ - int error_correction_scheme; + * packets and expected in received UDPTL packets. + */ + enum ast_t38_ec_modes error_correction_scheme; /*! This option indicates the number of error correction entries transmitted in - UDPTL packets. */ - int error_correction_entries; + * UDPTL packets and expected in received UDPTL packets. + */ + unsigned int error_correction_entries; /*! This option indicates the span of the error correction entries in transmitted - UDPTL packets (FEC only). */ - int error_correction_span; - - /*! This option indicates the maximum size of a UDPTL packet that can be accepted by - the remote device. */ - int far_max_datagram_size; - - /*! This option indicates the maximum size of a UDPTL packet that we are prepared to - accept. */ - int local_max_datagram_size; + * UDPTL packets (FEC only). + */ + unsigned int error_correction_span; + + /*! The maximum size UDPTL packet that can be accepted by + * the remote device. + */ + unsigned int far_max_datagram; + + /*! The maximum size UDPTL packet that we are prepared to + * accept. + */ + unsigned int local_max_datagram; + + /*! The maximum IFP that can be submitted for sending + * to the remote device. Calculated from far_max_datagram, + * error_correction_scheme and error_correction_entries. + */ + unsigned int far_max_ifp; + + /*! The maximum IFP that the local endpoint is prepared + * to accept. Along with error_correction_scheme and + * error_correction_entries, used to calculate local_max_datagram. + */ + unsigned int local_max_ifp; int verbose; struct sockaddr_in far; - int tx_seq_no; - int rx_seq_no; - int rx_expected_seq_no; + unsigned int tx_seq_no; + unsigned int rx_seq_no; + unsigned int rx_expected_seq_no; udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1]; udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1]; @@ -158,23 +174,20 @@ struct ast_udptl { static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol); -static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len); -static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len); - -static inline int udptl_debug_test_addr(struct sockaddr_in *addr) +static inline int udptl_debug_test_addr(const struct sockaddr_in *addr) { if (udptldebug == 0) return 0; if (udptldebugaddr.sin_addr.s_addr) { - if (((ntohs(udptldebugaddr.sin_port) != 0) - && (udptldebugaddr.sin_port != addr->sin_port)) - || (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr)) + if (((ntohs(udptldebugaddr.sin_port) != 0) && + (udptldebugaddr.sin_port != addr->sin_port)) || + (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr)) return 0; } return 1; } -static int decode_length(uint8_t *buf, int limit, int *len, int *pvalue) +static int decode_length(uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue) { if (*len >= limit) return -1; @@ -199,15 +212,16 @@ static int decode_length(uint8_t *buf, int limit, int *len, int *pvalue) } /*- End of function --------------------------------------------------------*/ -static int decode_open_type(uint8_t *buf, int limit, int *len, const uint8_t **p_object, int *p_num_octets) +static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets) { - int octet_cnt; - int octet_idx; - int length; - int i; + unsigned int octet_cnt; + unsigned int octet_idx; + unsigned int length; + unsigned int i; const uint8_t **pbuf; for (octet_idx = 0, *p_num_octets = 0; ; octet_idx += octet_cnt) { + octet_cnt = 0; if ((length = decode_length(buf, limit, len, &octet_cnt)) < 0) return -1; if (octet_cnt > 0) { @@ -229,9 +243,9 @@ static int decode_open_type(uint8_t *buf, int limit, int *len, const uint8_t **p } /*- End of function --------------------------------------------------------*/ -static int encode_length(uint8_t *buf, int *len, int value) +static unsigned int encode_length(uint8_t *buf, unsigned int *len, unsigned int value) { - int multiplier; + unsigned int multiplier; if (value < 0x80) { /* 1 octet */ @@ -257,10 +271,10 @@ static int encode_length(uint8_t *buf, int *len, int value) } /*- End of function --------------------------------------------------------*/ -static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *data, int num_octets) +static int encode_open_type(uint8_t *buf, unsigned int buflen, unsigned int *len, const uint8_t *data, unsigned int num_octets) { - int enclen; - int octet_idx; + unsigned int enclen; + unsigned int octet_idx; uint8_t zero_byte; /* If open type is of zero length, add a single zero byte (10.1) */ @@ -289,7 +303,7 @@ static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *d } /*- End of function --------------------------------------------------------*/ -static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len) +static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len) { int stat1; int stat2; @@ -301,16 +315,16 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len) int x; int limit; int which; - int ptr; - int count; + unsigned int ptr; + unsigned int count; int total_count; int seq_no; const uint8_t *ifp; const uint8_t *data; - int ifp_len; + unsigned int ifp_len; int repaired[16]; const uint8_t *bufs[16]; - int lengths[16]; + unsigned int lengths[16]; int span; int entries; int ifp_no; @@ -497,7 +511,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len) } /*- End of function --------------------------------------------------------*/ -static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len) +static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len) { uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2]; int i; @@ -507,7 +521,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uin int entries; int span; int m; - int len; + unsigned int len; int limit; int high_tide; @@ -612,7 +626,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uin return len; } -int ast_udptl_fd(struct ast_udptl *udptl) +int ast_udptl_fd(const struct ast_udptl *udptl) { return udptl->fd; } @@ -695,15 +709,67 @@ struct ast_frame *ast_udptl_read(struct ast_udptl *udptl) return &udptl->f[0]; } -void ast_udptl_offered_from_local(struct ast_udptl* udptl, int local) +static void calculate_local_max_datagram(struct ast_udptl *udptl) { - if (udptl) - udptl->udptl_offered_from_local = local; - else - ast_log(LOG_WARNING, "udptl structure is null\n"); + unsigned int new_max = 200; + + /* calculate the amount of space required to receive an IFP + * using the current error correction mode, and ensure that our + * local max datagram size is at least that big + */ + switch (udptl->error_correction_scheme) { + case UDPTL_ERROR_CORRECTION_NONE: + /* only need room for sequence number and length indicators */ + new_max = 6 + udptl->local_max_ifp; + break; + case UDPTL_ERROR_CORRECTION_REDUNDANCY: + /* need room for sequence number, length indicators and the + * configured number of redundant packets + */ + new_max = 6 + udptl->local_max_ifp + 2 + (udptl->error_correction_entries * udptl->local_max_ifp); + break; + case UDPTL_ERROR_CORRECTION_FEC: + /* need room for sequence number, length indicators and a + * a single IFP of the maximum size expected + */ + new_max = 6 + udptl->local_max_ifp + 4 + udptl->local_max_ifp; + break; + } + /* add 25% of extra space for insurance, but no larger than LOCAL_FAX_MAX_DATAGRAM */ + udptl->local_max_datagram = MIN(new_max * 1.25, LOCAL_FAX_MAX_DATAGRAM); +} + +static void calculate_far_max_ifp(struct ast_udptl *udptl) +{ + unsigned new_max = 40; + + /* calculate the maximum IFP the local endpoint should + * generate based on the far end's maximum datagram size + * and the current error correction mode + */ + switch (udptl->error_correction_scheme) { + case UDPTL_ERROR_CORRECTION_NONE: + /* only need room for sequence number and length indicators */ + new_max = udptl->far_max_datagram - 6; + break; + case UDPTL_ERROR_CORRECTION_REDUNDANCY: + /* need room for sequence number, length indicators and the + * configured number of redundant packets + */ + new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1); + break; + case UDPTL_ERROR_CORRECTION_FEC: + /* need room for sequence number, length indicators and a + * a single IFP of the maximum size expected + */ + new_max = (udptl->far_max_datagram - 10) / 2; + break; + } + /* subtract 25% of space for insurance */ + udptl->far_max_ifp = new_max * 0.75; } -int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl) +int ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl) { if (udptl) return udptl->error_correction_scheme; @@ -713,60 +779,75 @@ int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl) } } -void ast_udptl_set_error_correction_scheme(struct ast_udptl* udptl, int ec) +void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec) { if (udptl) { + udptl->error_correction_scheme = ec; switch (ec) { case UDPTL_ERROR_CORRECTION_FEC: udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC; + if (udptl->error_correction_entries == 0) { + udptl->error_correction_entries = 3; + } + if (udptl->error_correction_span == 0) { + udptl->error_correction_span = 3; + } break; case UDPTL_ERROR_CORRECTION_REDUNDANCY: udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY; - break; - case UDPTL_ERROR_CORRECTION_NONE: - udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_NONE; + if (udptl->error_correction_entries == 0) { + udptl->error_correction_entries = 3; + } break; default: - ast_log(LOG_WARNING, "error correction parameter invalid\n"); + /* nothing to do */ + break; }; + calculate_local_max_datagram(udptl); + calculate_far_max_ifp(udptl); } else ast_log(LOG_WARNING, "udptl structure is null\n"); } -int ast_udptl_get_local_max_datagram(struct ast_udptl* udptl) +unsigned int ast_udptl_get_local_max_datagram(const struct ast_udptl *udptl) { if (udptl) - return udptl->local_max_datagram_size; + return udptl->local_max_datagram; else { ast_log(LOG_WARNING, "udptl structure is null\n"); - return -1; + return 0; } } -int ast_udptl_get_far_max_datagram(struct ast_udptl* udptl) +unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl) { if (udptl) - return udptl->far_max_datagram_size; + return udptl->far_max_datagram; else { ast_log(LOG_WARNING, "udptl structure is null\n"); - return -1; + return 0; } } -void ast_udptl_set_local_max_datagram(struct ast_udptl* udptl, int max_datagram) +void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram) { - if (udptl) - udptl->local_max_datagram_size = max_datagram; - else + if (udptl) { + udptl->far_max_datagram = max_datagram; + calculate_far_max_ifp(udptl); + } else { ast_log(LOG_WARNING, "udptl structure is null\n"); + } } -void ast_udptl_set_far_max_datagram(struct ast_udptl* udptl, int max_datagram) +void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp) { - if (udptl) - udptl->far_max_datagram_size = max_datagram; - else - ast_log(LOG_WARNING, "udptl structure is null\n"); + udptl->local_max_ifp = max_ifp; + calculate_local_max_datagram(udptl); +} + +unsigned int ast_udptl_get_far_max_ifp(const struct ast_udptl *udptl) +{ + return udptl->far_max_ifp; } struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr addr) @@ -780,20 +861,13 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struc if (!(udptl = ast_calloc(1, sizeof(*udptl)))) return NULL; - if (udptlfectype == 2) - udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC; - else if (udptlfectype == 1) - udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY; - else - udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_NONE; + udptl->error_correction_scheme = udptlfectype; udptl->error_correction_span = udptlfecspan; udptl->error_correction_entries = udptlfecentries; - udptl->far_max_datagram_size = udptlmaxdatagram; - udptl->local_max_datagram_size = udptlmaxdatagram; + udptl->far_max_datagram = udptlmaxdatagram; + udptl->local_max_datagram = udptlmaxdatagram; - memset(&udptl->rx, 0, sizeof(udptl->rx)); - memset(&udptl->tx, 0, sizeof(udptl->tx)); for (i = 0; i <= UDPTL_BUF_MASK; i++) { udptl->rx[i].buf_len = -1; udptl->tx[i].buf_len = -1; @@ -852,18 +926,18 @@ struct ast_udptl *ast_udptl_new(struct sched_context *sched, struct io_context * return ast_udptl_new_with_bindaddr(sched, io, callbackmode, ia); } -int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos) +int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos) { return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL"); } -void ast_udptl_set_peer(struct ast_udptl *udptl, struct sockaddr_in *them) +void ast_udptl_set_peer(struct ast_udptl *udptl, const struct sockaddr_in *them) { udptl->them.sin_port = them->sin_port; udptl->them.sin_addr = them->sin_addr; } -void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them) +void ast_udptl_get_peer(const struct ast_udptl *udptl, struct sockaddr_in *them) { memset(them, 0, sizeof(*them)); them->sin_family = AF_INET; @@ -871,7 +945,7 @@ void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them) them->sin_addr = udptl->them.sin_addr; } -void ast_udptl_get_us(struct ast_udptl *udptl, struct sockaddr_in *us) +void ast_udptl_get_us(const struct ast_udptl *udptl, struct sockaddr_in *us) { memcpy(us, &udptl->us, sizeof(udptl->us)); } @@ -893,10 +967,10 @@ void ast_udptl_destroy(struct ast_udptl *udptl) int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f) { - int seq; - int len; + unsigned int seq; + unsigned int len; int res; - uint8_t buf[LOCAL_FAX_MAX_DATAGRAM * 2]; + uint8_t buf[s->far_max_datagram]; /* If we have no peer, return immediately */ if (s->them.sin_addr.s_addr == INADDR_ANY) @@ -906,11 +980,16 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f) if (f->datalen == 0) return 0; - if (f->frametype != AST_FRAME_MODEM) { - ast_log(LOG_WARNING, "UDPTL can only send T.38 data\n"); + if ((f->frametype != AST_FRAME_MODEM) || + (f->subclass != AST_MODEM_T38)) { + ast_log(LOG_WARNING, "UDPTL can only send T.38 data.\n"); return -1; } + if (f->datalen > s->far_max_ifp) { + ast_log(LOG_WARNING, "UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss may occur.\n", f->datalen, s->far_max_ifp); + } + /* Save seq_no for debug output because udptl_build_packet increments it */ seq = s->tx_seq_no & 0xFFFF; @@ -1234,7 +1313,7 @@ static void __ast_udptl_reload(int reload) udptlstart = 4500; udptlend = 4999; - udptlfectype = 0; + udptlfectype = UDPTL_ERROR_CORRECTION_NONE; udptlfecentries = 0; udptlfecspan = 0; udptlmaxdatagram = 0; @@ -1275,9 +1354,9 @@ static void __ast_udptl_reload(int reload) } if ((s = ast_variable_retrieve(cfg, "general", "T38FaxUdpEC"))) { if (strcmp(s, "t38UDPFEC") == 0) - udptlfectype = 2; + udptlfectype = UDPTL_ERROR_CORRECTION_FEC; else if (strcmp(s, "t38UDPRedundancy") == 0) - udptlfectype = 1; + udptlfectype = UDPTL_ERROR_CORRECTION_REDUNDANCY; } if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) { udptlmaxdatagram = atoi(s); |