res_pjsip_t38: bind UDPTL sessions like RTP

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.

ASTERISK-29402

Change-Id: I87220c0e9cdd2fe9d156846cb906debe08c63557
This commit is contained in:
Matthew Kern 2021-07-19 10:34:00 -06:00
parent 7ee4136dcf
commit 39824c7a96
7 changed files with 96 additions and 1 deletions

View File

@ -725,6 +725,9 @@
; (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

View File

@ -0,0 +1,29 @@
"""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')

View File

@ -0,0 +1,9 @@
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.

View File

@ -692,6 +692,8 @@ struct ast_sip_t38_configuration {
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;
};
/*!

View File

@ -701,6 +701,13 @@
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>
@ -2465,6 +2472,9 @@
<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>

View File

@ -1908,6 +1908,7 @@ int ast_res_pjsip_initialize_configuration(void)
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));

View File

@ -255,11 +255,52 @@ static struct t38_state *t38_state_get_or_alloc(struct ast_sip_session *session)
/*! \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;
}