; (default: "0")
;t38_udptl_nat=no ; Whether NAT support is enabled on UDPTL sessions
; (default: "no")
+;t38_bind_rtp_to_media_address= ; Bind the UDPTL session to the media_address.
+ ; This causes all UDPTL packets to be sent from
+ ; the specified address. (default: "no")
;tone_zone= ; Set which country s indications to use for channels created
; for this endpoint (default: "")
;language= ; Set the default language to use for channels created for this
--- /dev/null
+"""add t38_bind_udptl_to_media_address
+
+Revision ID: a06d8f8462d9
+Revises: f56d79a9f337
+Create Date: 2021-09-24 10:03:01.320480
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'a06d8f8462d9'
+down_revision = 'f56d79a9f337'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+AST_BOOL_NAME = 'ast_bool_values'
+AST_BOOL_VALUES = [ '0', '1',
+ 'off', 'on',
+ 'false', 'true',
+ 'no', 'yes' ]
+
+def upgrade():
+ ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
+ op.add_column('ps_endpoints', sa.Column('t38_bind_udptl_to_media_address', ast_bool_values))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 't38_bind_udptl_to_media_address')
--- /dev/null
+Subject: res_pjsip_t38
+
+In res_pjsip_sdp_rtp, the bind_rtp_to_media_address option and the
+fallback use of the transport's bind address solve problems sending
+media on systems that cannot send ipv4 packets on ipv6 sockets, and
+certain other situations. This change extends both of these behaviors
+to UDPTL sessions as well in res_pjsip_t38, to fix fax-specific
+problems on these systems, introducing a new option
+endpoint/t38_bind_udptl_to_media_address.
unsigned int nat;
/*! Whether to use IPv6 for UDPTL or not */
unsigned int ipv6;
+ /*! Bind the UDPTL instance to the media_address */
+ unsigned int bind_udptl_to_media_address;
};
/*!
When enabled the UDPTL stack will use IPv6.
</para></description>
</configOption>
+ <configOption name="t38_bind_udptl_to_media_address" default="no">
+ <synopsis>Bind the UDPTL instance to the media_adress</synopsis>
+ <description><para>
+ If media_address is specified, this option causes the UDPTL instance to be bound to
+ the specified ip address which causes the packets to be sent from that address.
+ </para></description>
+ </configOption>
<configOption name="tone_zone">
<synopsis>Set which country's indications to use for channels created for this endpoint.</synopsis>
</configOption>
<parameter name="T38UdptlIpv6">
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_udptl_ipv6']/synopsis/node())"/></para>
</parameter>
+ <parameter name="T38BindUdptlToMediaAddress">
+ <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='t38_bind_udptl_to_media_address']/synopsis/node())"/></para>
+ </parameter>
<parameter name="ToneZone">
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='tone_zone']/synopsis/node())"/></para>
</parameter>
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, faxdetect_timeout));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_bind_udptl_to_media_address", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.bind_udptl_to_media_address));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "language", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, language));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_on_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.onfeature));
/*! \brief Initializes UDPTL support on a session, only done when actually needed */
static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
{
+ struct ast_sockaddr temp_media_address;
+ struct ast_sockaddr *media_address = &address;
+
if (session_media->udptl) {
return 0;
}
- if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, &address))) {
+ if (session->endpoint->media.t38.bind_udptl_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
+ if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) {
+ ast_debug(5, "Endpoint %s: Binding UDPTL media to %s\n",
+ ast_sorcery_object_get_id(session->endpoint),
+ session->endpoint->media.address);
+ media_address = &temp_media_address;
+ } else {
+ ast_debug(5, "Endpoint %s: UDPTL media address invalid: %s\n",
+ ast_sorcery_object_get_id(session->endpoint),
+ session->endpoint->media.address);
+ }
+ } else {
+ struct ast_sip_transport *transport;
+
+ transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport",
+ session->endpoint->transport);
+ if (transport) {
+ struct ast_sip_transport_state *trans_state;
+
+ trans_state = ast_sip_get_transport_state(ast_sorcery_object_get_id(transport));
+ if (trans_state) {
+ char hoststr[PJ_INET6_ADDRSTRLEN];
+
+ pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0);
+ if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) {
+ ast_debug(5, "Transport %s bound to %s: Using it for UDPTL media.\n",
+ session->endpoint->transport, hoststr);
+ media_address = &temp_media_address;
+ } else {
+ ast_debug(5, "Transport %s bound to %s: Invalid for UDPTL media.\n",
+ session->endpoint->transport, hoststr);
+ }
+ ao2_ref(trans_state, -1);
+ }
+ ao2_ref(transport, -1);
+ }
+ }
+
+ if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, media_address))) {
return -1;
}