diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 80888c32ab8251f6c01275021018e881ac4431ad..2d57208e656ef6998a29d6ce0829ade15a4330ce 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -737,6 +737,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 diff --git a/contrib/ast-db-manage/config/versions/a06d8f8462d9_add_t38_bind_udptl_to_media_address.py b/contrib/ast-db-manage/config/versions/a06d8f8462d9_add_t38_bind_udptl_to_media_address.py new file mode 100644 index 0000000000000000000000000000000000000000..2d9a58cad8f6597eaf8df2204eef2075e00684dc --- /dev/null +++ b/contrib/ast-db-manage/config/versions/a06d8f8462d9_add_t38_bind_udptl_to_media_address.py @@ -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') diff --git a/doc/CHANGES-staging/res_pjsip_t38_bind_fixes.txt b/doc/CHANGES-staging/res_pjsip_t38_bind_fixes.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7bc8a1e9fb836864bc767211d6e075a76f599c3 --- /dev/null +++ b/doc/CHANGES-staging/res_pjsip_t38_bind_fixes.txt @@ -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. diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 8c5b775bf5db7f2f15523bad6c14095b15951b9e..7b9dcbd51d0f742af344ec5509fe726ffd19f1f5 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -760,6 +760,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; }; /*! diff --git a/res/res_pjsip.c b/res/res_pjsip.c index a375fe083b34112707a5e883f6545c444d9223af..2b30317738545bcf9c3e26f417e844c6193e73a0 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -940,6 +940,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> @@ -2783,6 +2790,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> diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 6defa7cb96a542d75ae9a13dad7b90afe52bd71c..c27b587076d79b3809b526331fbe77f3f3772596 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -2077,6 +2077,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)); diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 5d7f68d09559ed8bbbd42a88b9e2b7ac7f86e94f..7df35d9b2ae0aa409ae2a934c25f4211d7b158b4 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -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; }