Merge "pjsip: Support dual stack automatically."

changes/74/4174/1
Joshua Colp 9 years ago committed by Gerrit Code Review
commit 7c79b057dd

@ -34,6 +34,19 @@ res_pjsip
preferred codec rather than advertising all joint codec capabilities.
This limits the other side's codec choice to exactly what we prefer.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ----------
------------------------------------------------------------------------------
res_pjsip
------------------
* Automatic dual stack support is now implemented. Depending on DNS resolution
and the transport used for sending a message the SIP signaling and SDP will
be updated with the correct IP address and protocol version. This means that
the rtp_ipv6 and t38_udptl_ipv6 options no longer have any effect. The
res_pjsip_multihomed module has also been moved into core res_pjsip to ensure
that messages are updated with the correct address information in all cases.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ----------
------------------------------------------------------------------------------

@ -112,9 +112,6 @@
; the prefix "external_" will only apply to communication with addresses
; outside the range set with "local_net=".
;
; IPv6: For endpoints using IPv6, remember to set "rtp_ipv6=yes" so that the RTP
; engine will also be able to bind to an IPv6 address.
;
; You can have more than one of any type of transport, as long as it doesn't
; use the same resources (bind address, port, etc) as the others.
@ -294,8 +291,6 @@
; If using the TLS enabled transport, you may want the "media_encryption=sdes"
; option to additionally enable SRTP, though they are not mutually inclusive.
;
; Use the "rtp_ipv6=yes" option if you want to utilize RTP over an ipv6 transport.
;
; If this endpoint were remote, and it was using a transport configured for NAT
; then you likely want to use "direct_media=no" to prevent audio issues.
@ -315,7 +310,6 @@
;transport=transport-tls
;media_encryption=sdes
;transport=transport-udp-ipv6
;rtp_ipv6=yes
;transport=transport-udp-nat
;direct_media=no
;
@ -646,7 +640,6 @@
; must be provided (default: "")
;rewrite_contact=no ; Allow Contact header to be rewritten with the source
; IP address port (default: "no")
;rtp_ipv6=no ; Allow use of IPv6 for RTP traffic (default: "no")
;rtp_symmetric=no ; Enforce that RTP must be symmetric (default: "no")
;send_diversion=yes ; Send the Diversion header conveying the diversion
; information to the called user agent (default: "yes")
@ -699,8 +692,6 @@
; (default: "0")
;t38_udptl_nat=no ; Whether NAT support is enabled on UDPTL sessions
; (default: "no")
;t38_udptl_ipv6=no ; Whether IPv6 is used for UDPTL Sessions (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

@ -374,7 +374,7 @@ def from_dtlsenable(key, val, section, pjsip, nmapped):
###############################################################################
# options in pjsip.conf on an endpoint that have no sip.conf equivalent:
# type, rtp_ipv6, 100rel, trust_id_outbound, aggregate_mwi,
# type, 100rel, trust_id_outbound, aggregate_mwi,
# connected_line_method
# known sip.conf peer keys that can be mapped to a pjsip.conf section/key

@ -4332,6 +4332,7 @@ static int unload_pjsip(void *data)
*/
if (ast_pjsip_endpoint && serializer_pool[0]) {
ast_res_pjsip_cleanup_options_handling();
ast_res_pjsip_cleanup_message_ip_updater();
ast_sip_destroy_distributor();
ast_res_pjsip_destroy_configuration();
ast_sip_destroy_system();
@ -4499,6 +4500,12 @@ static int load_module(void)
}
ast_res_pjsip_init_options_handling(0);
if (ast_res_pjsip_init_message_ip_updater()) {
ast_log(LOG_ERROR, "Failed to initialize message IP updating. Aborting load\n");
goto error;
}
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
AST_TEST_REGISTER(xml_sanitization_end_null);

@ -183,6 +183,14 @@ void ast_sip_destroy_global_headers(void);
*/
int ast_res_pjsip_init_options_handling(int reload);
/*!
* \internal Initialize message IP updating handling.
*
* \retval 0 on success
* \retval other on failure
*/
int ast_res_pjsip_init_message_ip_updater(void);
/*!
* \internal
* \brief Initialize transport storage for contacts.
@ -234,6 +242,12 @@ int ast_sip_initialize_global(void);
*/
void ast_res_pjsip_cleanup_options_handling(void);
/*!
* \internal
* \brief Clean up res_pjsip message ip updating handling
*/
void ast_res_pjsip_cleanup_message_ip_updater(void);
/*!
* \internal
* \brief Get threadpool options

@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2014, Digium, Inc.
* Copyright (C) 2014-2016, Digium, Inc.
*
* Joshua Colp <jcolp@digium.com>
*
@ -16,19 +16,78 @@
* at the top of the source tree.
*/
/*** MODULEINFO
<depend>pjproject</depend>
<depend>res_pjsip</depend>
<support_level>core</support_level>
***/
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
#include "asterisk/res_pjsip_session.h"
#include "include/res_pjsip_private.h"
#define MOD_DATA_RESTRICTIONS "restrictions"
static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata);
/*! \brief Outgoing message modification restrictions */
struct multihomed_message_restrictions {
/*! \brief Disallow modification of the From domain */
unsigned int disallow_from_domain_modification;
};
static pjsip_module multihomed_module = {
.name = { "Multihomed Routing", 18 },
.id = -1,
.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1,
.on_tx_request = multihomed_on_tx_message,
.on_tx_response = multihomed_on_tx_message,
};
/*! \brief Helper function to get (or allocate if not already present) restrictions on a message */
static struct multihomed_message_restrictions *multihomed_get_restrictions(pjsip_tx_data *tdata)
{
struct multihomed_message_restrictions *restrictions;
restrictions = ast_sip_mod_data_get(tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS);
if (restrictions) {
return restrictions;
}
restrictions = PJ_POOL_ALLOC_T(tdata->pool, struct multihomed_message_restrictions);
ast_sip_mod_data_set(tdata->pool, tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS, restrictions);
return restrictions;
}
/*! \brief Callback invoked on non-session outgoing messages */
static void multihomed_outgoing_message(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
{
struct multihomed_message_restrictions *restrictions = multihomed_get_restrictions(tdata);
restrictions->disallow_from_domain_modification = !ast_strlen_zero(endpoint->fromdomain);
}
/*! \brief PJSIP Supplement for tagging messages with restrictions */
static struct ast_sip_supplement multihomed_supplement = {
.priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST,
.outgoing_request = multihomed_outgoing_message,
.outgoing_response = multihomed_outgoing_message,
};
/*! \brief Callback invoked on session outgoing messages */
static void multihomed_session_outgoing_message(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
{
struct multihomed_message_restrictions *restrictions = multihomed_get_restrictions(tdata);
restrictions->disallow_from_domain_modification = !ast_strlen_zero(session->endpoint->fromdomain);
}
/*! \brief PJSIP Session Supplement for tagging messages with restrictions */
static struct ast_sip_session_supplement multihomed_session_supplement = {
.priority = 1,
.outgoing_request = multihomed_session_outgoing_message,
.outgoing_response = multihomed_session_outgoing_message,
};
/*! \brief Helper function which returns a UDP transport bound to the given address and port */
static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port)
@ -59,6 +118,21 @@ static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port
return sip_transport;
}
/*! \brief Helper function which determines if a transport is bound to any */
static int multihomed_bound_any(pjsip_transport *transport)
{
pj_uint32_t loop6[4] = {0, 0, 0, 0};
if ((transport->local_addr.addr.sa_family == pj_AF_INET() &&
transport->local_addr.ipv4.sin_addr.s_addr == PJ_INADDR_ANY) ||
(transport->local_addr.addr.sa_family == pj_AF_INET6() &&
!pj_memcmp(&transport->local_addr.ipv6.sin6_addr, loop6, sizeof(loop6)))) {
return 1;
}
return 0;
}
/*! \brief Helper function which determines if the address within SDP should be rewritten */
static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp)
{
@ -77,26 +151,13 @@ static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp)
return 0;
}
/*! \brief Helper function which determines if a transport is bound to any */
static int multihomed_bound_any(pjsip_transport *transport)
{
pj_uint32_t loop6[4] = {0, 0, 0, 0};
if ((transport->local_addr.addr.sa_family == pj_AF_INET() &&
transport->local_addr.ipv4.sin_addr.s_addr == PJ_INADDR_ANY) ||
(transport->local_addr.addr.sa_family == pj_AF_INET6() &&
!pj_memcmp(&transport->local_addr.ipv6.sin6_addr, loop6, sizeof(loop6)))) {
return 1;
}
return 0;
}
static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
{
struct multihomed_message_restrictions *restrictions = ast_sip_mod_data_get(tdata->mod_data, multihomed_module.id, MOD_DATA_RESTRICTIONS);
pjsip_tpmgr_fla2_param prm;
pjsip_cseq_hdr *cseq;
pjsip_via_hdr *via;
pjsip_fromto_hdr *from;
/* Use the destination information to determine what local interface this message will go out on */
pjsip_tpmgr_fla2_param_default(&prm);
@ -153,6 +214,13 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n",
(int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port);
if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
uri->transport_param.slen = 0;
} else {
pj_strdup2(tdata->pool, &uri->transport_param, pjsip_transport_get_type_name(tdata->tp_info.transport->key.type));
}
pjsip_tx_data_invalidate_msg(tdata);
}
}
@ -164,17 +232,38 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
pjsip_tx_data_invalidate_msg(tdata);
}
if (tdata->msg->type == PJSIP_REQUEST_MSG && (from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL)) &&
(restrictions && !restrictions->disallow_from_domain_modification)) {
pjsip_name_addr *id_name_addr = (pjsip_name_addr *)from->uri;
pjsip_sip_uri *uri = pjsip_uri_get_uri(id_name_addr);
pj_sockaddr ip;
if (pj_strcmp2(&uri->host, "localhost") && pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &uri->host, &ip) == PJ_SUCCESS) {
pj_strassign(&uri->host, &prm.ret_addr);
pjsip_tx_data_invalidate_msg(tdata);
}
}
/* Update the SDP if it is present */
if (tdata->msg->body && ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") &&
multihomed_rewrite_sdp(tdata->msg->body->data)) {
struct pjmedia_sdp_session *sdp = tdata->msg->body->data;
static const pj_str_t STR_IP4 = { "IP4", 3 };
static const pj_str_t STR_IP6 = { "IP6", 3 };
pj_str_t STR_IP;
int stream;
STR_IP = tdata->tp_info.transport->key.type & PJSIP_TRANSPORT_IPV6 ? STR_IP6 : STR_IP4;
pj_strassign(&sdp->origin.addr, &prm.ret_addr);
sdp->origin.addr_type = STR_IP;
pj_strassign(&sdp->conn->addr, &prm.ret_addr);
sdp->conn->addr_type = STR_IP;
for (stream = 0; stream < sdp->media_count; ++stream) {
if (sdp->media[stream]->conn) {
pj_strassign(&sdp->media[stream]->conn->addr, &prm.ret_addr);
sdp->media[stream]->conn->addr_type = STR_IP;
}
}
@ -184,42 +273,31 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
return PJ_SUCCESS;
}
static pjsip_module multihomed_module = {
.name = { "Multihomed Routing", 18 },
.id = -1,
.priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1,
.on_tx_request = multihomed_on_tx_message,
.on_tx_response = multihomed_on_tx_message,
};
static int unload_module(void)
void ast_res_pjsip_cleanup_message_ip_updater(void)
{
ast_sip_unregister_service(&multihomed_module);
return 0;
ast_sip_unregister_supplement(&multihomed_supplement);
ast_sip_session_unregister_supplement(&multihomed_session_supplement);
}
static int load_module(void)
int ast_res_pjsip_init_message_ip_updater(void)
{
char hostname[MAXHOSTNAMELEN] = "";
CHECK_PJSIP_MODULE_LOADED();
if (ast_sip_session_register_supplement(&multihomed_session_supplement)) {
ast_log(LOG_ERROR, "Could not register multihomed session supplement for outgoing requests\n");
return -1;
}
if (!gethostname(hostname, sizeof(hostname) - 1)) {
ast_verb(2, "Performing DNS resolution of local hostname '%s' to get local IPv4 and IPv6 address\n",
hostname);
if (ast_sip_register_supplement(&multihomed_supplement)) {
ast_log(LOG_ERROR, "Could not register multihomed supplement for outgoing requests\n");
ast_res_pjsip_cleanup_message_ip_updater();
return -1;
}
if (ast_sip_register_service(&multihomed_module)) {
ast_log(LOG_ERROR, "Could not register multihomed module for incoming and outgoing requests\n");
return AST_MODULE_LOAD_FAILURE;
ast_res_pjsip_cleanup_message_ip_updater();
return -1;
}
return AST_MODULE_LOAD_SUCCESS;
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Multihomed Routing Support",
.support_level = AST_MODULE_SUPPORT_CORE,
.load = load_module,
.unload = unload_module,
.load_pri = AST_MODPRI_APP_DEPEND,
);

@ -59,11 +59,8 @@ ASTERISK_REGISTER_FILE()
/*! \brief Scheduler for RTCP purposes */
static struct ast_sched_context *sched;
/*! \brief Address for IPv4 RTP */
static struct ast_sockaddr address_ipv4;
/*! \brief Address for IPv6 RTP */
static struct ast_sockaddr address_ipv6;
/*! \brief Address for RTP */
static struct ast_sockaddr address_rtp;
static const char STR_AUDIO[] = "audio";
static const int FD_AUDIO = 0;
@ -173,11 +170,11 @@ static int rtp_check_timeout(const void *data)
}
/*! \brief Internal function which creates an RTP instance */
static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6)
static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
{
struct ast_rtp_engine_ice *ice;
struct ast_sockaddr temp_media_address;
struct ast_sockaddr *media_address = ipv6 ? &address_ipv6 : &address_ipv4;
struct ast_sockaddr *media_address = &address_rtp;
if (session->endpoint->media.bind_rtp_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0);
@ -903,7 +900,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct
}
/* Using the connection information create an appropriate RTP instance */
if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
if (!session_media->rtp && create_rtp(session, session_media)) {
return -1;
}
@ -1055,7 +1052,6 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
pj_pool_t *pool = session->inv_session->pool_prov;
static const pj_str_t STR_IN = { "IN", 2 };
static const pj_str_t STR_IP4 = { "IP4", 3};
static const pj_str_t STR_IP6 = { "IP6", 3};
static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
static const pj_str_t STR_SENDONLY = { "sendonly", 8 };
pjmedia_sdp_media *media;
@ -1079,7 +1075,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
(!use_override_prefs && !ast_format_cap_has_type(session->endpoint->media.codecs, media_type))) {
/* If no type formats are configured don't add a stream */
return 0;
} else if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->media.rtp.ipv6)) {
} else if (!session_media->rtp && create_rtp(session, session_media)) {
return -1;
}
@ -1120,7 +1116,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
}
media->conn->net_type = STR_IN;
media->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
/* Connection information will be updated by the multihomed module */
media->conn->addr_type = STR_IP4;
pj_strdup2(pool, &media->conn->addr, hostip);
ast_rtp_instance_get_local_address(session_media->rtp, &addr);
media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr);
@ -1257,7 +1254,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a
}
/* Create an RTP instance if need be */
if (!session_media->rtp && create_rtp(session, session_media, session->endpoint->media.rtp.ipv6)) {
if (!session_media->rtp && create_rtp(session, session_media)) {
return -1;
}
@ -1493,8 +1490,7 @@ static int load_module(void)
{
CHECK_PJSIP_SESSION_MODULE_LOADED();
ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
ast_sockaddr_parse(&address_ipv6, "::", 0);
ast_sockaddr_parse(&address_rtp, "::", 0);
if (!(sched = ast_sched_context_create())) {
ast_log(LOG_ERROR, "Unable to create scheduler context.\n");

@ -51,11 +51,8 @@ ASTERISK_REGISTER_FILE()
/*! \brief The number of seconds after receiving a T.38 re-invite before automatically rejecting it */
#define T38_AUTOMATIC_REJECTION_SECONDS 5
/*! \brief Address for IPv4 UDPTL */
static struct ast_sockaddr address_ipv4;
/*! \brief Address for IPv6 UDPTL */
static struct ast_sockaddr address_ipv6;
/*! \brief Address for UDPTL */
static struct ast_sockaddr address;
/*! \brief T.38 state information */
struct t38_state {
@ -259,8 +256,7 @@ static int t38_initialize_session(struct ast_sip_session *session, struct ast_si
return 0;
}
if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0,
session->endpoint->media.t38.ipv6 ? &address_ipv6 : &address_ipv4))) {
if (!(session_media->udptl = ast_udptl_new_with_bindaddr(NULL, NULL, 0, &address))) {
return -1;
}
@ -922,8 +918,7 @@ static int load_module(void)
{
CHECK_PJSIP_SESSION_MODULE_LOADED();
ast_sockaddr_parse(&address_ipv4, "0.0.0.0", 0);
ast_sockaddr_parse(&address_ipv6, "::", 0);
ast_sockaddr_parse(&address, "::", 0);
if (ast_sip_session_register_supplement(&t38_supplement)) {
ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n");

@ -4971,6 +4971,15 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp)
static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr local, us;
if (!ast_sockaddr_isnull(addr)) {
/* Update the local RTP address with what is being used */
ast_ouraddrfor(addr, &us);
ast_rtp_instance_get_local_address(instance, &local);
ast_sockaddr_set_port(&us, ast_sockaddr_port(&local));
ast_rtp_instance_set_local_address(instance, &us);
}
if (rtp->rtcp) {
ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
@ -4979,6 +4988,15 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
ast_sockaddr_set_port(&rtp->rtcp->them,
ast_sockaddr_port(addr) + 1);
}
if (!ast_sockaddr_isnull(addr)) {
/* Update the local RTCP address with what is being used */
ast_sockaddr_set_port(&us, ast_sockaddr_port(&local) + 1);
ast_sockaddr_copy(&rtp->rtcp->us, &us);
ast_free(rtp->rtcp->local_addr_str);
rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&us));
}
}
rtp->rxseqno = 0;

Loading…
Cancel
Save