UDPTL support for T.38. More...
#include "asterisk/network.h"
#include "asterisk/frame.h"
#include "asterisk/io.h"
#include "asterisk/sched.h"
#include "asterisk/channel.h"
Go to the source code of this file.
Data Structures | |
struct | ast_udptl_protocol |
Typedefs | |
typedef int(* | ast_udptl_callback )(struct ast_udptl *udptl, struct ast_frame *f, void *data) |
Enumerations | |
enum | ast_t38_ec_modes { UDPTL_ERROR_CORRECTION_NONE, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_REDUNDANCY } |
Functions | |
int | ast_udptl_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) |
void | ast_udptl_destroy (struct ast_udptl *udptl) |
int | ast_udptl_fd (const struct ast_udptl *udptl) |
enum ast_t38_ec_modes | ast_udptl_get_error_correction_scheme (const struct ast_udptl *udptl) |
unsigned int | ast_udptl_get_far_max_datagram (const struct ast_udptl *udptl) |
unsigned int | ast_udptl_get_far_max_ifp (struct ast_udptl *udptl) |
retrieves far max ifp | |
unsigned int | ast_udptl_get_local_max_datagram (struct ast_udptl *udptl) |
retrieves local_max_datagram. | |
void | ast_udptl_get_peer (const struct ast_udptl *udptl, struct sockaddr_in *them) |
void | ast_udptl_get_us (const struct ast_udptl *udptl, struct sockaddr_in *us) |
void | ast_udptl_init (void) |
struct ast_udptl * | ast_udptl_new (struct sched_context *sched, struct io_context *io, int callbackmode) |
struct ast_udptl * | ast_udptl_new_with_bindaddr (struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr in) |
int | ast_udptl_proto_register (struct ast_udptl_protocol *proto) |
void | ast_udptl_proto_unregister (struct ast_udptl_protocol *proto) |
struct ast_frame * | ast_udptl_read (struct ast_udptl *udptl) |
int | ast_udptl_reload (void) |
void | ast_udptl_reset (struct ast_udptl *udptl) |
void | ast_udptl_set_callback (struct ast_udptl *udptl, ast_udptl_callback callback) |
void | ast_udptl_set_data (struct ast_udptl *udptl, void *data) |
void | ast_udptl_set_error_correction_scheme (struct ast_udptl *udptl, enum ast_t38_ec_modes ec) |
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 value. | |
void | ast_udptl_set_local_max_ifp (struct ast_udptl *udptl, unsigned int max_ifp) |
void | ast_udptl_set_m_type (struct ast_udptl *udptl, unsigned int pt) |
void | ast_udptl_set_peer (struct ast_udptl *udptl, const struct sockaddr_in *them) |
void | ast_udptl_set_tag (struct ast_udptl *udptl, const char *format,...) |
Associates a character string 'tag' with a UDPTL session. | |
void | ast_udptl_set_udptlmap_type (struct ast_udptl *udptl, unsigned int pt, char *mimeType, char *mimeSubtype) |
void | ast_udptl_setnat (struct ast_udptl *udptl, int nat) |
int | ast_udptl_setqos (struct ast_udptl *udptl, unsigned int tos, unsigned int cos) |
void | ast_udptl_stop (struct ast_udptl *udptl) |
int | ast_udptl_write (struct ast_udptl *udptl, struct ast_frame *f) |
typedef int(* ast_udptl_callback)(struct ast_udptl *udptl, struct ast_frame *f, void *data) |
enum ast_t38_ec_modes |
int ast_udptl_bridge | ( | struct ast_channel * | c0, |
struct ast_channel * | c1, | ||
int | flags, | ||
struct ast_frame ** | fo, | ||
struct ast_channel ** | rc | ||
) |
Definition at line 1139 of file udptl.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_debug, AST_FRAME_MODEM, ast_frfree, ast_inet_ntoa(), ast_log(), ast_read(), ast_udptl_get_peer(), ast_waitfor_n(), ast_write(), f, ast_frame::frametype, get_proto(), ast_udptl_protocol::get_udptl_info, inaddrcmp(), LOG_WARNING, ast_channel::masq, ast_channel::masqr, ast_channel::name, ast_udptl_protocol::set_udptl_peer, and ast_channel::tech_pvt.
{ struct ast_frame *f; struct ast_channel *who; struct ast_channel *cs[3]; struct ast_udptl *p0; struct ast_udptl *p1; struct ast_udptl_protocol *pr0; struct ast_udptl_protocol *pr1; struct sockaddr_in ac0; struct sockaddr_in ac1; struct sockaddr_in t0; struct sockaddr_in t1; void *pvt0; void *pvt1; int to; ast_channel_lock(c0); while (ast_channel_trylock(c1)) { ast_channel_unlock(c0); usleep(1); ast_channel_lock(c0); } pr0 = get_proto(c0); pr1 = get_proto(c1); if (!pr0) { ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name); ast_channel_unlock(c0); ast_channel_unlock(c1); return -1; } if (!pr1) { ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name); ast_channel_unlock(c0); ast_channel_unlock(c1); return -1; } pvt0 = c0->tech_pvt; pvt1 = c1->tech_pvt; p0 = pr0->get_udptl_info(c0); p1 = pr1->get_udptl_info(c1); if (!p0 || !p1) { /* Somebody doesn't want to play... */ ast_channel_unlock(c0); ast_channel_unlock(c1); return -2; } if (pr0->set_udptl_peer(c0, p1)) { ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name); memset(&ac1, 0, sizeof(ac1)); } else { /* Store UDPTL peer */ ast_udptl_get_peer(p1, &ac1); } if (pr1->set_udptl_peer(c1, p0)) { ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name); memset(&ac0, 0, sizeof(ac0)); } else { /* Store UDPTL peer */ ast_udptl_get_peer(p0, &ac0); } ast_channel_unlock(c0); ast_channel_unlock(c1); cs[0] = c0; cs[1] = c1; cs[2] = NULL; for (;;) { if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) || (c0->masq || c0->masqr || c1->masq || c1->masqr)) { ast_debug(1, "Oooh, something is weird, backing out\n"); /* Tell it to try again later */ return -3; } to = -1; ast_udptl_get_peer(p1, &t1); ast_udptl_get_peer(p0, &t0); if (inaddrcmp(&t1, &ac1)) { ast_debug(1, "Oooh, '%s' changed end address to %s:%d\n", c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port)); ast_debug(1, "Oooh, '%s' was %s:%d\n", c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port)); memcpy(&ac1, &t1, sizeof(ac1)); } if (inaddrcmp(&t0, &ac0)) { ast_debug(1, "Oooh, '%s' changed end address to %s:%d\n", c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port)); ast_debug(1, "Oooh, '%s' was %s:%d\n", c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port)); memcpy(&ac0, &t0, sizeof(ac0)); } who = ast_waitfor_n(cs, 2, &to); if (!who) { ast_debug(1, "Ooh, empty read...\n"); /* check for hangup / whentohangup */ if (ast_check_hangup(c0) || ast_check_hangup(c1)) break; continue; } f = ast_read(who); if (!f) { *fo = f; *rc = who; ast_debug(1, "Oooh, got a %s\n", f ? "digit" : "hangup"); /* That's all we needed */ return 0; } else { if (f->frametype == AST_FRAME_MODEM) { /* Forward T.38 frames if they happen upon us */ if (who == c0) { ast_write(c1, f); } else if (who == c1) { ast_write(c0, f); } } ast_frfree(f); } /* Swap priority. Not that it's a big deal at this point */ cs[2] = cs[0]; cs[0] = cs[1]; cs[1] = cs[2]; } return -1; }
void ast_udptl_destroy | ( | struct ast_udptl * | udptl | ) |
Definition at line 1038 of file udptl.c.
References ast_free, ast_io_remove(), ast_udptl::fd, ast_udptl::io, ast_udptl::ioid, and ast_udptl::tag.
Referenced by __sip_destroy(), and create_addr_from_peer().
int ast_udptl_fd | ( | const struct ast_udptl * | udptl | ) |
Definition at line 629 of file udptl.c.
References ast_udptl::fd.
Referenced by __oh323_new(), and sip_new().
{ return udptl->fd; }
enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme | ( | const struct ast_udptl * | udptl | ) |
Definition at line 820 of file udptl.c.
References ast_udptl::error_correction_scheme.
Referenced by add_sdp().
{ return udptl->error_correction_scheme; }
unsigned int ast_udptl_get_far_max_datagram | ( | const struct ast_udptl * | udptl | ) |
Definition at line 888 of file udptl.c.
References ast_udptl::far_max_datagram.
Referenced by process_sdp().
{ if (udptl->far_max_datagram < 0) { return 0; } return udptl->far_max_datagram; }
unsigned int ast_udptl_get_far_max_ifp | ( | struct ast_udptl * | udptl | ) |
retrieves far max ifp
positive | value representing max ifp size |
0 | if no value is present |
Definition at line 896 of file udptl.c.
References calculate_far_max_ifp(), and ast_udptl::far_max_ifp.
Referenced by change_t38_state(), and interpret_t38_parameters().
{ if (udptl->far_max_ifp == -1) { calculate_far_max_ifp(udptl); } if (udptl->far_max_ifp < 0) { return 0; } return udptl->far_max_ifp; }
unsigned int ast_udptl_get_local_max_datagram | ( | struct ast_udptl * | udptl | ) |
retrieves local_max_datagram.
positive | value representing max datagram size. |
0 | if no value is present |
Definition at line 864 of file udptl.c.
References calculate_local_max_datagram(), and ast_udptl::local_max_datagram.
Referenced by add_sdp().
{ if (udptl->local_max_datagram == -1) { calculate_local_max_datagram(udptl); } /* this function expects a unsigned value in return. */ if (udptl->local_max_datagram < 0) { return 0; } return udptl->local_max_datagram; }
void ast_udptl_get_peer | ( | const struct ast_udptl * | udptl, |
struct sockaddr_in * | them | ||
) |
Definition at line 1019 of file udptl.c.
References ast_udptl::them.
Referenced by ast_udptl_bridge(), and sip_set_udptl_peer().
void ast_udptl_get_us | ( | const struct ast_udptl * | udptl, |
struct sockaddr_in * | us | ||
) |
void ast_udptl_init | ( | void | ) |
Definition at line 1437 of file udptl.c.
References __ast_udptl_reload(), ARRAY_LEN, and ast_cli_register_multiple().
Referenced by main().
struct ast_udptl* ast_udptl_new | ( | struct sched_context * | sched, |
struct io_context * | io, | ||
int | callbackmode | ||
) | [read] |
Definition at line 986 of file udptl.c.
References ast_udptl_new_with_bindaddr().
{ struct in_addr ia; memset(&ia, 0, sizeof(ia)); return ast_udptl_new_with_bindaddr(sched, io, callbackmode, ia); }
struct ast_udptl* ast_udptl_new_with_bindaddr | ( | struct sched_context * | sched, |
struct io_context * | io, | ||
int | callbackmode, | ||
struct in_addr | in | ||
) | [read] |
Definition at line 908 of file udptl.c.
References ast_calloc, ast_free, ast_io_add(), AST_IO_IN, ast_log(), ast_random(), udptl_fec_tx_buffer_t::buf_len, udptl_fec_rx_buffer_t::buf_len, errno, ast_udptl::error_correction_entries, ast_udptl::error_correction_span, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, ast_udptl::fd, ast_udptl::flags, io, ast_udptl::io, ast_udptl::ioid, ast_udptl::local_max_datagram, ast_udptl::local_max_ifp, LOG_WARNING, ast_udptl::rx, sched, ast_udptl::sched, ast_udptl::them, ast_udptl::tx, UDPTL_BUF_MASK, udptlend, udptlfecentries, udptlfecspan, udptlread(), udptlstart, and ast_udptl::us.
Referenced by ast_udptl_new(), create_addr_from_peer(), handle_request_invite(), and sip_alloc().
{ struct ast_udptl *udptl; int x; int startplace; int i; long int flags; if (!(udptl = ast_calloc(1, sizeof(*udptl)))) return NULL; udptl->error_correction_span = udptlfecspan; udptl->error_correction_entries = udptlfecentries; udptl->far_max_datagram = -1; udptl->far_max_ifp = -1; udptl->local_max_ifp = -1; udptl->local_max_datagram = -1; for (i = 0; i <= UDPTL_BUF_MASK; i++) { udptl->rx[i].buf_len = -1; udptl->tx[i].buf_len = -1; } udptl->them.sin_family = AF_INET; udptl->us.sin_family = AF_INET; if ((udptl->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ast_free(udptl); ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno)); return NULL; } flags = fcntl(udptl->fd, F_GETFL); fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK); #ifdef SO_NO_CHECK if (nochecksums) setsockopt(udptl->fd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums)); #endif /* Find us a place */ x = (udptlstart == udptlend) ? udptlstart : (ast_random() % (udptlend - udptlstart)) + udptlstart; if (use_even_ports && (x & 1)) { ++x; } startplace = x; for (;;) { udptl->us.sin_port = htons(x); udptl->us.sin_addr = addr; if (bind(udptl->fd, (struct sockaddr *) &udptl->us, sizeof(udptl->us)) == 0) break; if (errno != EADDRINUSE) { ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno)); close(udptl->fd); ast_free(udptl); return NULL; } if (use_even_ports) { x += 2; } else { ++x; } if (x > udptlend) x = udptlstart; if (x == startplace) { ast_log(LOG_WARNING, "No UDPTL ports remaining\n"); close(udptl->fd); ast_free(udptl); return NULL; } } if (io && sched && callbackmode) { /* Operate this one in a callback mode */ udptl->sched = sched; udptl->io = io; udptl->ioid = ast_io_add(udptl->io, udptl->fd, udptlread, AST_IO_IN, udptl); } return udptl; }
int ast_udptl_proto_register | ( | struct ast_udptl_protocol * | proto | ) |
Definition at line 1108 of file udptl.c.
References ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, LOG_WARNING, and ast_udptl_protocol::type.
Referenced by load_module().
{ struct ast_udptl_protocol *cur; AST_RWLIST_WRLOCK(&protos); AST_RWLIST_TRAVERSE(&protos, cur, list) { if (cur->type == proto->type) { ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type); AST_RWLIST_UNLOCK(&protos); return -1; } } AST_RWLIST_INSERT_TAIL(&protos, proto, list); AST_RWLIST_UNLOCK(&protos); return 0; }
void ast_udptl_proto_unregister | ( | struct ast_udptl_protocol * | proto | ) |
Definition at line 1101 of file udptl.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
Referenced by unload_module().
{ AST_RWLIST_WRLOCK(&protos); AST_RWLIST_REMOVE(&protos, proto, list); AST_RWLIST_UNLOCK(&protos); }
Definition at line 661 of file udptl.c.
References ast_assert, ast_debug, AST_FRIENDLY_OFFSET, ast_inet_ntoa(), ast_log(), ast_null_frame, ast_verb, errno, ast_udptl::f, ast_udptl::fd, len(), LOG_TAG, LOG_WARNING, ast_udptl::nat, ast_udptl::rawdata, ast_udptl::them, udptl_debug_test_addr(), and udptl_rx_packet().
Referenced by sip_rtp_read(), skinny_rtp_read(), and udptlread().
{ int res; struct sockaddr_in sin; socklen_t len; uint16_t seqno = 0; uint16_t *udptlheader; len = sizeof(sin); /* Cache where the header will go */ res = recvfrom(udptl->fd, udptl->rawdata + AST_FRIENDLY_OFFSET, sizeof(udptl->rawdata) - AST_FRIENDLY_OFFSET, 0, (struct sockaddr *) &sin, &len); udptlheader = (uint16_t *)(udptl->rawdata + AST_FRIENDLY_OFFSET); if (res < 0) { if (errno != EAGAIN) ast_log(LOG_WARNING, "(%s): UDPTL read error: %s\n", LOG_TAG(udptl), strerror(errno)); ast_assert(errno != EBADF); return &ast_null_frame; } /* Ignore if the other side hasn't been given an address yet. */ if (!udptl->them.sin_addr.s_addr || !udptl->them.sin_port) return &ast_null_frame; if (udptl->nat) { /* Send to whoever sent to us */ if ((udptl->them.sin_addr.s_addr != sin.sin_addr.s_addr) || (udptl->them.sin_port != sin.sin_port)) { memcpy(&udptl->them, &sin, sizeof(udptl->them)); ast_debug(1, "UDPTL NAT (%s): Using address %s:%d\n", LOG_TAG(udptl), ast_inet_ntoa(udptl->them.sin_addr), ntohs(udptl->them.sin_port)); } } if (udptl_debug_test_addr(&sin)) { ast_verb(1, "UDPTL (%s): packet from %s:%d (type %d, seq %d, len %d)\n", LOG_TAG(udptl), ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), 0, seqno, res); } if (udptl_rx_packet(udptl, udptl->rawdata + AST_FRIENDLY_OFFSET, res) < 1) return &ast_null_frame; return &udptl->f[0]; }
int ast_udptl_reload | ( | void | ) |
Definition at line 1431 of file udptl.c.
References __ast_udptl_reload().
{ __ast_udptl_reload(1); return 0; }
void ast_udptl_reset | ( | struct ast_udptl * | udptl | ) |
void ast_udptl_set_callback | ( | struct ast_udptl * | udptl, |
ast_udptl_callback | callback | ||
) |
Definition at line 639 of file udptl.c.
References ast_udptl::callback.
{ udptl->callback = callback; }
void ast_udptl_set_data | ( | struct ast_udptl * | udptl, |
void * | data | ||
) |
void ast_udptl_set_error_correction_scheme | ( | struct ast_udptl * | udptl, |
enum ast_t38_ec_modes | ec | ||
) |
Definition at line 825 of file udptl.c.
References ast_udptl::error_correction_entries, ast_udptl::error_correction_scheme, ast_udptl::error_correction_span, ast_udptl::far_max_ifp, ast_udptl::local_max_datagram, UDPTL_ERROR_CORRECTION_FEC, and UDPTL_ERROR_CORRECTION_REDUNDANCY.
Referenced by process_sdp(), process_sdp_a_image(), and set_t38_capabilities().
{ 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; if (udptl->error_correction_entries == 0) { udptl->error_correction_entries = 3; } break; default: /* nothing to do */ break; }; /* reset calculated values so they'll be computed again */ udptl->local_max_datagram = -1; udptl->far_max_ifp = -1; }
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 value.
Definition at line 877 of file udptl.c.
References DEFAULT_FAX_MAX_DATAGRAM, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, and FAX_MAX_DATAGRAM_LIMIT.
Referenced by process_sdp(), and process_sdp_a_image().
{ if (!max_datagram || (max_datagram > FAX_MAX_DATAGRAM_LIMIT)) { udptl->far_max_datagram = DEFAULT_FAX_MAX_DATAGRAM; } else { udptl->far_max_datagram = max_datagram; } /* reset calculated values so they'll be computed again */ udptl->far_max_ifp = -1; }
void ast_udptl_set_local_max_ifp | ( | struct ast_udptl * | udptl, |
unsigned int | max_ifp | ||
) |
Definition at line 853 of file udptl.c.
References ast_udptl::local_max_datagram, and ast_udptl::local_max_ifp.
Referenced by interpret_t38_parameters().
{ /* make sure max_ifp is a positive value since a cast will take place when * when setting local_max_ifp */ if ((signed int) max_ifp > 0) { udptl->local_max_ifp = max_ifp; /* reset calculated values so they'll be computed again */ udptl->local_max_datagram = -1; } }
void ast_udptl_set_m_type | ( | struct ast_udptl * | udptl, |
unsigned int | pt | ||
) |
void ast_udptl_set_peer | ( | struct ast_udptl * | udptl, |
const struct sockaddr_in * | them | ||
) |
void ast_udptl_set_tag | ( | struct ast_udptl * | udptl, |
const char * | format, | ||
... | |||
) |
Associates a character string 'tag' with a UDPTL session.
udptl | The UDPTL session. |
format | printf-style format string used to construct the tag |
This function formats a tag for the specified UDPTL session, so that any log messages generated by the UDPTL stack related to that session will include the tag and the reader of the messages will be able to identify which endpoint caused them to be generated.
none |
Definition at line 993 of file udptl.c.
References ast_free, ast_vasprintf, and ast_udptl::tag.
Referenced by change_t38_state().
void ast_udptl_set_udptlmap_type | ( | struct ast_udptl * | udptl, |
unsigned int | pt, | ||
char * | mimeType, | ||
char * | mimeSubtype | ||
) |
void ast_udptl_setnat | ( | struct ast_udptl * | udptl, |
int | nat | ||
) |
Definition at line 644 of file udptl.c.
References nat, and ast_udptl::nat.
Referenced by do_setnat().
int ast_udptl_setqos | ( | struct ast_udptl * | udptl, |
unsigned int | tos, | ||
unsigned int | cos | ||
) |
Definition at line 1008 of file udptl.c.
References ast_netsock_set_qos(), and ast_udptl::fd.
Referenced by sip_alloc().
{ return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL"); }
void ast_udptl_stop | ( | struct ast_udptl * | udptl | ) |
Definition at line 1032 of file udptl.c.
References ast_udptl::them.
Referenced by process_sdp(), and stop_media_flows().
Definition at line 1049 of file udptl.c.
References AST_FRAME_MODEM, ast_inet_ntoa(), ast_log(), AST_MODEM_T38, ast_verb, buf, ast_frame::data, ast_frame::datalen, DEFAULT_FAX_MAX_DATAGRAM, errno, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, ast_udptl::fd, ast_frame::frametype, len(), LOG_NOTICE, LOG_TAG, LOG_WARNING, ast_frame::ptr, seq, ast_frame::subclass, ast_udptl::them, ast_udptl::tx_seq_no, udptl_build_packet(), and udptl_debug_test_addr().
Referenced by sip_write().
{ unsigned int seq; unsigned int len = f->datalen; int res; /* if no max datagram size is provided, use default value */ const int bufsize = (s->far_max_datagram > 0) ? s->far_max_datagram : DEFAULT_FAX_MAX_DATAGRAM; uint8_t buf[bufsize]; memset(buf, 0, sizeof(buf)); /* If we have no peer, return immediately */ if (s->them.sin_addr.s_addr == INADDR_ANY) return 0; /* If there is no data length, return immediately */ if (f->datalen == 0) return 0; if ((f->frametype != AST_FRAME_MODEM) || (f->subclass != AST_MODEM_T38)) { ast_log(LOG_WARNING, "(%s): UDPTL can only send T.38 data.\n", LOG_TAG(s)); return -1; } if (len > s->far_max_ifp) { ast_log(LOG_WARNING, "(%s): UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss will occur." "You may need to override the T38FaxMaxDatagram value for this endpoint in the channel driver configuration.\n", LOG_TAG(s), len, s->far_max_ifp); len = s->far_max_ifp; } /* Save seq_no for debug output because udptl_build_packet increments it */ seq = s->tx_seq_no & 0xFFFF; /* Cook up the UDPTL packet, with the relevant EC info. */ len = udptl_build_packet(s, buf, sizeof(buf), f->data.ptr, len); if ((signed int) len > 0 && s->them.sin_port && s->them.sin_addr.s_addr) { if ((res = sendto(s->fd, buf, len, 0, (struct sockaddr *) &s->them, sizeof(s->them))) < 0) ast_log(LOG_NOTICE, "(%s): UDPTL Transmission error to %s:%d: %s\n", LOG_TAG(s), ast_inet_ntoa(s->them.sin_addr), ntohs(s->them.sin_port), strerror(errno)); if (udptl_debug_test_addr(&s->them)) ast_verb(1, "UDPTL (%s): packet to %s:%d (type %d, seq %d, len %d)\n", LOG_TAG(s), ast_inet_ntoa(s->them.sin_addr), ntohs(s->them.sin_port), 0, seq, len); } return 0; }